結論:
1、使用php magic_quotes_gpc是錯誤的。從PHP 5.4.0 起已刪除此功能。http://www.php.net/manual/zh/function.get-magic-quotes-gpc.php
2、使用php addslashes是錯誤的。因為它不對應mysql或pgsql。PHP官方強烈建議使用對應mysql的mysqli_real_escape_string()和對應PostgreSQL的pg_escape_string()。http://php.net/manual/en/function.addslashes.php
3、儲存到資料庫之前使用htmlspecialchars是錯誤的。應直接儲存到資料庫。通過API提供給手機app看,C++不需要轉義HTML。通過web看時,才需要轉義。見。
4、使用php mysql_escape_string是錯誤的,已廢棄,應使用mysqli::real_escape_string。http://php.net/manual/en/function.mysql-escape-string.php
5、資料入庫前根據不同資料庫進行不同的轉義,這放在dao層。controller、model都不應該知道。
錯誤的轉義方式:
正確的轉義方式:
詳細分析如下。
為什麼要轉義:
1、字元與保留字衝突,比如HTML中的小與號<用於標籤
2、ASCII字元集中沒有此字元,比如HTML中以前經常寫成©
第2種情況現在已經無需考慮,因為 Windows 從 XP 開始、Linux 從 GNU glibc 2.2 開始,作業系統都支援Unicode字元集了,目前開發程式主流是使用Unicode的utf-8編碼。
本文只討論第1種情況。
需要轉義的內容:
|
需要轉義 |
不需要轉義的字元(常見錯誤) |
HTML |
<、& |
> |
mysql |
換行、斷行符號等 |
換頁、空格、<、>、& |
postgresql |
換頁、換行、斷行符號等 |
|
JSON |
"、\和控制字元 |
|
PHP常見轉義方法:
|
轉義範圍 |
不應使用addslashes |
單引號'、雙引號"、反斜線\與 NUL |
htmlspecialchars |
&、'、"、<、> |
不應使用mysql_escape_string |
對應mysql 4 |
mysqli::real_escape_string |
對應mysql 5+ |
pg_escape_string |
對應PostgreSQL |
php PDO::quote |
自動判斷資料庫是Mysql還是PostgreSQL等 |
PDO::prepare() |
自動判斷資料庫是Mysql還是PostgreSQL等 |
對字串"hello world\fjim\n\r"進行轉義,結果如下:
mysqli::real_escape_string
View Code
<?php$mysqli = new mysqli('localhost', 'root', '1', 'test');$a = "hello world\fjim\n\r";var_dump($mysqli->real_escape_string($a));$sql = "INSERT INTO user VALUES ('2','lucy','". $mysqli->real_escape_string($a) . '\');';var_dump($sql);$mysqli->query($sql);?>
PDO::quote mysql 與 mysqli::real_escape_string 結果一樣。
View Code
<?php$dsn = 'mysql:dbname=test;host=localhost';$user = 'root';$password = '1';$dbh = new PDO($dsn, $user, $password);$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);$a = "hello world\fjim\n\r";var_dump($dbh->quote($a));$sql = "INSERT INTO user VALUES ('2','lucy',". $dbh->quote($a) . ');';var_dump($sql);$stmt = $dbh->query($sql);exit;?>
pg_escape_string
View Code
<?php$db = pg_connect("host=localhost port=5432 dbname=test user=root password=1");$a = "hello world\fjim\n\r";var_dump(pg_escape_string($a));$sql = "INSERT INTO schema1.user VALUES ('2','lucy','". pg_escape_string($a) . '\');';var_dump($sql);pg_query($db, $sql);exit;?>
PDO::quote pgsql 與pg_escape_string 結果相同。
View Code
<?php$dsn = 'pgsql:host=localhost;port=5432;dbname=test;user=root;password=1';$dbh = new PDO($dsn);$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);$a = "hello world\fjim\n\r";var_dump($dbh->quote($a));//$stmt = $dbh->query('SELECT "id","name","desc" FROM schema1."user"');//$sql = "INSERT INTO schema1.user VALUES ('1','jim','hello world\fjim\n\r');";$sql = "INSERT INTO schema1.user VALUES ('2','lucy',". $dbh->quote($a) . ');';var_dump($sql);$stmt = $dbh->query($sql);exit;?>
HTML:
HTML標籤使用小與號<開頭,所以需要轉義。而大與號>不用轉義。官方文檔:http://www.w3.org/TR/xhtml1/#h-4.8
mysql:
官方文檔:http://dev.mysql.com/doc/refman/5.1/zh/language-structure.html#string-syntax
mysql在預設的空sql-mode下,value的string使用單引號'或雙引號"引起來,官方文檔:http://dev.mysql.com/doc/refman/5.1/zh/language-structure.html#string-syntax
mysql在預設的空sql-mode下,識別符(庫、表、索引、列和別名)使用反勾號`引起來,官方文檔:http://dev.mysql.com/doc/refman/5.1/zh/language-structure.html#legal-names
mysql在ANSI_QUOTES sql-mode下,value的string使用單引號'引起來,官方文檔:http://dev.mysql.com/doc/refman/5.1/zh/language-structure.html#string-syntax
mysql在ANSI_QUOTES sql-mode下,識別符(庫、表、索引、列和別名)使用雙引號"或反勾號`引起來,http://dev.mysql.com/doc/refman/5.1/zh/database-administration.html#server-sql-mode
這裡以預設的空sql-mode為例。
如果string使用雙引號引起來,那麼string中的單引號無需轉義。如果string使用單引號引起來,那麼string中的雙引號無需轉義。
使用musqldump匯出sql就會看到,mysql的string使用單引號'引起來,而雙引號一定被轉義。
比如INSERT INTO `asdf` VALUES ('a\"b'); 和 INSERT INTO `asdf` VALUES ('a"b'); 結果是一樣的。
postgresql:
官方文檔:http://wiki.postgresql.org/wiki/9.1%E7%AC%AC%E5%9B%9B%E7%AB%A0#C.E8.AF.AD.E8.A8.80.E4.B8.AD.E7.9A.84.E8.BD.AC.E6.84.8F.E5.AD.97.E7.AC.A6.E4.B8.B2.E5.B8.B8.E9.87.8F.28String_Constants_with_C-style_Escapes.29
value的string使用單引號'引起來或者不引。
識別符(列名等)使用雙引號"引起來或者不引。
JSON:
官方文檔:http://www.json.org/json-zh.html
JSON的string,必須使用雙引號"引起來,不能使用單引號'引起來。如果字串中出現雙引號,需要轉義,比如{"name" : "John \"Cliff\" Barxter"}。
參考資料:
http://www.ibm.com/developerworks/cn/linux/i18n/unicode/linuni/
http://msdn.microsoft.com/zh-cn/magazine/cc163490.aspx
採用支援 Unicode 的單原始碼庫使開發時間得以縮短,Unicode 為 Microsoft 帶來的好處是顯而易見的。就 Windows 2000 來說,在發布英文產品後需要花費幾個月的時間來準備其語言版本。而對於 Windows XP,這一周期已縮短為幾周時間。