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

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

閱讀前提:你必須看過php手冊上的"第IV部分安全"的"第10章魔術引號"。若是沒看過,也沒問題,如今立刻花10分鐘先看一下php手冊上的這東西。

魔術引號(Magic Quote)是一個自動將進入 PHP 腳本的數據進行轉義的過程

你可能想讓你的程序兼容多個數據庫,但你使用的不一樣的數據庫可能使用不一樣的轉義符,而咱們的程序又有可能運行在不一樣的php.ini配置的主機上,關於magic_quotes的配置又可能不同,因此編寫不受魔術引號影響的php應用是高兼容性的php應用所必須的。
mysql

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

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

        return trim($var);
    }
}
.net


    從上面的表咱們能夠看出,對於magic_quotes_runtime,我在程序中用 ini_set('magic_quotes_runtime', 0);就能夠把它關掉,而後能夠用本身的方法來處理來自數據庫或文件的數據。code

相關文章
相關標籤/搜索