诺亚方舟

沉淀

PHP转义与编码函数小结

前面用到php转义、编码函数时,一直都很不知所以然,人云亦云,这篇文章用来总结下php转义函数的用法。

1、url_encode、url_decode

首先要说明这种encode的作用,url_encode会将字符串中除了 -_. 之外的所有非字母数字字符都将被替换成百分号(%)后跟两位十六进制数,空格则编码为加号(+),使用url_encode后接收的数据,需要显示或隐式进行url_decode才能获得原先的数据。

这里说明下我对post、get两种http请求方式关于urlencode的理解。

form表单以get形式提交数据时,是将请求追加到url后面。若将参数带到url中,需要手动进行urlencode,服务器接受方也要对应进行urldecode。

form表单以post形式提交数据,是把数据封装在http body中,这时便会有两种不同的形式。

①entype:application/x-www-form-urlencode:会对提交的数据自动进行urlencode,服务端接收到请求后会根据编码类型自动进行urldecode。

②entype:mutipare/form-data:二进制方式提交数据,不做urlencode,服务端自然也不会进行urldecode。

综上所述,当web中表单以post形式提交请求时,客户端并不需要手动进行urlencode,服务端接收数据后会自动根据请求类型来判断是否进行urldecode,也无需手动。

curl是大家都很喜欢用的一个请求模拟工具,那么问题又来了,curl中post方式又是否需要手动进行urlencode?(get方式显而易见是需要的)

实际上,curl来post数据时也有两种方式,一种是将所有参数拼做一串字符串,这相当于上述①,不同的是curl并不会自动urlencode,所有这里客户端需要手动,但服务端是会自动进行urldecode的;另一种则将参数按一个数组的方式提交,这相当于上述②,并不需要进行urlencode与urldecode。

=============================2017-10-15=============================

最近无意中发现,nginx会对urlencode做一些意外的处理,当客户端以post方式,Content-Type: application/x-www-form-urlencoded提交时,nginx服务器会自动进入一次urldecode,这个过程应用层是无感的;而单客户端以get方式提交时,如果客户端手动加上了urlencode,此时nginx会“自作聪明”,对数据自动进行一次urldecode,fastcgi拿到的数据就是urldecode后的内容了,跟我们所想的内容并不一样。

2、json_encode、json_decode

可以接受除了resource 类型之外的任何数据类型 ,前提是只能支持UTF8格式的编码。

3、base64_encode、base64_encode

 base64_encode的作用是对给定的字符串使用base64编码,设计此种编码是为了使二进制数据可以通过非纯 8-bit 的传输层传输,例如电子邮件的主体就需要用到该函数来编码。据说Base64-encoded后的数据要比原始数据多占用 33% 左右的空间。

4、magic_quotes_gpc

 magic_quotes_gpc设置是否自动为GPC(GET,POST,COOKIE)传来的数据中的某些字符进行转义, 可以使用get_magic_quotes_gpc()检测其设置。这些字段包括单引号(’)、双引号(”)、反斜线(\)与 NULL(NULL 字符)等字符。注意,若开启为on,输入会自动转义,但输出不会自动进行反转义(即会按转义后字符串输出)。

若php中该项设置为off,则代码必须对输入进行字符串转义,以保证sql安全,常用函数addslashes。php6已取消该项,所以代码不应该 过分依赖系统默认设置。

5、addslashes()、stripslashes()

 这个函数就是为magic_quotes_gpc为off时而用,手动为字符串转义,预定义字符包括:

单引号 (‘)、双引号 (“)、反斜杠 (\)、NULL。

strupslaches()负责将转义字符反转义。

 

6、mysql_escape_string()、mysql_escape_real_string()

 首先:不要使用mysql_escape_string,它已被弃用,请使用mysql_real_escape_string代替它。

mysql_escape_real_string()与addslashes()有什么区别呢?两者都是为输入数据做安全转义,不同的有两点。第一,mysql_escape_real_string()转义的字符集比addslashes多(包括了\x00,\n,\r,\,’,”,\x1a),第二,前者的转义是基于mysql指定编码后的字符,后者是基于当前环境的编码字符。怎么理解第二点,看下面的栗子:

首先创建一个gbk表格。

1
2
3
4
5
CREATE TABLE users(
 username VARCHAR(32) CHARACTER SET GBK,
 password VARCHAR(32) CHARACTER SET GBK,
 PRIMARY KEY(username)
);

然后,注入username=chr(0xbf) . chr(0×27) . ‘ OR username = username ‘

1
2
3
4
5
6
7
8
9
$mysql = array();
$db = mysqli_init();
$db->real_connect('localhost', 'lorui', 'lorui.com', 'lorui_db');
$_POST['username'] = chr(0xbf) . chr(0×27) . ' OR username = username ';
 $_POST['password'] = 'guess'; 
$mysql['username'] = addslashes($_POST['username']); 
$mysql['password'] = addslashes($_POST['password']); 
$sql = “SELECT * FROM users WHERE username = '{$mysql['username']}' AND password = '{$mysql['password']}'; $result = $db->query($sql); 
if ($result->num_rows) { /* 成功 */ } else { /* 失败 */ }

0xbf27经过addslashes转义后会变成0xbf5c27,这对于mysql的编码来说恰好是注入了一个单引号。原因详见文章:http://www.jb51.net/article/49205.htm

最后介绍下这个函数的原型:mysql_real_escape_string(string,connection)

第一个参数不用解释,第二个参数是指指定的mysql链接,这使转义跟选定的编码很有关系(记不记得建立mysql链接的时候要选择编码?),若为空则指定上一个可用链接。

 

7、addcslashes()和stripcslashes()

 addcslashes()‍以C 语言风格使用反斜线转义字符串中的字符,这个函数很少人去用,但是应该注意的是:当选择对字符 0,a,b,f,n,r,t 和 v 进行转义时,它们将被转换成 \0,\a,\b,\f,\n,\r,\t 和 \v。在 PHP 中,只有 \0(NULL),\r(回车符),\n(换行符)和 \t(制表符)是预定义的转义序列, 而在 C 语言中,上述的所有转换后的字符都是预定义的转义序列。同理stripcslashes()的功能就是去除其转义。

8、htmlentities() 和html_entity_decode()

htmlentities() 的作用是让浏览器输出html代码,不去解析该html代码了,比如说在发帖的时候,为了不让其输入的html代码生效,可以使用htmlentities。

函数原型:htmlentities(string,quotestyle,character-set)

string是必选参数,是需要转换的字符串。其余可选,quotestyle规定如何编码单引号和双引号:ENT_COMPAT – 默认。仅编码双引号;ENT_QUOTES – 编码双引号和单引号;ENT_NOQUOTES – 不编码任何引号。character-set是规定转换用的字符集,常用的有UTF-8/GB-2312/ISO-8859-1(默认)。

html_entity_decode()函数的作用相反,把html实体转换回html标签。

9、htmlspecialchars()和htmlspecialchars_decode()

htmlspecialchars()这个函数的功能与htmlentities()是相似的,不同的是作用的结果集较小,只针对& ‘ ” < 和 > 这几个特殊符号。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>