在 CodeIgniter 做的網站裡,想輸入一段代碼:
$var = sprintf("%04d", 2);
但是發現入庫後,代碼變成了
$var = sprintf("d", 2);
在網上環境,本地環境都測試過,最終確認是 CodeIgniter 系統的問題。下面談一下問題解決的過程與思維方法:
1. 是 config.php 的 permitted_uri_chars 嗎?
$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() 函數問題嗎?
function _clean_input_keys($str) { $config = &get_config('config'); if ( ! preg_match("/^[".$config['permitted_uri_chars']."]+$/i", rawurlencode($str))) { exit('Disallowed Key Characters.'); } // Clean UTF-8 if supportedif (UTF8_ENABLED === TRUE){$str = $this->uni->clean_string($str);}return $str; }
這個函數使用了 $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 有聯絡。
$new_array[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
於是把 _clean_input_data() 的函數體注釋掉,竟然輸入沒被過濾了。繼續縮小範圍,發現是這段代碼惹得禍:
// Remove control characters// 就是這個會把%0x過濾掉$str = remove_invisible_characters($str);
5. 元兇找到了 remove_invisible_characters() 函數
那麼 remove_invisible_characters() 這個函數是什麼呢?
這個函數在 core/Common.php中,我把它揪出來:
function remove_invisible_characters($str, $url_encoded = TRUE){$non_displayables = array();// every control character except newline (dec 10)// carriage return (dec 13), and horizontal tab (dec 09)if ($url_encoded){$non_displayables[] = '/%0[0-8bcef]/';// url encoded 00-08, 11, 12, 14, 15$non_displayables[] = '/%1[0-9a-f]/';// url encoded 16-31}$non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S';// 00-08, 11, 12, 14-31, 127do{$str = preg_replace($non_displayables, '', $str, -1, $count);}while ($count);return $str;}
看這麼幾行代碼:
if ($url_encoded){$non_displayables[] = '/%0[0-8bcef]/';// url encoded 00-08, 11, 12, 14, 15$non_displayables[] = '/%1[0-9a-f]/';// url encoded 16-31}
明確了吧,他會把%0與%1開頭的3個字元過濾掉。直接把這個注釋掉,問題解決。
記錄這個問題解決的思維全過程。
http://www.bkjia.com/PHPjc/752355.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/752355.htmlTechArticle在 CodeIgniter 做的網站裡,想輸入一段代碼: $var = sprintf("%04d", 2); 但是發現入庫後,代碼變成了 $var = sprintf("d", 2); 在網上環境,本地環境都...