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

cnbird發表於2008-07-22
 

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

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

魔術引號(Magic Quote)是一個自動將進入 PHP 指令碼的資料進行轉義的過程

你可能想讓你的程式相容多個資料庫,但你使用的不同的資料庫可能使用不同的轉義符,而我們的程式又有可能執行在不同的php.ini配置的主機上,關於magic_quotes的配置又可能不一樣,所以編寫不受魔術引號影響的php應用是高相容性的php應用所必須的。

php.ini中有三個魔術引號配置選項:

  魔術引號配置選項   描述  執行時改變 在 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)

 能  Off

 

    但是要處理外部傳來的全域性變數就比較麻煩了。

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

    有人可能說,當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);之前完成的。

 

<?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]) && $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]) && $GLOBALS[`useQuotesSybase`][CONFIG_DB_DBMS]) {
                $var = str_replace("`", "``", $var);
            } else {
                $var = addslashes($var);
            }
        }

        return trim($var);
    }
}


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


相關文章