The manual page for the PHP addcslashes() function gives the following example:
addcslashes($not_escaped, "\0..\37!#\177..\377");
to escape all ASCII characters between 0 and 31 (= 037 octal). A user suggests the following improvement:
addcslashes($not_escaped, "\0..\37!#\#\177..\377");
to "protect original, innocent backslashes from stripcslashes".
Is there any documentation for the format of the charlist parameter? Specifically, what is the interpretation of the !# sequence in the first example, and the !#\# sequence in the second?
It took me some time to find the obvious.
!# is no special sequence, that are single characters which should be escaped.
The only special input for addcslashes is char..char for a range.
\0..\37!#\177..\377 escapes the range 0..\37, the character !, the character # and the range \177..\377
The suggestion with !#\# is invalid (not clean) in my opinion.
\# is not masked in php (there is no special meaning behind it like \n) and it will be the same. So \ and # (for a second time) are added to the character list.
No magic and no special sequence behind this.
The clean solution when you want to escape all non printable characters (0-37 and 177+), the #, !, \ is:
"\0..\37!#\\\177..\377"
Related
<?php
$a='/\\\/';
$b='/\\\\/';
var_dump($a);//string '/\\/' (length=4)
var_dump($b);//string '/\\/' (length=4)
var_dump($a===$b);//boolean true
?>
Why is the string with 3 backslashes equal to the string with 4 backslashes in PHP?
And can we use the 3-backslash version in regular expression?
The PHP reference says we must use 4 backslashes.
Note:
Single and double quoted PHP strings have special meaning of backslash. Thus if \ has to be matched with a regular expression \\, then "\\\\" or '\\\\' must be used in PHP code.
$b='/\\\\/';
php parses the string literal (more or less) character by character. The first input symbol is the forward slash. The result is a forward slash in the result (of the parsing step) and the input symbol (one character, the /) is taken away from the input.
The next input symbol is a backslash. It's taken from the input and the next character/symbol is inspected. It's also a backslash. That's a valid combination, so the second symbol is also taken from the input and the result is a single blackslash (for both input symbols).
The same with the third and fourth backslash.
The last input symbol (within the literal) is the forwardslash -> forwardslash in the result.
-> /\\/
Now for the string with three backslashes:
$a='/\\\/';
php "finds" the first blackslash, the next character is a blackslash - that's a valid combination resulting in one single blackslash in the result and both characters in the input literal taken.
php then "finds" the third blackslash, the next character is a forward-slash, this is not a valid combination. So the result is a single blackslash (because php loves and forgives you....) and only one character taken from the input.
The next input character is the forward-slash, resulting in a forwardslash in the result.
-> /\\/
=> both literals encode the same string.
It is explained in the documentation on the page about Strings:
Under the Single quoted section it says:
The simplest way to specify a string is to enclose it in single quotes (the character ').
To specify a literal single quote, escape it with a backslash (\). To specify a literal backslash, double it (\\). All other instances of backslash will be treated as a literal backslash.
Let's try to interpret your strings:
$a='/\\\/';
The forward slashes (/) have no special meaning in PHP strings, they represent themselves.
The first backslash (\) escapes the second backslash, as explained in the first sentence from the second paragraph quoted above.
The third backslash stands for itself, as explained in the last sentence of the above quote, because it is not followed by an apostrophe (') or a backslash (\).
As a result, the variable $a contains this string: /\\/.
On
$b='/\\\\/';
there are two backslashes (the second and the fourth) that are escaped by the first and the third backslash. The final (runtime) string is the same as for $a: /\\/.
Note
The discussion above is about the encoding of strings in PHP source. As you can see, there always is more than one (correct) way to encode the same string. Other options (beside string literals enclosed in single or double quotes, using heredoc or nowdoc syntax) is to use constants (for literal backslashes, for example) and build the strings from pieces.
For example:
define('BS', '\'); // can also use '\\', the result is the same
$c = '/'.BS.BS.'/';
uses no escaping and a single backslash. The constant BS contains a literal backslash and it is used everywhere a backslash is needed for its intrinsic value. Where a backslash is needed for escaping then a real backslash is used (there is no way to use BS for that).
The escaping in regex is a different thing. First, the regex is parsed at the runtime and at runtime $a, $b and $c above contain /\\/, no matter how they were generated.
Then, in regex a backslash that is not followed by a special character is ignored (see the difference above, in PHP it is interpreted as a literal backslash).
Combining PHP & regex
There are endless possibilities to make the things complicate. Let's try to keep them simple and put some guidelines for regex in PHP:
enclose the regex string in apostrophes ('), if it's possible; this way there are only two characters that needs to be escaped for PHP: the apostrophe and the backslash;
when parse URLs, paths or other strings that can contain forward slashes (/) use #, ~, ! or # as regex delimiter (which one is not used in the regex itself); this way there is no need to escape the delimiter when it is used inside the regex;
don't escape in regex characters when it's not needed; f.e., the dash (-) has a special meaning only when it is used in character classes; outside them it's useless to escape it (and even in character classes it can be used unquoted without having any special meaning if it is placed as the very first or the very last character inside the [...] enclosure);
I have finally started to understand the context behind escaping hexadecimal characters such as \x80. The documentation talks about the escape sequences, but I can also see that some regular expression use double backslashes such as \\x80 - \\xFF.
What's the difference between \\x80 - \\xFF and \x80 - \xFF when using something like preg_replace ?
When using preg_ functions, your string is parsed twice - first, by php compiler, and then by the PCRE engine. So if you have, for example:
preg_match("/\x80/"....)
the compiler turns it into
preg_match("/�/"....) // let � be chr(80)
and passes this to PCRE. When you have two slashes:
preg_match("/\\x80/"....)
the compiler turns the string into
preg_match("/\x80/"....)
and then it's the PCRE engine that converts this to the literal character �.
It doesn't make a difference in this particular case, but consider:
preg_match("/\x5B/"....)
after compilation
preg_match("/[/"....)
and PCRE fails, because of the dangling metacharacter [. Now if you escape the slash
preg_match("/\\x5B/"....)
it's compiled to
preg_match("/\x5B/"....)
which makes PCRE happy, because it understands that [ should be taken literally.
How exactly php compiles your string depends on the quotes you use: double/single/heredocs/nowdocs. See docs for details. A simple rule of thumb is to use single quotes when possible, if you have to use doubles (for variable interpolation), escape everything twice, even if there's technically no need (e.g "\\b$word\\b").
To write hex x80, you use \ and that way you get \x80.
Now in PHP string \ escapes special characters. In string "$var" PHP will try to insert variable $var in that string (because string uses ". To escape $ you write "\$var" and output will be just simple string $var.
Now to write \ in string (no matter if it uses " or ') you use same escaping character \. So it becomes \\ to output \.
If you write "\x80" your output will be "x80" (without \). Than you escape \ with another \ => "\\x80" outputs "\x80".
So to summarize everything:
\x80 is hex character, and when you write it inside string, you write \\x80.
Just some fun:
PHP that outputs js function to alert \x80:
echo "function alertHex(){
alert('\\\\x80 - \\\\xFF');
}";
Why 4 x \? First you escape PHP string to get alert('\\x80 - \\xFF'), that you escape JS string to get \x80 - \xFF.
Same with preg_replace: Allowed symbols: \, $, a-z, [, ]: patern: \\\$[a-z]\[\]; preg_replace('\\\\\$[a-z]\\[\\]', '', $str);
I have a question regarding one character in the preg_match syntax below.
I just want to completely understand.
\w looking for alpha-numberic characters and the underscore.
My question is what does the \ mean after \w and before the # sign?
Does this mean that it will allow:
any alphanumeric
any backslash
any dash
or is this backslash meant to single out the character that follows?
When I test it in w3schools.com example I can have backslashes in the email address which validates but they are removed when they are echoed out.
$email = test_input($_POST["email"]);
// check if e-mail address syntax is valid
if (!preg_match("/([\w\-]+\#[\w\-]+\.[\w\-]+)/",$email))
{
$emailErr = "Invalid email format";
}
The backslash is used to escape characters that have a special meaning in a regex to obtain a literal character. There are twelve characters that must be escaped: [ { ( ) . ? * + | \ ^ $
If I want to write a literal $ in a pattern, I must write \$
Note: you don't need to escape { if the situation is no ambiguous (with the quantifier {m,n} or {m})
Note 2: The delimiter of the pattern must be escaped too, inside and outside a character class.
Inside a character class these twelve characters don't need no more to be escaped since they loose their special meaning and are seen as literals. However, there is three characters that have a special meaning if they are in a special position in the character class. These characters are: ^ - ]
^ at the first position is used to negate a character class ([^M] => all that is not a M ). If you want to use it as a literal character at "the first position", you must write: [\^]
- between two characters defines a character range ([a-z]). This means that you don't need to escape it at the begining (or immediatly after ^) or at the end of the class. You only need to escape it between two characters. - is seen as a literal (and doesn't define a range) in all these examples:
[-abcd]
[^-abcd]
[abcd-]
[ab\-cd]
[\s-abcd] # because \s is not a character
] since it is used to close the character class must be escaped except at the first position or immediatly after the ^. []] and [^]] are correct.
If I write the pattern without uneeded backslashes, I obtain:
/([\w-]+#[\w-]+\.[\w-]+)/
To answer your question ("What does it mean?"): Nothing, uneeded escapes are ignored by the regex engine.
I want to declare the same regex pattern for both languages. For TCL I do this
set pattern "\d\s\S"
but for C++ I have to do this for the same pattern
boost::regex pattern("\\d\\s\\S");
otherwise C++ compiler will tell us the following:
warning C4129: 'd' : unrecognized character escape sequence
so why TCL don't try to find \d \s \S escape symbols and just ignores \-s but C++ tries and sucks?
P.S. PHP works as TCL as I remeber.
This is just how C++ and PHP differ; in PHP, the character following a backslash is matched against a small set of special characters (I believe "rnvtx"). If the match fails it will just continue without altering the meaning.
However, C++ expects the character to be in that small set (I think the set is bigger btw) but if the match fails you will see an error instead.
C++ has the concept of Character Escape Sequences. Escape sequences, which take the form \c (the 'c' being a character), are used to define certain special characters within string literals, so it follows that backslashes by themselves must also be escaped to denote that a special character isn't being implied.
I am trying to validate that the given string contains contains only letters, numbers, spaces, and characters from a set of symbols (!-?():&,;+). Here is what I have so far:
/^[a-zA-Z0-9 !-?\(\):&,;\+]+$/
Now this works somewhat but it accepts other characters as well. For example, strings containing * or # validate. I thought that the ^ at the beginning of the expression and the $ at the end meant that it would match the whole string. What am I doing wrong?
Thanks.
/^[a-zA-Z0-9 !-?\(\):&,;\+]+$/
The - is not nice where you placed it! If you want to place - inside a character class be sure to either place it first or last e.g.
/^[a-zA-Z0-9 !?\(\):&,;\+-]+$/
Otherwise it will take the range of ! until ? whatever this range maybe...Depends on your regex machine.
Finally special characters are not special inside character classes. So no need to escape most of them :
/^[a-zA-Z0-9 !?():&,;+-]+$/
You have specified a "range" within your character class:
[!-?]
Means all ASCII symbols between ! and ?
http://www.regular-expressions.info/charclass.html
You need to escape the minus - with a \ backslash. (OTOH the backslash is redundant before the + and ( and ) within a character class.)