addslashes和mysql_real_escape_string.都是為了使數據安全的插入到數據庫中而進行過濾.那么這兩個函數到底是有什么區別呢??
我們今天來簡單的看下..
首先.我們還是從PHP手冊入手..
手冊上addslashes轉義的字符是單引號(')、雙引號(")、反斜線(\)與NUL(NULL 字符)。
mysql_real_escape_string轉義的字符並沒有被提到.只是說了一句
注意: mysql_real_escape_string() 並不轉義% 和_。
為什么PHP手冊沒有說呢?因為其實這是個MySql的C的API.所以我們需要查下MySql手冊..上面是這么說的.
編碼的字符為NUL (ASCII 0)、'\n'、'\r'、'\'、'''、'"'、以及Control-Z(請參見9.1節,“文字值”)。(嚴格地講,MySQL僅需要反斜杠和引號字符,用於引用轉義查詢中的字符串。該函數能引用其他字符,從而使得它們在日志文件中具有更好的可讀性)。
不得不說一句.MySql手冊上面的話總是令人費解的..
我們為了更深層次的探究這兩個函數的不同..還是去看一看PHP的源碼吧..
這是PHP的addslashes函數..
PHP_FUNCTION(addslashes)
{
zval **str;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(str);
if (Z_STRLEN_PP(str) == 0) {
RETURN_EMPTY_STRING();
}
RETURN_STRING(php_addslashes(Z_STRVAL_PP(str),
Z_STRLEN_PP(str),
&Z_STRLEN_P(return_value), 0
TSRMLS_CC), 0);
}
很顯然.它調用了php_addslashes.我們繼續看這個函數
PHPAPI char *php_addslashes(char *str, int length, int *new_length, int should_free TSRMLS_DC)
{
return php_addslashes_ex(str, length, new_length, should_free, 0 TSRMLS_CC);
}
結果又是是在調用php_addslashes_ex 我們就像在剝洋蔥一樣..一步一步的接近真理..
PHPAPI char *php_addslashes_ex(char *str, int length, int *new_length, int should_free, int ignore_sybase TSRMLS_DC)
{
/* maximum string length, worst case situation */
char *new_str;
char *source, *target;
char *end;
int local_new_length;
if (!new_length) {
new_length = &local_new_length;
}
if (!str) {
*new_length = 0;
return str;
}
new_str = (char *) safe_emalloc(2, (length ? length : (length = strlen(str))), 1);
source = str;
end = source + length;
target = new_str;
if (!ignore_sybase && PG(magic_quotes_sybase)) {
while (source < end) {
switch (*source) {
case '\0':
*target++ = '\\';
*target++ = '0';
break;
case '\'':
*target++ = '\'';
*target++ = '\'';
break;
default:
*target++ = *source;
break;
}
source++;
}
} else {
while (source < end) {
switch (*source) {
case '\0':
*target++ = '\\';
*target++ = '0';
break;
case '\'':
case '\"':
case '\\':
*target++ = '\\';
/* break is missing *intentionally* */
default:
*target++ = *source;
break;
}
source++;
}
}
*target = 0;
*new_length = target - new_str;
if (should_free) {
STR_FREE(str);
}
new_str = (char *) erealloc(new_str, *new_length + 1);
return new_str;
}
上面的函數已經非常清楚的描述出都要轉義哪些字符了..現在我們去看一看mysql_real_escape_string
這個不在string.c里了..是在mysql擴展中.
PHP_FUNCTION(mysql_real_escape_string)
{
zval *mysql_link = NULL;
char *str;
char *new_str;
int id = -1, str_len, new_str_len;
php_mysql_conn *mysql;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|r", &str, &str_len, &mysql_link) == FAILURE) {
return;
}
if (ZEND_NUM_ARGS() == 1) {
id = php_mysql_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU);
CHECK_LINK(id);
}
ZEND_FETCH_RESOURCE2(mysql, php_mysql_conn *, &mysql_link, id, "MySQL-Link", le_link, le_plink);
new_str = safe_emalloc(str_len, 2, 1);
new_str_len = mysql_real_escape_string(&mysql->conn, new_str, str, str_len);
new_str = erealloc(new_str, new_str_len + 1);
RETURN_STRINGL(new_str, new_str_len, 0);
}
這個函數並沒有像上面的那樣剝洋蔥..
而是直接調用了MySql的C的API.mysql_real_escape_string()..
需要注意的是.這個函數在調用mysql_real_escape_string這個API之前.先是判斷了是否連接上了數據庫
CHECK_LINK(id); //就是這句
所以這就意味着mysql_real_escape_string必須是連接數據庫之后才能使用.為了證實這一點.
我們來簡單的實驗下.
<?php
echo mysql_real_escape_string("fdsafda'fdsa");
結果
Warning: mysql_real_escape_string() [function.mysql-real-escape-string]: Access denied for user 'ODBC'@'localhost' (using password: NO) in PHPDocument1 on line 2
Warning: mysql_real_escape_string() [function.mysql-real-escape-string]: A link to the server could not be established in PHPDocument1 on line 2
果然報錯了..顯示沒有鏈接上數據庫..
好了..總結就先告一段落..
我們終於明白為什么那么多開源的程序比如Discuz用addslashes而不用mysql_real_escape_string了.
所以呢.以后也就用addslashes好了..暫時可以忘記掉mysql_real_escape_string了