字符串过滤是Web应用安全的第一道防线,而在众多过滤手段中,针对不可见字符的处理经常被开发者忽略。CodeIgniter框架在核心全局函数文件中提供了remove_invisible_characters函数,专门用来剔除字符串中那些肉眼看不到却可能造成安全风险的控制字符。本文将从函数原型、源码实现、实际调用和常见误区几个方面,全面讲解这个函数的使用方法。

一、remove_invisible_characters函数的基本作用
所谓不可见字符,指的是ASCII控制字符范围内那些无法在页面上正常显示的字符,例如空字节\0、换行符、回车符、以及一些零宽字符。这些字符平时看起来无害,但在特定场景下却可能带来严重问题。比如文件名校验时,攻击者在文件名中插入空字节,可能截断后续的扩展名判断;在SQL语句拼接场景中,不可见字符可能干扰过滤规则的匹配结果。
remove_invisible_characters函数的定义位于CodeIgniter的核心公共函数文件中,属于全局函数,意味着它在框架加载完成后可以在任何地方直接调用,不需要引入额外的类或辅助函数文件。函数接收两个参数,第一个参数是要过滤的字符串,第二个参数是一个布尔值$url_encoded,用于控制是否同时处理URL编码形式的不可见字符,默认值为TRUE。
函数返回处理后的干净字符串,原字符串不会被修改,属于无副作用的纯函数调用。这也是推荐在接收用户输入的第一时间就调用它的原因,先清洗,再做后续的业务校验。
二、源码实现原理逐行解析
理解一个函数最好的方式就是阅读它的源码。下面是CodeIgniter中该函数的核心实现:
function remove_invisible_characters($str, $url_encoded = TRUE)
{
$non_displayables = array();
// URL编码形式的不可见字符,例如 %00 到 %08、%0b、%0c、%0e 到 %1f
if ($url_encoded)
{
$non_displayables[] = '/%0[0-8bcef]/i'; // 0-8, 11, 12, 14, 15
$non_displayables[] = '/%1[0-9a-f]/i'; // 16-31
}
// 原始形式的控制字符
$non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/S';
do
{
$str = preg_replace($non_displayables, '', $str, -1, $count);
}
while ($count);
return $str;
}从源码可以看出,函数维护了一个正则表达式数组。当$url_encoded为真时,会额外匹配经过URL编码的控制字符,例如%00表示空字节、%08表示退格符。这一步非常关键,因为浏览器提交表单数据时,特殊字符往往会以URL编码的形式传输,如果只过滤原始字符,编码形态的攻击载荷就会漏网。
第二个正则直接匹配原始十六进制控制字符。注意这里的范围是\x00到\x08、\x0B、\x0C、\x0E到\x1F以及\x7F。细心的读者会发现,\x09(制表符)、\x0A(换行符)、\x0D(回车符)并不在过滤范围内,这是有意为之的设计,因为这三个字符在正常文本中合法且常见,盲目剔除会破坏用户的原始输入。
最后的do-while循环值得重点关注。由于过滤掉一层字符后,剩余字符可能重新拼接成新的编码形态,例如%%3300去掉中间的3后会变成%00,所以函数采用循环替换,直到某次替换次数为零才停止,确保多重嵌套的隐藏字符被彻底清除。
三、实际调用场景与常见误区
在实际项目中,最常见的用法是在控制器中处理用户输入。示例如下:
class User extends CI_Controller
{
public function upload()
{
$filename = $this->input->post('filename');
// 过滤不可见字符后再进行业务校验
$clean_name = remove_invisible_characters($filename);
if ($clean_name !== $filename)
{
log_message('error', '检测到可疑的不可见字符输入');
}
// 后续处理逻辑
}
}第一个常见误区是认为开了框架的安全类Security就不需要这个函数。实际上,xss_clean主要针对HTML标签和JavaScript注入,对控制字符的覆盖并不完整,两者是互补关系而不是替代关系。建议在处理文件名、路由参数、邮件头等对字符敏感的场景时,显式调用remove_invisible_characters进行预处理。
第二个误区是忽略$url_encoded参数。如果你的数据来源是已经解码过的字符串,可以传FALSE跳过编码匹配,稍微提升一点性能;但如果不确定数据是否解码,保持默认值TRUE是更稳妥的选择。此外要注意,该函数只做字符剔除,不做转义,过滤完成后仍需配合参数化查询、输出转义等其他手段,多层防御才能构建真正安全的输入处理链路。把它放在接收输入的最前端,配合后续的校验和转义,可以让整个应用的安全过滤体系更加严密。
CodeIgniterremove_invisible_characters安全过滤修改时间:2026-09-07 15:04:38