note 73382 rejected from function.preg-replace by nlopess
| From: | nlopess@php.net | Date: | Fri, 23 Feb 2007 12:31:05 +0000 |
| Subject: | note 73382 rejected from function.preg-replace by nlopess | ||
| References: | 1 | Groups: | php.notes |
| Request: | Send a blank email to php-notes+get-123748@lists.php.net to get a copy of this message | ||
Note Submitter: phpcoder at cyberpimp dot sexventure dot com
----
preg_replace() is NOT binary-safe.
If a match is made to an ASCII NULL character (0x00) or an ASCII double-quote character (0x22), the
backreference will NOT return those characters! Instead, the backreference contains the 2-character
backslash-escaped sequence \0 or \" respectively.
This causes escaped data to be mixed with unescaped data in the resulting replacement string,
destroying the data integrity.
To use preg_replace() for binary data, you MUST use the "e" modifier in the regular
expression, and then call a function on the backreference to unescape the data in these two special
circumstances.
Since it is only 0x00 and 0x22 that are escaped, you can NOT use stripslashes(). Instead, write
your own function, or use a pair of nested str_replace() function calls.
Here's an example of a URL validator using preg_replace() made binary-safe:
<?php
function url_validate($uncertainURL){
return preg_replace('/([\\x00-\\x20"<>`\\x7F-\\xFF])/e',
"'%'.sprintf('%02X',ord(
str_replace('\\\\0',\"\\0\",
str_replace('\\\\\"','\"','\\1')
)
))",
$uncertainURL);
}
?>
Notice the following:
-A match is made for all ASCII control characters, double-quote, the greater-than and less-than
characters, the grave accent, ASCII DEL, and all 8-bit high characters.
-When an ASCII NULL is matched, the outer str_replace() function call unescapes it.
-When a double-quote is matched, the nested str_replace() function call unescapes it.
-All other matched characters are returned in the back-reference as-is, and therefore do not need
unescaping.
-After unescaping the backreference (if necessary), the sprintf() and ord() functions are called to
replace the instance of the matched character in the source string ($uncertainURL) with a
URL-encoded character code.
The sheer number of backslashes looks a little confusing, but remember, we're 2-levels deep in
escaping context: Literal backslashes have to be doubled in the source code first to make them
literals in the regular expression, and then those have to be doubled again if they are to be
literals in the replacement PHP string expression. So every literal backslash has to be represented
with 4 backslashes!