I've inherited a large and extremely buggy PHP codebase. It needs a thorough review and cleanup, but I'm in need of a stopgap fix in the meantime. In the long run it needs proper user input sanitisation, e.g. as per What's the best method for sanitizing user input with PHP?. However, this just isn't practical in the short term. It's a codebase of thousands of files comprising hundreds of thousands of lines of code and I need some way of blocking the majority of errors as soon as possible.
Many of the scripts use $_GET['id']
as an unsanitised parameter for database lookups. Is there any way of getting PHP to automatically preprocess the $_GET
array along these lines:
if( isset( $_GET['id'] ) )
$_GET['id'] = (int) $_GET['id'];
I'm well aware that:
- This isn't a proper fix, just a kludge.
- I could use some kind of find and replace to put this at the top of every file.
- There are almost certainly other unsanitised SQL input problems.
- The code should be using prepared statements.
However, it would block 99% of the problems, and gain me some much needed breathing room. If at all possible I would much prefer to do it globally in the PHP config or the like. Many thanks for any suggestions.
EDIT: Below is some code I've knocked together to include via auto prepend, in case it is useful to others. You'll need to replace the database username, password, and possibly the charset too. In addition to $_GET
and $_POST
, you might also want to sanitise the $_REQUEST
, $_SESSION
and $_COOKIE
superglobals. Debugging code is included for testing purposes. Note that this is intended as a stopgap, not as a substitute for proper input sanitisation! Thanks again to all who offered advice.
<?php
$debug = false;
if( $debug ) ini_set( 'display_errors', 1 );
if( !function_exists( '_sanitise' ) )
{
function _sanitise( $input )
{
return htmlspecialchars( $input, ENT_QUOTES, 'UTF-8' );
}
}
if( !function_exists( '_sanitise_sql' ) )
{
function _sanitise_sql( $input )
{
$mysqli = new mysqli( 'localhost', 'username', 'password', 'database' );
/*if( mysqli_connect_error() )
{
echo 'Connect Error (' . mysqli_connect_errno() . ') ' . mysqli_connect_error();
}*/
$mysqli->set_charset( 'utf8mb4' );
if( is_array( $input ) )
{
$result = array();
foreach( $input as $key => $value )
{
$result[$key] = _sanitise_sql( $value );
}
return $result;
}
else return $mysqli->real_escape_string( $input );
}
}
if( !isset( $_GET['_sanitised'] ) )
{
foreach( $_GET as $key => &$value )
{
if( mb_strtolower( $key ) === 'id' ) $value = (int) $value;
elseif( substr( mb_strtolower( $key ), -3 ) === '_id' ) $value = (int) $value;
else $value = _sanitise_sql( $value );
}
$_GET['_sanitised'] = true;
}
if( !isset( $_POST['_sanitised'] ) )
{
foreach( $_POST as $key => &$value )
{
if( mb_strtolower( $key ) === 'id' ) $value = (int) $value;
elseif( substr( mb_strtolower( $key ), -3 ) === '_id' ) $value = (int) $value;
else $value = _sanitise_sql( $value );
}
$_POST['_sanitised'] = true;
}
if( $debug )
{
echo '<pre>$_GET:' . PHP_EOL;
echo _sanitise( print_r( $_GET, true ) );
echo PHP_EOL . '$_POST:' . PHP_EOL;
echo _sanitise( print_r( $_POST, true ) );
echo '</pre>';
}