2

Following a recent upgrade to WP and MySQL one site that has a custom built plugin throws a Fatal error:

Fatal error: Cannot re-assign auto-global variable _REQUEST in /home/mysitexyz/public_html/wp-content/plugins/employment_application/employment_application.php on line 549

Here is the offending code:

function getApplications($_REQUEST) {
    global $wpdb;
    $sql = "SELECT * FROM employment_applications";
    if($_REQUEST['s'] != '') {

    }
    $sql .= " WHERE applicant_name LIKE '%" . $_REQUEST['s']  . "%'";
//echo "SQL: $sql<BR>"; 
    $applications = $wpdb->get_results($sql);
    $wpdb->show_errors();
    //$errors = $wpdb->print_error();
    $error = $wpdb->last_error;     
    if($error != '') {
        echo '<div class="alert alert-error">' . $error . '</div>';
    }
    //print_r($applications);
    return $applications;
}

I know that this forum does not support Plugins, and since I am not the original developer and have only inherited the problem, I would like to address the other problem:

When I remove the above mentioned plugin by changing the name of the folder the site comes back up but only the sidebar navigation of the Dashboard shows. The rest of it is blank.

enter image description here

Is there a way to disable plugins without removing them from the Plugins folder? Is there a better way to troubleshoot the root cause of the empty dashboard?

Thanks!

1
  • Renaming plugins directory will turn off all plugins at once. Commented May 29, 2014 at 21:40

2 Answers 2

1

That is a seriously wonky plugin, my friend.


##Prologue##

Before we actually start, trash this conditional - it does absolutely nothing:

if($_REQUEST['s'] != '') {

}

But really, more than likely, the original plugin developer had intended this conditional to actually do something by bailing out of the function if $_REQUEST['s'] is not set (seeings as this function will do very little in such a case):

function getApplications( $_REQUEST ) {
    if( empty( $_REQUEST['s'] ) ) {
        return false;
    }

    global $wpdb;
    $sql = "SELECT * FROM employment_applications";

    ...

    return $applications;
}

##The Fatal Error##

First up: the fatal error. $_REQUEST in PHP is an automatically-populated super-global that PHP fills with HTTP request data. As such, it can be regarded as a reserved word (more specifically, a predefined variable). Specifying $_REQUEST as a parameter to the getApplications() function tells PHP to reference the first argument as $_REQUEST, but super-globals cannot be locally scoped in PHP5 which means that PHP interprets the code as attempting to re-assign the super-global, thus the error (not sure of the specific version in which this changed, but it was possible to use super-globals as parameters in PHP4).

If the getApplications() function is called with arguments, change the name of the parameter to maintain proper flow and avoid reassigning the $_REQUEST super-global:

function getApplications( $request ) {
    if( empty( $request['s'] ) )
        return false;

    global $wpdb;
    $sql = "SELECT * FROM employment_applications";
    $sql .= " WHERE applicant_name LIKE '%" . $request['s']  . "%'";

    $applications = $wpdb->get_results( $sql );
    $wpdb->show_errors();
    $error = $wpdb->last_error;

    if($error != '') {
        echo '<div class="alert alert-error">' . $error . '</div>';
    }

    return $applications;
}

If the getApplications() function called without arguments (or is always called with $_REQUEST as the argument, i.e. getApplications( $_REQUEST )), remove the parameter entirely and make direct use of the $_REQUEST super-global:

function getApplications() {
    if( empty( $_REQUEST['s'] ) )
        return false;

    global $wpdb;
    $sql = "SELECT * FROM employment_applications";
    $sql .= " WHERE applicant_name LIKE '%" . $_REQUEST['s']  . "%'";

    $applications = $wpdb->get_results( $sql );
    $wpdb->show_errors();
    $error = $wpdb->last_error;

    if($error != '') {
        echo '<div class="alert alert-error">' . $error . '</div>';
    }

    return $applications;
}

More than likely, your solution will be the latter of the two.


##Disabling Plugins Outside of the Dashboard## There are many ways to go about this, but here are a few of the most common:

  • Alter the active_plugins option (permanent)
    • Database:

Using PHPMyAdmin or raw SQL, within the wp_options table locate the row whose option_name field is active_plugins and modify it's option_value field. Note that this is a serialized value, so if you're not sure how to make the modifications to serialized data by hand you'll need to unserialize the value, make your modifications, and then reserialize it before placing it back into the field. Alternately, deleting the contents of option_value will disable all plugins (though their deactivation hooks may not fire, depending on the plugin's implementation).

Or you can make use of a serialization-aware search and replace tool.

  • PHP:

Make use of the deactivate_plugins() function or the Options API in a must-use plugin. Must-use plugins are always regarded as "activated" and are loaded before all other plugins; this provides a convenient entry point to execute code even when the large portions of the site are inaccessible.

  • Invalidate active_plugins ("undoable")

This is essentially the same trick as renaming the (root) plugins folder. In active_plugins, WordPress notes the location of each plugin's primary file relative to the plugin root (the constant WP_PLUGIN_DIR). By changing WP_PLUGIN_DIR you can force WordPress to loose track of the plugins and thus fail to load them, effectively processing the request as though no plugins are present and leaving the active_plugins option untouched in the database. In wp-config.php: define( 'WP_PLUGIN_DIR', 'thisPathDoesNotExist' );. Removing this line will revert the plugin path to it's default setting.


##"A Better Way to Troubleshoot"## Please refer to the Codex entry Debugging in WordPress for a primer into the debugging facilities provided by WordPress, as well as a short list of some great plugins that aid debugging. The very first step is always to enable the WP_DEBUG constant in wp-config.php (though refrain from doing this in a production environment, if at all possible):

define( 'WP_DEBUG', true );

If WP_DEBUG is false (as is default), WordPress suppresses the vast majority of warnings and errors.

I also highly recommend using Xdebug on your development machine for quick access to ridiculously useful stack traces, formatted var_dump()s, remote debugging, and pretty colors (among other things).


##A Note Regarding Security##

Let's take a moment to inspect this line here:

$sql .= " WHERE applicant_name LIKE '%" . $_REQUEST['s']  . "%'";

As $_REQUEST is filled with HTTP request data, what this line here is doing is taking the data-key s straight from the request and dropping it into an SQL query. This is a major security hole and likely exposes your site to SQL injections. Anyone who has access to any part of the site that results in the getApplications() function executing can simply append ?s=whatever to the URL to perform queries of their own design. The lack of proper escaping means that an attacker could even potentially use this query to access data outside of the employment_applications table.

If not abstracted and/or validated, all data supplied by users should be escaped, at the very least:

$sql = "SELECT * FROM employment_applications";
$sql .= " WHERE applicant_name LIKE '%" . esc_sql( like_escape( $_REQUEST['s'] ) ) . "%'";
$applications = $wpdb->get_results( $sql );

or

$querystring = "SELECT * FROM employment_applications WHERE applicant_name LIKE '%%%s%%'";
$applications = $wpdb->get_results( $wpdb->prepare( $querystring, $_REQUEST['s'] ) );

You should give the Codex entries on Data Validation and Protecting Queries Against SQL Injection Attacks a look-over for a brief intro to data security in WordPress.


##Epilogue## All of the above considered, I feel your modified code should look similar to the following:

function getApplications() {
    if( empty( $_REQUEST['s'] ) )
        return false;

    global $wpdb;
    $querystring = "SELECT * FROM employment_applications WHERE applicant_name LIKE '%%%s%%'";
    $applications = $wpdb->get_results( $wpdb->prepare( $querystring, $_REQUEST['s'] ) );
    $wpdb->show_errors();
    $error = $wpdb->last_error;

    if( ! empty( $error ) ) {
        echo '<div class="alert alert-error">' . $error . '</div>';
    }

    return $applications;
}
2
  • Hi Boscho, sometimes inheriting things is not such a good thing!. I appreciate your thorough review and recommendations. I am going to look this over and then respond again. Thanks.
    – forrest
    Commented May 29, 2014 at 22:30
  • Oh I definitely feel you, man - I myself have inherited a massive and undocumented C codebase from the 80s... Inheritance is wonderful tool in the context of code and a terrible curse in the context of coders ;) . Let me know if I can clarify/expand upon anything!
    – bosco
    Commented May 29, 2014 at 22:50
1

You can disable a plugin from the database as a last resort, here is a link to an article that will help if your familiar with MySQL

http://perishablepress.com/quickly-disable-or-enable-all-wordpress-plugins-via-the-database/

If you are not familiar with MySQL, then I suggest you use a tool such as Sequel Pro for OS X or PHPMyAdmin to look for the 'active_plugins' field inside the wp_options table. Somewhere inside the serialized object will be your plugins, just remove it and its index (the "i":4 part before it) and save.

You can also disable all plugins by setting the value of 'active_plugins' with an empty string (''). Then it should be easy enough to enable the plugins you want with the admin interface.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.