4.5 编码和转义
Encoding and Escaping
因为PHP程序经常与HTML页、web地址(URL)以及数据库交互,所以PHP提供一些函数来帮助你处理这些类型的数据。HTML、web页地址和数据库命令都是字符串,但是它们每个都要求不同的字符以不同的方法来转义。例如,在web地址中一个空格被写作%20,而直接量小于符号(<)在HTML文档中必须写作<。PHP有许多内置函数来转换和取得这些编码。
4.5.1 HTML
HTML
在HTML中特殊的字符以实体(entity)表示,如 & 和 <。这里有两个PHP函数来把字符串中的特殊字符转换为实体,一个用于删除HTML标签,一个仅用于提取meta标签。
4.5.1.1 对所有特殊字符进行实体引用
函数htmlentities( )将HTML字符转换为对应的实体(除了空格符)。包括小于符号(<)、大于符号(>)、与号(&)和重音字符。
例如:
$string = htmlentities("Einstürzende Neubauten");
echo $string;
Einstürzende Neubauten
经过实体转义的版本在web页面中正确地显示了ü(如果在页面上点右键,查看源代码可以看到实体ü)。如你所看到的那样,空格没有被转换成 。
函数htmlentities( )实际上有3个参数:
$output = htmlentities(input, quote_style, charset);
如果给了参数,charset则识别字符集。默认的字符集是“ISO-8859-1”。参数quote_style 控制单引号和双引号是否变成它们实体的形式。ENT_COMPAT(默认值)只转换双引号;ENT_QUOTES两种引号都转换;ENT_NOQUOTES则一种都不转换。没有只转换单引号的选项,例如:
$input = <<< End
"Stop pulling my hair!" Jane's eyes flashed.<p>
End;
$double = htmlentities($input);
// "Stop pulling my hair!" Jane's eyes flashed.<p>
$both = htmlentities($input, ENT_QUOTES);
// "Stop pulling my hair!" Jane's eyes flashed.<p>
$neither = htmlentities($input, ENT_NOQUOTES);
// "Stop pulling my hair!" Jane's eyes flashed.<p>
4.5.1.2 只对HTML语法字符进行实体引用
函数htmlspecialchars( )转换最小的实体集来生成合法的HTML。下面的实体被转换:
l 与符号 (&)被转换成 &
l 双引号(")被转换成 "
l 单引号 (') 被转换成 ' (就像调用htmlentities( )时使用ENT_QUOTES 的效果)
l 小于号 (<)被转换成 <
l 大于号 (>)被转换成 >
如果有一个应用程序来显示用户填入表单的数据,则要在显示和保存数据之前通过htmlspecialchars( )处理数据。如果没有处理的话,一旦用户提交了像“angle < 30”或“sturm & drang”这样的字符串,浏览器会认为这些特殊的字符是HTML,从而得到一个混乱的页面。
和htmlentities( )类似,htmlspecialchars( )可以有3个参数:
$output = htmlspecialchars(input, [quote_style,[charse]]);
参数quote_style 和 charset 同它们在htmlentities( )中的意义相同。
没有专门的函数来把实体转换回原始的文本,因为很少需要这样做。不过这里有一个相对简单的方法来完成这个任务。使用函数get_html_translation_table( )用特定引号的方式获取被任一转换函数使用的转换表。例如,要获得htmlentities( )使用的转换表,可以这样做:
$table = get_html_translation_table(HTML_ENTITIES);
要在ENT_NOQUOTES模式下获得htmlspecialchars( )的转换表,可以这样做:
$table = get_html_translation_table(HTML_SPECIALCHARS, ENT_NOQUOTES);
使用转换表的一个小技巧是,用array_flip( )翻转它、并把它传给strtr( )来得到一个字符串。因此有效的回滚htmlentities( )操作的方法是:
$str = htmlentities("Einstürzende Neubauten"); //现在被编码了
$table = get_html_translation_table(HTML_ENTITIES);
$rev_trans = array_flip($table);
echo strtr($str,$rev_trans); // 回复到正常
Einst Ürzende Neubauten
当然,你也可以取出转换表,增加你想要它转换的其他东西,然后使用strtr( )。例如,如果想让htmlentities( )把空格编码为 s,可以这样做:
$table = get_html_translation_table(HTML_ENTITIES);
$table[' '] = ' ';
$encoded = strtr($original, $table);
4.5.1.3 删除HTML标签
函数strip_tags( )从字符串中删除HTML标签:
$input = '<p>Howdy, "Cowboy"</p>';
$output = strip_tags($input);
// $output is 'Howdy, "Cowboy"'
函数可以有第二个参数来指定在字符串中留下的标签。只列出标签的开始形式,在第二个参数中列出的标签结束形式也将被保留:
$input = 'The <b>bold</b> tags will <i>stay</i><p>';
$output = strip_tags($input, '<b>');
// $output is 'The <b>bold</b> tags will stay'
在保留标签中的属性不会被strip_tags( )改变。由于HTML标签属性(例如style和onmouseover)可以影响web页面的外观和行为,所以用strip_tags( )保留一些标签可能会导致无法删除所有潜在的冗余内容。
4.5.1.4 提取元标签
如果你把web页面的HTML存在一个字符串中,函数get_meta_tags( )可返回包含该页面中元标签(meta tag)内容的数组。元标签的名字(keywords、author、escription等)成为数组的键,而元标签的内容则成为对应的值:
$meta_tags = get_meta_tags('http://www.example.com/');
echo "Web page made by {$meta_tags[author]}";
Web page made by John Doe
函数的一般形式是:
$array = get_meta_tags(filename [, use_include_path]);
可以指定参数use_include_path 为true,这样可使PHP尝试用标准包含路径打开文件。
4.5.2 URLs URL
PHP提供了一些函数用于对URL进行编码和解码。实际上有两种方法对URL编码,其区别在于如何处理空格。第一种(根据RFC 1738规范)把空格当作URL中的另一个非法字符并把它编码为%20。第二种(执行application/x-www-form-urlencoded 系统)把空格编码为一个+并且把它用于建立查询的字符串中。
注意并不需要对一个完整的URL使用这些函数,例如http://www.example.com/hello,因为它们会转义冒号和反斜杠:
http%3A%2F%2Fwww.example.com%2Fhello
应该只编码部分URL(在http://www.example.com/后面的部分),随后再加上协议和域名。
4.5.2.1 RFC 1738编码和解码
要把字符串依照URL约定编码,可以使用rawurlencode( ):
$output = rawurlencode(input);
该函数接收一个字符串并返回对该字符串的拷贝,该拷贝中把非法URL字符按%dd约定编码。
如果你要为一个页面里的链接动态生成超级链接地址,则需要用rawurlencode( )转换它们:
$name = "Programming PHP";
$output = rawurlencode($name);
echo "http://localhost/$output";
http://localhost/Programming%20PHP
函数rawurldecode( )用于解码被编码过的URL字符串:
$encoded = 'Programming%20PHP';
echo rawurldecode($encoded);
Programming PHP
4.5.2.2 查询字符串编码
urlencode( )和urldecode( )函数和它们原始版本(即rawurlencode()和rawurldecode())的不同仅在于它们把空格编码为加号(+),而不是%20。这是用于创建查询字符串(query string)和cookie值的格式,但是因为这些值在通过表单或cookie传送时会自动解码,所以你不需要使用这些函数来处理当前页的查询字符串或cookie。这两个函数对于生成查询字符串是很有用的:
$base_url = 'http://www.google.com/q=';
$query = 'PHP sessions -cookies';
$url = $base_url . urlencode($query);
echo $url;
http://www.google.com/q=PHP+sessions+-cookies
4.5.3 SQL
绝大多数数据库系统都要求将SQL查询字符串进行转义。SQL的转义方法相当简单——在单引号、双引号、空字节和反斜杠前面加上一个反斜杠(\)。addslashes( )函数可添加这些反斜杠,stripslashes( )函数则删除它们:
$string = <<< The_End
"It's never going to work," she cried,
as she hit the backslash (\) key.
The_End;
echo addslashes($string);
\"It\'s never going to work,\" she cried,
as she hit the backslash (\\) key.
echo stripslashes($string);
"It's never going to work," she cried,
as she hit the backslash (\) key.
提示:一些数据库(如SYBASE)用另一个单引号为单引号转义,而不是一个反斜杠。对于这些数据库,可以在php.ini文件中打开magic_quotes_sybase。
4.5.4 C语言字符串编码
C-String Encoding
addcslashes( )函数模仿C编程语言的处理方式,通过在字符前加反斜杠来转义任意字符。除了在表4-4中的字符,ASCII值小于32或大于126的字符将使用它们的八进制值(例如,"\002")进行编码。addcslashes( )和stripcslashes( )函数常常被用于非标准的数据库系统,这些系统对哪些字符需要被转义有自己的要求。
表4-4:可以被addcslashes( ) 和stripcslashes( )识别的单字符转义
|
ASK值 |
编 码 |
|
7 |
\a |
|
8 |
\b |
|
9 |
\t |
|
10 |
\n |
|
11 |
\t |
|
12 |
\f |
|
13 |
\r |
调用addcslashes( )时有两个参数——string是要编码的字符串,charset是要转义的字符:
$escaped = addcslashes(string, charset);
用".."结构来指定要转义字符的范围:
echo addcslashes("hello\tworld\n", "\x00..\x1fz..\xff");
hello\\tworld\\n
如果将'0', 'a', 'b', 'f', 'n', 'r', 't',或'v'指定在要转换的字符范围中,要特别注意它们会被转换成'\0', '\a'等。C和PHP可以识别这些转义序列(如\0在PHP中是预定义序列,表示NULL),可能会引起混乱。
stripcslashes( )接受一个字符串并返回去掉转义后的新字符串。
$string = stripcslashes(escaped);
例如:
$string = stripcslashes('hello\tworld\n');
//此时字符串内容为“hello\tworld\n”







