天天看點

編寫不受魔術引号影響的php應用

原創作品author流水孟春,轉載請注明出處lib.cublog.cn

閱讀前提:你必須看過php手冊上的"第IV部分安全"的"第10章魔術引号"。如果沒看過,也沒問題,現在馬上花10分鐘先看一下php手冊上的這東西。

<code>魔術引号(Magic Quote)是一個自動将進入 PHP 腳本的資料進行轉義的過程 你可能想讓你的程式相容多個資料庫,但你使用的不同的資料庫可能使用不同的轉義符,而我們的程式又有可能運作在不同的php.ini配置的主機上,關于magic_quotes的配置又可能不一樣,是以編寫不受魔術引号影響的php應用是高相容性的php應用所必須的。</code>

<code>php.ini中有三個魔術引号配置選項:</code>

  魔術引号配置選項

  描述

 運作時改變

在 PHP中的預設值為 

  magic_quotes_gpc

如果打開的話,影響到 HTTP 請求資料(GET,POST 和 COOKIE)。

 不能

 On

 magic_quotes_runtime

如果打開的話,大部份從外部來源取得資料并傳回的函數,包括從資料庫和文本檔案,所傳回的資料都會被反斜線轉義。(前提是magic_quotes_gpc = On)

 能

 Off

 magic_quotes_sybase

當關閉時,所有的 '(單引号),"(雙引号),/(反斜線)和 NULL 字元都會被自動加上一個反斜線進行轉義。這和 addslashes() 作用完全相同。

    如果打開的話,将會使用單引号對單引号進行轉義而非反斜線。此選項會完全覆寫 magic_quotes_gpc。如果同時打開兩個選項的話,單引号将會被轉義成 ''。而雙引号、反斜線 和 NULL 字元将不會進行轉義。 

(前提是magic_quotes_gpc = On)

<code>    但是要處理外部傳來的全局變量就比較麻煩了。</code>

<code>要處理外部超級變量,我們要看magic_quotes_gpc是否已經打開(如果magic_quotes_gpc沒打開,而magic_quotes_sybase打開,magic_quotes_sybase也不起作用),還要看magic_quotes_sybase是否打開,再看我們的程式需要對外部變量用addslashes轉義方式還是使用magic_quotes_sybase式的轉義方式。下面的代碼是一個具體的實作。</code>

<code>    有人可能說,當magic_quotes_gpc設成On,而magic_quotes_sybase設成Off,那麼直接用ini_set('magic_quotes_sybase', 1);就能讓系統用'來對addslashes式的轉義進行覆寫。這樣是不行的。你用ini_get('magic_quotes_sybase')輸出看下配置,magic_quotes_sybase的确被改變了,但是你的代碼就是不能用'轉義符覆寫addslashes式的自動轉義。這是因為系統擷取外部變量的時候,是在你的ini_set('magic_quotes_sybase', 1);之前完成的。</code>

<code></code> 

<code>&lt;?php /**  * 解決不受magic_quotes影響的php應用  *  * 使用這個處理辦法需要配置是否使用magic_quotes_sybase, 以适應不同的DBMS  *  * 設定方法:  * $useQuotesSybase[資料庫名] = 1;  * 如:使用sqlite,則定義并初始化 $useQuotesSybase['sqlite'] = 1;  * 如果使用mysql,可以定義并初始化 $useQuotesSybase['sqlite'] = 0; 也可以不定義  *  * CONFIG_DB_DBMS 為所用的DBMS的常量, 在别處定義。比如 define('CONFIG_DB_DBMS', 'mysql');  *  * @author 流水孟春 cmpan(at)qq.com  * @link http://lib.cublog.cn  * $date 2007.11.18  */ error_reporting(E_ALL); set_magic_quotes_runtime(0); define('CONFIG_DB_DBMS', 'sqlite'); // 測試用 // 使用 ' 做轉義符的資料庫 $useQuotesSybase = array(); $useQuotesSybase['sqlite'] = 1; $useQuotesSybase['sybase'] = 1; if(!empty($_POST)) $_POST = array_map('quotesOuterVars', $_POST); if(!empty($_GET)) $_GET = array_map('quotesOuterVars', $_GET); $_COOKIE = array_map('quotesOuterVars', $_COOKIE); $_REQUEST = array_map('quotesOuterVars', $_REQUEST); function quotesOuterVars($var) {     if (is_array($var)) {         return array_map('quotesOuterVars',$var);     } else {         if (get_magic_quotes_gpc()) {             if (isset($GLOBALS['useQuotesSybase'][CONFIG_DB_DBMS]) &amp;&amp; $GLOBALS['useQuotesSybase'][CONFIG_DB_DBMS]) {                 // 目前需要以 ' 為轉義符                 // 如果 magic_quotes_sybase = Off, 系統将把外部變量 addslashes, 我們得先 stripslashes                 // 否則系統自動把 ' 換成 '',                 if (!ini_get('magic_quotes_sybase')) {                     $var = stripslashes($var);                     $var = str_replace("'", "''", $var);                 }             } else {                 // 目前需要以 / 為轉義符                 // 如果 magic_quotes_sybase = On, 我們先把 '' 替換成 ', 然後在 addslashes                 // 否則系統自動quotes                 if (ini_get('magic_quotes_sybase')) {                     $var = str_replace("'", "''", $var);                     $var = addslashes($var);                 }             }         } else{             if (isset($GLOBALS['useQuotesSybase'][CONFIG_DB_DBMS]) &amp;&amp; $GLOBALS['useQuotesSybase'][CONFIG_DB_DBMS]) {                 $var = str_replace("'", "''", $var);             } else {                 $var = addslashes($var);             }         }</code>

<code>        return trim($var);     } }</code>

<code></code><code>    從上面的表我們可以看出,對于magic_quotes_runtime,我在程式中用 ini_set('magic_quotes_runtime', 0);就可以把它關掉,然後可以用自己的方法來處理來自資料庫或檔案的資料。</code>