PHP: Treat variable like function?
I'd like to use a variable like $GET[name] that always outputs a MySQL-safe version of $_GET[name], even if the value of $GET[name] changes somewhere in the script.
So:
$_GET[name] = "Timmy O'Toole";
echo $GET[name]; // Timmy O\'Toole
$_GET[name] = "Tommy O'Toole";
echo $GET[name]; // Tommy O\'Toole
Is this doable? If not, can you think of any other way that might work that doesn't involve an actual function call? (I'd like to be able to use the variables inside strings and have them automatically evaluate, rather than having to do a whole lot of con开发者_如何学编程catenation.)
Update:
I used a version of mario's solution, and it seems to work:
// Assume $_REQUEST['name'] = "Timmy O'Toole";
class request_safe_vars IMPLEMENTS ArrayAccess {
var $array = array();
function offsetGet($varname) {
return mysql_real_escape_string($_REQUEST[$varname]);
}
function offsetSet($name, $value) { }
function offsetUnset($name) { }
function offsetExists($name) { }
}
$REQUEST = new request_safe_vars();
$_REQUEST['name'] = $_REQUEST['name'].' MODIFIED';
$query = "SELECT id FROM user WHERE name = '{$REQUEST['name']}'";
// Query output:
// SELECT id FROM user WHERE name = 'Timmy O\'Toole MODIFIED'
You don't want to do this.
Rather, the thing you're trying to do -- ensure that the database gets only sane values -- is correct, but the way you're going about it is a bad approach.
Instead of escaping all input as it comes in, you should escape it when you use it by choosing a database adapter that has this functionality built in. PDO is a great example of such a database adapter. PDO uses prepared statements and parameter binding to automatically escape and quote input. Here's an example that binds placeholders at execution time:
$statement = $pdo->prepare('SELECT id FROM users WHERE name = ?');
$statement->execute(array( $_GET['name'] ));
if($statement->rowCount() > 0) {
echo "I found you!";
} else {
echo "You don't exist. :(";
}
Prepared statements with placeholders and binding is the most sane and safe way to ensure that SQL is safe from attack.
That's doable with an object that implements ArrayAccess. By turning $GET into an object you can have a magic offsetSet
and offsetGet
method which can accomplish this.
class safe_vars IMPLEMENTS ArrayAccess {
var $array = array();
function offsetGet($varname) {
return mysql_real_escape_string($this->array[$varname]);
}
function offsetSet($name, $value) {
$this->array[$name] = $value;
}
function offsetUnset($name) { }
function offsetExists($name) { }
}
This is how you would use it:
$GET = new safe_vars();
$GET["name"] = "Timmy O'Toole";
echo $GET["name"]; // Timmy O\'Toole
I actually have something similar (but never implemented the set
part) which specifically works on $_GET
(as listed in your question). http://sourceforge.net/p/php7framework/svn/60/tree/trunk/php7/input.php?force=True - It can be configured to apply the sql
filter per default for example. Though that approach feels a bit like magic_quotes even if it uses the correct escaping function.
First off, put quotes around 'name' unless you purposely define it as a constant.
Another suggestion would be to use a DB wrapper class such as PDO, mysqli, or your own, and use prepared statements and have the input escaped for you. This has the benefit of escaping data at the last possible time, which is optimal. Either that or you can create a very simple wrapper function, e.g.
function get($key) {
return isset($_GET[$key]) : mysql_real_escape_string($_GET[$key]) : null;
}
The problem with defining a class (unless you use it only statically) is that this strips $_GET
of its superglobal status and you are forced to use either globals (evil) or pass all get arguments to local closures.
精彩评论