addslashes 和 mysql_real_escape_string

先看手冊說明

1.addslashes


說明 ¶

string addslashes ( string $str )

返回字符串,該字符串爲了數據庫查詢語句等的需要在某些字符前加上了反斜線。這些字符是單引號(')、雙引號(")、反斜線(\)與 NUL(NULL 字符)。

一個使用 addslashes() 的例子是當你要往數據庫中輸入數據時。 例如,將名字 O'reilly 插入到數據庫中,這就需要對其進行轉義。 強烈建議使用 DBMS 指定的轉義函數 (比如 MySQL 是 mysqli_real_escape_string(),PostgreSQL 是 pg_escape_string()),但是如果你使用的 DBMS 沒有一個轉義函數,並且使用 \ 來轉義特殊字符,你可以使用這個函數。 僅僅是爲了獲取插入數據庫的數據,額外的 \ 並不會插入。 當 PHP 指令magic_quotes_sybase 被設置成 on 時,意味着插入 ' 時將使用 ' 進行轉義。

PHP 5.4 之前 PHP 指令 magic_quotes_gpc 默認是 on, 實際上所有的 GET、POST 和 COOKIE 數據都用被 addslashes() 了。 不要對已經被magic_quotes_gpc 轉義過的字符串使用 addslashes(),因爲這樣會導致雙層轉義。 遇到這種情況時可以使用函數 get_magic_quotes_gpc() 進行檢測。


2.mysql_real_escape_string


mysql_real_escape_string

(PHP 4 >= 4.3.0, PHP 5)

mysql_real_escape_string — 轉義 SQL 語句中使用的字符串中的特殊字符,並考慮到連接的當前字符集

說明 ¶

string mysql_real_escape_string ( string $unescaped_string [, resource $link_identifier ] )

本函數將 unescaped_string 中的特殊字符轉義,並計及連接的當前字符集,因此可以安全用於 mysql_query()

Notemysql_real_escape_string() 並不轉義 % 和 _


3.實現


/* {{{ php_addslashes
 */
PHPAPI char *php_addslashes(char *str, int length, int *new_length, int should_free 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;

	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;
}
/* }}} */





MYSQLND_METHOD(mysqlnd_conn_data, escape_string)(MYSQLND_CONN_DATA * const conn, char * newstr, const char * escapestr, size_t escapestr_len TSRMLS_DC)
{
	size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, escape_string);
	ulong ret = FAIL;
	DBG_ENTER("mysqlnd_conn_data::escape_string");
	DBG_INF_FMT("conn=%llu", conn->thread_id);

	if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
		DBG_INF_FMT("server_status=%u", conn->upsert_status->server_status);
		if (conn->upsert_status->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES) {
			ret = mysqlnd_cset_escape_quotes(conn->charset, newstr, escapestr, escapestr_len TSRMLS_CC);
		} else {
			ret = mysqlnd_cset_escape_slashes(conn->charset, newstr, escapestr, escapestr_len TSRMLS_CC);
		}
		conn->m->local_tx_end(conn, this_func, PASS TSRMLS_CC);
	}
	DBG_RETURN(ret);
}

/* {{{ mysqlnd_cset_escape_quotes */
PHPAPI ulong mysqlnd_cset_escape_quotes(const MYSQLND_CHARSET * const cset, char *newstr,
										const char * escapestr, size_t escapestr_len TSRMLS_DC)
{
	const char 	*newstr_s = newstr;
	const char 	*newstr_e = newstr + 2 * escapestr_len;
	const char 	*end = escapestr + escapestr_len;
	zend_bool	escape_overflow = FALSE;

	DBG_ENTER("mysqlnd_cset_escape_quotes");

	for (;escapestr < end; escapestr++) {
		unsigned int len = 0;
		/* check unicode characters */

		if (cset->char_maxlen > 1 && (len = cset->mb_valid(escapestr, end))) {

			/* check possible overflow */
			if ((newstr + len) > newstr_e) {
				escape_overflow = TRUE;
				break;
			}
			/* copy mb char without escaping it */
			while (len--) {
				*newstr++ = *escapestr++;
			}
			escapestr--;
			continue;
		}
		if (*escapestr == '\'') {
			if (newstr + 2 > newstr_e) {
				escape_overflow = TRUE;
				break;
			}
			*newstr++ = '\'';
			*newstr++ = '\'';
		} else {
			if (newstr + 1 > newstr_e) {
				escape_overflow = TRUE;
				break;
			}
			*newstr++ = *escapestr;
		}
	}
	*newstr = '\0';

	if (escape_overflow) {
		DBG_RETURN((ulong)~0);
	}
	DBG_RETURN((ulong)(newstr - newstr_s));
}
/* }}} */

/* {{{ mysqlnd_cset_escape_slashes */
PHPAPI ulong mysqlnd_cset_escape_slashes(const MYSQLND_CHARSET * const cset, char *newstr,
										 const char * escapestr, size_t escapestr_len TSRMLS_DC)
{
	const char 	*newstr_s = newstr;
	const char 	*newstr_e = newstr + 2 * escapestr_len;
	const char 	*end = escapestr + escapestr_len;
	zend_bool	escape_overflow = FALSE;

	DBG_ENTER("mysqlnd_cset_escape_slashes");
	DBG_INF_FMT("charset=%s", cset->name);

	for (;escapestr < end; escapestr++) {
		char esc = '\0';
		unsigned int len = 0;

		/* check unicode characters */
		if (cset->char_maxlen > 1 && (len = cset->mb_valid(escapestr, end))) {
			/* check possible overflow */
			if ((newstr + len) > newstr_e) {
				escape_overflow = TRUE;
				break;
			}
			/* copy mb char without escaping it */
			while (len--) {
				*newstr++ = *escapestr++;
			}
			escapestr--;
			continue;
		}
		if (cset->char_maxlen > 1 && cset->mb_charlen(*escapestr) > 1) {
			esc = *escapestr;
		} else {
			switch (*escapestr) {
				case 0:
					esc = '0';
					break;
				case '\n':
					esc = 'n';
					break;
				case '\r':
					esc = 'r';
					break;
				case '\\':
				case '\'':
				case '"':
					esc = *escapestr;
					break;
				case '\032':
					esc = 'Z';
					break;
			}
		}
		if (esc) {
			if (newstr + 2 > newstr_e) {
				escape_overflow = TRUE;
				break;
			}
			/* copy escaped character */
			*newstr++ = '\\';
			*newstr++ = esc;
		} else {
			if (newstr + 1 > newstr_e) {
				escape_overflow = TRUE;
				break;
			}
			/* copy non escaped character */
			*newstr++ = *escapestr;
		}
	}
	*newstr = '\0';

	if (escape_overflow) {
		DBG_RETURN((ulong)~0);
	}
	DBG_RETURN((ulong)(newstr - newstr_s));
}
/* }}} */

NO_BACKSLASH_ESCAPES:反斜槓“\”作爲普通字符而非轉義符.


4.總結


addslashes 和  mysql_real_escape_string如何選擇哪個?

sql注入是數據庫的行爲。所以最好的做法是在入庫的時候進行處理。所以提倡在入庫的時候,用php提供的數據庫的相關的轉義函數。

mysql 就用 mysql_real_escape_string,pdo 的就用 quote 。

所以不太提倡一上來就所有php的請求都進行addslashes。這樣會破壞原始的數據。也會污染入庫的數據。所以addslashes 是在迫不得或者說沒有數據庫上下文的時候在使用。但是這種情況下使用的意義在何處? 


參考文章

http://book.51cto.com/art/201204/331330.htm

http://www.2cto.com/kf/201206/137796.html

http://php.net/manual/zh/function.addslashes.php

http://php.net/manual/zh/function.mysql-real-escape-string.php

http://www.2cto.com/kf/201206/137796.html


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章