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)
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.
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;
}