CI自动过滤掉百分号%后两位的问题解决

原文:http://www.nowamagic.net/librarys/veda/detail/1721


在 CodeIgniter 做的网站里,想输入一段代码:

1 $var = sprintf("%04d", 2);

但是发现入库后,代码变成了

1 $var = sprintf("d", 2);

在网上环境,本地环境都测试过,最终确认是 CodeIgniter 系统的问题。下面谈一下问题解决的过程与思维方法:

1. 是 config.php 的 permitted_uri_chars 吗?

1 $config['permitted_uri_chars'] = 'a-z 0-9~%.:_\-';

在 stackoverflow 上找到几个差不多的问题,有答案说改 config.php 的 permitted_uri_chars 就行了。

Ahem... after looking at your sample string again. Here is why you get "The URI you submitted has disallowed characters".

Short explanation: Add the ampersand & to the allowed characters list

$config['permitted_uri_chars'] = 'a-z 0-9~%.:_+&-';

试过了,没效果,于是就查找应用了 $config['permitted_uri_chars'] 的代码。

2. 是 core/Input.php 的 _clean_input_keys() 函数问题吗?

01 function _clean_input_keys($str)  
02 {  
03     $config = &get_config('config');  
04     if ( ! preg_match("/^[".$config['permitted_uri_chars']."]+$/i", rawurlencode($str)))  
05     {  
06         exit('Disallowed Key Characters.');  
07     }  
08      
09     // Clean UTF-8 if supported
10     if (UTF8_ENABLED === TRUE)
11     {
12         $str $this->uni->clean_string($str);
13     }
14     return $str;  
15 }

这个函数使用了 $config['permitted_uri_chars'] 直接过滤 post 过来的数据,很大原因就是元凶了。我把它单独出来,经过测试发现,post $var = sprintf("%04d", 2); 过来,结果还是 $var = sprintf("%04d", 2); ,%04并未被过滤,看来还得细细地找。

3. 是 xss 的防御机制吗?

stackoverflow 有个人说他完美解决了这个问题,是 xss clean 的原因。

:) God damn URLDECODE, I have looked at the code in URI.php but the xss clean is doing the job so I missed it. Thank you now everything is perfect. – RaduM

于是我找到了 core/security.php 下的 xss_clean() 函数。把函数体代码全部注释掉,发现输入还是会把 %04 过滤掉,显然也不是 xss 的问题。

4. 问题出在 _clean_input_data() 函数

重新回到 Input.php,发现 _clean_input_data 与 _clean_input_keys 有联系。

1 $new_array[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);

于是把 _clean_input_data() 的函数体注释掉,竟然输入没被过滤了。继续缩小范围,发现是这段代码惹得祸:

1 // Remove control characters
2 // 就是这个会把%0x过滤掉
3 $str = remove_invisible_characters($str);

5. 元凶找到了 remove_invisible_characters() 函数

那么 remove_invisible_characters() 这个函数是什么呢?

这个函数在 core/Common.php中,我把它揪出来:

01 function remove_invisible_characters($str$url_encoded = TRUE)
02 {
03     $non_displayables array();
04      
05     // every control character except newline (dec 10)
06     // carriage return (dec 13), and horizontal tab (dec 09)
07      
08     if ($url_encoded)
09     {
10         $non_displayables[] = '/%0[0-8bcef]/';  // url encoded 00-08, 11, 12, 14, 15
11         $non_displayables[] = '/%1[0-9a-f]/';   // url encoded 16-31
12     }
13      
14     $non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S';   // 00-08, 11, 12, 14-31, 127
15  
16     do
17     {
18         $str = preg_replace($non_displayables''$str, -1, $count);
19     }
20     while ($count);
21  
22     return $str;
23 }

看这么几行代码:

1 if ($url_encoded)
2 {
3     $non_displayables[] = '/%0[0-8bcef]/';  // url encoded 00-08, 11, 12, 14, 15
4     $non_displayables[] = '/%1[0-9a-f]/';   // url encoded 16-31
5 }

明确了吧,他会把%0与%1开头的3个字符过滤掉。直接把这个注释掉,问题解决。

记录这个问题解决的思维全过程。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值