我有一天想到一个问题,json和sql的转义字符这么像(其实很多数据格式的特殊字符都很像),能不能共用一下,我现在认为是可以的。
最初我实现了这样一段代码:
<?php
$username = isset($_GET['username']) ? sqlEscape($_GET['username']) : '""';
$password = isset($_GET['password']) ? sqlEscape($_GET['password']) : '""';
$sql = "SELECT * FROM user where username = {$username} AND password = {$password}";
print $sql;
function sqlEscape($param)
{
if (is_string($param)) {
return json_encode($param, JSON_UNESCAPED_UNICODE);
} else {
return json_encode(json_encode($param, JSON_UNESCAPED_UNICODE), JSON_UNESCAPED_UNICODE);
}
}
到这里就差不多了,但是我想了想,前面两段赋值语句,要对每个变量做过滤,有点太啰嗦了,于是改了一下
<?php
$s = new S();
isset($_GET['username'], $_GET['username']) OR exit("username and password is required");
print "SELECT * FROM user WHERE username = {$s->{$_GET['username']}} AND password = {$s->{$_GET['password']}}";
/**
* SQL转义类
*/
class S
{
function __get($param)
{
if (is_string($param) || is_numeric($param) || is_bool($param) || is_null($param)) {
return json_encode($param, JSON_UNESCAPED_UNICODE);
} else {
return json_encode(json_encode($param, JSON_UNESCAPED_UNICODE), JSON_UNESCAPED_UNICODE);
}
}
}
这样一来,实现的就相对优雅一点了
当然,现代化的技术是采用预编译(即参数化查询),原生的参数化查询需要为每一个代码编写冗长的逻辑,于是诞生了一些查询框架,其中最知名的是https://github.com/illuminate/database,内置于laravel,中文社区可能用thinkphp比较多,查询框架见https://github.com/top-think/think-orm
这篇文章的意义主要还是在一些小的思考,可以以一些简单、有效、优雅的方式解决一些小问题(我觉得像那种用双引号、单引号、连字符拼接出来的SQL实在是丑)
此外,任何基于转义的处理方案都不能解决宽字节注入的问题,宽字节问题属于编码不规范导致的,统一后端代码和数据库的编码才能解决:应该统一为utf8(mb4)
完。