自定义query_var函数能否实现数据库查询变量的通用sanitize?
多数开发者推荐使用预处理语句,但现有站点存在大量已有的查询,因此希望通过mysqli_real_escape_string()函数来净化数据库查询变量。mysqli_query()的PHP手册也说明该函数是可接受的替代方案,故提出以下问题:
计划使用如下查询方式:
$query = sprintf("SELECT * FROM users WHERE user_name = %s", query_var($user_name, "text")); $Records = mysqli_query($db, $query) or die(mysqli_error($db));
想确认下方自定义的query_var函数是否可行,存在以下疑问:
- 是否仍需在开头执行
stripslashes()?之前使用Adobe Dreamweaver的旧函数包含此操作。 - 在
mysqli_real_escape_string()后添加引号(如$the_value = "'".$the_value."'")是否可行? - 该函数是否存在明显的重大缺陷?
另外注意到stripslashes()会将多个\\转换为单个,这可能不适用于通用场景,例如用户提交包含\\的文本评论或商品描述时,不使用stripslashes()是否可行?
主要关注SQL注入问题,提交数据含HTML标签无影响,将在输出/打印时处理。
附自定义函数代码:
if(!function_exists('query_var')){ function query_var($the_value, $the_type="text"){ global $db; // do I still need this ? // $the_value = stripslashes($the_value); $the_value = mysqli_real_escape_string($db, $the_value); // do not allow dummy type of variables if(!in_array($the_type, array('text', 'int', 'float', 'double'))){ $the_type='text'; } if($the_type=='text'){ $the_value = "'".$the_value."'"; } if($the_type=='int'){ $the_value = intval($the_value); } if($the_type == 'float' or $the_type=='double'){ $the_value = floatval($the_value); } return $the_value; } }
是否需要执行
stripslashes()?
不需要。stripslashes()是为了兼容旧版PHP中magic_quotes_gpc开启时自动添加的转义符,而PHP5.4及以后该配置已被移除,默认处于关闭状态。如果强行使用,会错误移除用户输入的合法反斜杠(比如用户输入的路径C:\\Users\\xxx会变成C:\Users\xxx),破坏原始内容。直接注释掉这行即可,不会影响SQL注入防护效果。在
mysqli_real_escape_string()后添加引号是否可行?
可行且必要。mysqli_real_escape_string()仅负责转义字符串中的特殊字符(如单引号、反斜杠),不会自动为文本值添加SQL语句所需的单引号包裹。转义后再手动添加单引号,能确保文本值在SQL语句中是合法的字符串格式,既避免语法错误,也能有效防范SQL注入。该函数是否存在明显重大缺陷?
有几个需要优化的点,但不算致命缺陷:- 依赖全局数据库连接:函数依赖全局变量
$db,若后续代码结构调整(比如改用类封装数据库操作),函数会直接失效。建议将$db作为参数传入函数,提升独立性和可维护性。 - 浮点类型处理的精度风险:
floatval()处理部分字符串时可能出现精度丢失,且直接拼接进SQL语句时,不同数据库的浮点格式兼容性较差。如果是金额这类对精度要求高的场景,建议将其当作文本处理(转义加引号),或改用预处理语句。 - 类型判断代码冗余:多个独立的
if判断可合并为switch语句,代码会更简洁,但不影响功能逻辑。
- 依赖全局数据库连接:函数依赖全局变量
不使用
stripslashes()是否可行?
完全可行,甚至是推荐做法。如前所述,当前PHP环境已无magic_quotes_gpc的问题,保留用户输入的原始反斜杠是正确的选择。mysqli_real_escape_string()会正确处理这些反斜杠,既不会引发SQL注入,也能完整保留用户提交的原始内容。
内容的提问来源于stack exchange,提问作者adrianTNT

