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


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