Statement on glibc/iconv Vulnerability

Sequenze di escape

Il carattere backslash (\) ha diversi utilizzi. Primo uso: se viene anteposto a caratteri non alfanumerici, rimuove gli eventuali significati speciali che il carattere può avere. Questo utilizzo di backslash come carattere di escape può essere svolto sia all'interno delle classi di caratteri, sia all'esterno.

Ad esempio, un criterio che deve riconoscere il carattere "*" conterrà "\*". Ciò si applica indipendentemente dal carattere seguente, sia esso interpretabile come meta-carattere o meno. Nel caso in cui un carattere non alfanumerico debba identificare se stesso è opportuno farlo precedere dal "\". In particolare per identificare un backslash occorre scrivere "\\".

Nota:

Le stringhe PHP a singolo o doppio apice hanno un significato speciale del backslash. Quindi, se \ deve essere cercato con un'espressione regolare \\, nel codice PHP deve essere usato "\\\\" oppure '\\\\'.

Se nel criterio di riconoscimento si specifica l'opzione PCRE_EXTENDED, lo spazio bianco (diversamente da quando si trova all'interno di una classe di caratteri), e i caratteri posti tra "#" e un "a capo" all'esterno di una classe di caratteri sono ignorati. Un backslash può essere usato come escape per inserire uno spazio bianco od il carattere "#" come parte del criterio di riconoscimento.

Un secondo utilizzo del backslash consiste nel codificare in modo visibile dei caratteri non visibili. Non ci sono restrizioni nella presenza di caratteri non-stampabili, a parte lo zero binario terminante la stringa dell'espressione regolare. Di seguito saranno elencate le sequenze di caratteri che è preferibile utilizzare per la loro semplicità al posto delle corrispondenti codifiche binarie.

\a
allarme, il carattere BEL (hex 07)
\cx
"control-x", dove x è un qualsiasi carattere
\e
escape (hex 1B)
\f
salto pagina (hex 0C)
\n
"a capo" (newline) (hex 0A)
\p{xx}
un carattere con la proprietà xx, vedere proprietà unicode per maggiori informazioni
\P{xx}
un carattere senza la proprietà xx, vedere proprietà unicode per maggiori informazioni
\r
carriage return (hex 0D)
\t
tabulazione (hex 09)
\xhh
carattere il cui codice esadecimale è hh
\ddd
carattere il cui codice ottale è ddd, oppure riferimento all'indietro

Il preciso effetto di "\cx" è il seguente: se "x" è una lettera minuscola, viene convertita in lettera maiuscola. In pratica viene invertito il sesto bit (hex 40) del carattere. Quindi "\cz" diventa hex 1A, ma "\c{" diventa hex 3B, mentre "\c;" diventa hex 7B.

Dopo la sequenza "\x", saranno letti due numeri esadecimali (per le lettere non si distingue tra maiuscolo e minuscolo). In modalità UTF-8, "\x{...}" è permesso, quando il contenuto delle parentesi graffe è una stringa di cifre esadecimali. È interpretato come un carattere UTF-8 il cui numero di codice è la cifra esadecimale specificata. La sequenza originale esadecimale di escape, \xhh, cerca un carattere UTF-8 a due byte se il valore è maggiore di 127.

Dopo la sequenza "\0" saranno lette due cifre in ottale. In entrambi i casi se vi sono meno di due cifre, saranno usati i numeri presenti. Pertanto la sequenza "\0\x\07" indica 2 zeri binari seguiti dal carattere BEL. Occorre accertarsi di passare le cifre necessarie dopo lo zero iniziale se il carattere che segue può essere scambiato per una cifra in ottale.

Più complicata è la gestione del backslash seguito da una cifra diversa da 0. Al di fuori di una classe di caratteri, PCRE tratta le cifre che trova come numeri decimali. Se il numero è inferiore a 10, oppure vi sono state almeno altrettante parentesi sinistre, la sequenza viene considerata come un riferimento all'indietro. Più avanti, nella parte dei criteri parziali, sarà descritto come funzionano questi riferimenti.

All'interno di una classe di caratteri, oppure nel caso in cui il numero decimale è maggiore di 9 e non ci sono stati altrettanti criteri parziali, PCRE rilegge le prime 3 cifre seguenti il backslash in ottale e genera il carattere dagli 8 bit meno significativi del valore ottenuto. Ogni altra cifra seguente indica se stessa. Ad esempio:

\040
è un'altro modo per indicare uno spazio
\40
ha il medesimo significato dell'esempio precedente che non vi sono 40 sotto-criteri
\7
è sempre un riferimento all'indietro
\11
può essere un riferimento all'indietro o un'altro modo per indicare il carattere di tabulazione
\011
è ancora il carattere di tabulazione
\0113
il carattere di tabulazione seguito da "3"
\113
è il carattere con il codice ottale 113 (poiché non ci possono essere più di 99 riferimenti all'indietro)
\377
è un byte con tutti i bit a 1
\81
può essere un riferimento all'indietro o uno zero binario seguito da "8" e da "1"

Occorre rilevare che valori ottali maggiori di 100 non devono essere preceduti dallo zero, questo perché la libreria considera solo tre cifre.

Tutte le sequenze che definiscono il valore di un singolo byte possono essere utilizzate sia all'interno sia all'esterno delle classe di caratteri. Inoltre, all'interno delle classi di caratteri, la sequenza "\b" viene interpretata come carattere di backspace (hex 08), mentre all'esterno ha un altro significato (come descritto più avanti).

Il terzo utilizzo possibile per il backslash consiste nello specificare il tipo di carattere:

\d
qualsiasi cifra decimale
\D
qualsiasi carattere che non sia una cifra decimale
\h
qualsiasi carattere identificato come spazio bianco orizzontale (da PHP 5.2.4)
\H
qualsiasi carattere che non sia identificato come spazio bianco orizzontale (da PHP 5.2.4)
\s
qualsiasi carattere identificato come spazio bianco
\S
qualsiasi carattere che non sia identificato come spazio bianco
\v
qualsiasi carattere identificato come spazio bianco verticale (da PHP 5.2.4)
\V
qualsiasi carattere che non sia identificato come spazio bianco verticale (da PHP 5.2.4)
\w
qualsiasi carattere che sia una "parola" (word)
\W
qualsiasi carattere che non sia una "parola" (word)

Ciascuna coppia di sequenze di escape suddivide il set completo dei caratteri in due insiemi disgiunti. Un dato carattere deve essere identificato da un solo insieme di ciascuna coppia.

I caratteri definiti "parole" sono quelle lettere o cifre o il carattere underscore (_), cioè qualsiasi carattere che possa essere parte di una "parola" in Perl. In PCRE le definizioni di lettere e cifre vengono gestite tramite le tabelle dei caratteri, che possono variare in base a specifici parametri di localizzazione. Ad esempio, nella localizzazione fr (relativa alla Francia), qualche codice carattere maggiore di 128 è utilizzato per le lettere accentate, e queste sono identificate tramite la sequenza \w.

Queste sequenze di tipi di caratteri possono apparire sia all'interno sia all'esterno delle classi di caratteri. Ciascuna di esse identifica un carattere del tipo appropriato. Se durante la fase di identificazione di un testo, si giunge al termine della stringa in cui si esegue il riconoscimento e si hanno ancora di queste sequenze da incrociare, l'operazione di identificazione fallirà perché, ovviamente, non vi sono più caratteri in cui riconoscere le suddette sequenze.

Il quarto utilizzo per il backslash riguarda la costruzione di particolari asserzioni. L'asserzione è una condizione che deve essere soddisfatta ad un certo punto del riconoscimento, senza "consumare" caratteri dalla stringa oggetto del riconoscimento. Più avanti verranno descritte asserzioni più complicate, costruite tramite l'uso di sotto-criteri di riconoscimento, per ora saranno illustrate delle semplici asserzioni costruite con il backslash:

\b
limite di una parola
\B
non limite di una parola
\A
inizio dell'oggetto di ricerca (a prescindere dalla modalità multi-linea)
\Z
fine dell'oggetto di ricerca oppure newline alla fine (a prescindere dalla modalità multi-linea)
\z
fine dell'oggetto di ricerca (a prescindere dalla modalità multi-linea)
\G
prima posizione trovata nell'oggetto

Queste asserzioni non possono apparire all'interno di una classe di caratteri (attenzione che la sequenza "\b" all'interno di una classe di caratteri indica il carattere backspace).

Viene definito limite di una parola la posizione nella stringa oggetto della ricerca, nella quale il carattere corrente ed il carattere precedente non soddisfano la sequenza \w o la sequenza \W (ad esempio uno soddisfa la sequenza \w e l'altro carattere soddisfa la sequenza \W), oppure quella posizione, all'inizio o alla fine della stringa, nella quale rispettivamente il primo o l'ultimo carattere soddisfa la sequenza \w.

Le asserzioni \A, \Z e \z differiscono dai tradizionali caratteri "^" e "$" (descritti di seguito) per il fatto di identificare sempre l'inizio o la fine della stringa oggetto di ricerca a prescindere da quale opzione sia stata attivata. Infatti queste asserzioni non sono alterate da PCRE_MULTILINE oppure da PCRE_DOLLAR_ENDONLY. La differenza tra \Z e \z consiste nel fatto che \Z identifica sia il carattere precedente il newline posto al termine della stringa sia la fine della stringa, mentre \z identifica solo la fine.

The \G assertion is true only when the current matching position is at the start point of the match, as specified by the offset argument of preg_match(). It differs from \A when the value of offset is non-zero.

\Q and \E can be used to ignore regexp metacharacters in the pattern. For example: \w+\Q.$.\E$ will match one or more word characters, followed by literals .$. and anchored at the end of the string.

\K can be used to reset the match start since PHP 5.2.4. For example, the pattern foo\Kbar matches "foobar", but reports that it has matched "bar". The use of \K does not interfere with the setting of captured substrings. For example, when the pattern (foo)\Kbar matches "foobar", the first substring is still set to "foo".

add a note

User Contributed Notes 6 notes

up
53
mike at eastghost dot com
12 years ago
"line break" is ill-defined:

-- Windows uses CR+LF (\r\n)
-- Linux LF (\n)
-- OSX CR (\r)

Little-known special character:
\R in preg_* matches all three.

preg_match( '/^\R$/', "match\nany\\n\rline\r\nending\r" ); // match any line endings
up
8
Wirek
6 years ago
Significantly updated version (with new $pat4 utilising \R properly, its results and comments):
Note that there are (sometimes difficult to grasp at first glance) nuances of meaning and application of escape sequences like \r, \R and \v - none of them is perfect in all situations, but they are quite useful nevertheless. Some official PCRE control options and their changes come in handy too - unfortunately neither (*ANYCRLF), (*ANY) nor (*CRLF) is documented here on php.net at the moment (although they seem to be available for over 10 years and 5 months now), but they are described on Wikipedia ("Newline/linebreak options" at https://en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions) and official PCRE library site ("Newline convention" at http://www.pcre.org/original/doc/html/pcresyntax.html#SEC17) pretty well. The functionality of \R appears somehow disappointing (with default configuration of compile time option) according to php.net as well as official description ("Newline sequences" at https://www.pcre.org/original/doc/html/pcrepattern.html#newlineseq) when used improperly.
A hint for those of you who are trying to fight off (or work around at least) the problem of matching a pattern correctly at the end ($) of any line in multiple lines mode (/m).
<?php
// Various OS-es have various end line (a.k.a line break) chars:
// - Windows uses CR+LF (\r\n);
// - Linux LF (\n);
// - OSX CR (\r).
// And that's why single dollar meta assertion ($) sometimes fails with multiline modifier (/m) mode - possible bug in PHP 5.3.8 or just a "feature"(?).
$str="ABC ABC\n\n123 123\r\ndef def\rnop nop\r\n890 890\nQRS QRS\r\r~-_ ~-_";
// C 3 p 0 _
$pat1='/\w$/mi'; // This works excellent in JavaScript (Firefox 7.0.1+)
$pat2='/\w\r?$/mi'; // Slightly better
$pat3='/\w\R?$/mi'; // Somehow disappointing according to php.net and pcre.org when used improperly
$pat4='/\w(?=\R)/i'; // Much better with allowed lookahead assertion (just to detect without capture) without multiline (/m) mode; note that with alternative for end of string ((?=\R|$)) it would grab all 7 elements as expected
$pat5='/\w\v?$/mi';
$pat6='/(*ANYCRLF)\w$/mi'; // Excellent but undocumented on php.net at the moment (described on pcre.org and en.wikipedia.org)
$n=preg_match_all($pat1, $str, $m1);
$o=preg_match_all($pat2, $str, $m2);
$p=preg_match_all($pat3, $str, $m3);
$r=preg_match_all($pat4, $str, $m4);
$s=preg_match_all($pat5, $str, $m5);
$t=preg_match_all($pat6, $str, $m6);
echo
$str."\n1 !!! $pat1 ($n): ".print_r($m1[0], true)
.
"\n2 !!! $pat2 ($o): ".print_r($m2[0], true)
.
"\n3 !!! $pat3 ($p): ".print_r($m3[0], true)
.
"\n4 !!! $pat4 ($r): ".print_r($m4[0], true)
.
"\n5 !!! $pat5 ($s): ".print_r($m5[0], true)
.
"\n6 !!! $pat6 ($t): ".print_r($m6[0], true);
// Note the difference among the three very helpful escape sequences in $pat2 (\r), $pat3 and $pat4 (\R), $pat5 (\v) and altered newline option in $pat6 ((*ANYCRLF)) - for some applications at least.

/* The code above results in the following output:
ABC ABC

123 123
def def
nop nop
890 890
QRS QRS

~-_ ~-_
1 !!! /\w$/mi (3): Array
(
[0] => C
[1] => 0
[2] => _
)

2 !!! /\w\r?$/mi (5): Array
(
[0] => C
[1] => 3
[2] => p
[3] => 0
[4] => _
)

3 !!! /\w\R?$/mi (5): Array
(
[0] => C

[1] => 3
[2] => p
[3] => 0
[4] => _
)

4 !!! /\w(?=\R)/i (6): Array
(
[0] => C
[1] => 3
[2] => f
[3] => p
[4] => 0
[5] => S
)

5 !!! /\w\v?$/mi (5): Array
(
[0] => C

[1] => 3
[2] => p
[3] => 0
[4] => _
)

6 !!! /(*ANYCRLF)\w$/mi (7): Array
(
[0] => C
[1] => 3
[2] => f
[3] => p
[4] => 0
[5] => S
[6] => _
)
*/
?>
Unfortunately, I haven't got any access to a server with the latest PHP version - my local PHP is 5.3.8 and my public host's PHP is version 5.2.17.
up
4
Anonymous
4 years ago
A non breaking space is not considered as a space and cannot be caught by \s.

it can be found with :

- [\xc2\xa0] in utf-8
- \x{00a0} in unicode
up
10
grigor at the domain gatchev.info
12 years ago
As \v matches both single char line ends (CR, LF) and double char (CR+LF, LF+CR), it is not a fixed length atom (eg. is not allowed in lookbehind assertions).
up
-1
tharabar at gmail dot com
4 years ago
Required to use \007 instead of \a
up
-4
Wirek
6 years ago
Note that there are (sometimes difficult to grasp at first glance) nuances of meaning and application of escape sequences like \r, \R and \v - none of them is perfect in all situations, but they are quite useful nevertheless. Some official PCRE control options and their changes come in handy too - unfortunately neither (*ANYCRLF), (*ANY) nor (*CRLF) is documented here on php.net at the moment (although they seem to be available for over 10 years and 5 months now), but they are described on Wikipedia ("Newline/linebreak options" at https://en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions) and official PCRE library site ("Newline convention" at http://www.pcre.org/original/doc/html/pcresyntax.html#SEC17) pretty well. The functionality of \R appears somehow disappointing (with default configuration of compile time option) according to php.net as well as official description ("Newline sequences" at https://www.pcre.org/original/doc/html/pcrepattern.html#newlineseq).

A hint for those of you who are trying to fight off (or work around at least) the problem of matching a pattern correctly at the end ($) of any line in multiple lines mode (/m).
<?php
// Various OS-es have various end line (a.k.a line break) chars:
// - Windows uses CR+LF (\r\n);
// - Linux LF (\n);
// - OSX CR (\r).
// And that's why single dollar meta assertion ($) sometimes fails with multiline modifier (/m) mode - possible bug in PHP 5.3.8 or just a "feature"(?).
$str="ABC ABC\n\n123 123\r\ndef def\rnop nop\r\n890 890\nQRS QRS\r\r~-_ ~-_";
// C 3 p 0 _
$pat1='/\w$/mi'; // This works excellent in JavaScript (Firefox 7.0.1+)
$pat2='/\w\r?$/mi';
$pat3='/\w\R?$/mi'; // Somehow disappointing according to php.net and pcre.org
$pat4='/\w\v?$/mi';
$pat5='/(*ANYCRLF)\w$/mi'; // Excellent but undocumented on php.net at the moment
$n=preg_match_all($pat1, $str, $m1);
$o=preg_match_all($pat2, $str, $m2);
$p=preg_match_all($pat3, $str, $m3);
$r=preg_match_all($pat4, $str, $m4);
$s=preg_match_all($pat5, $str, $m5);
echo
$str."\n1 !!! $pat1 ($n): ".print_r($m1[0], true)
.
"\n2 !!! $pat2 ($o): ".print_r($m2[0], true)
.
"\n3 !!! $pat3 ($p): ".print_r($m3[0], true)
.
"\n4 !!! $pat4 ($r): ".print_r($m4[0], true)
.
"\n5 !!! $pat5 ($s): ".print_r($m5[0], true);
// Note the difference among the three very helpful escape sequences in $pat2 (\r), $pat3 (\R), $pat4 (\v) and altered newline option in $pat5 ((*ANYCRLF)) - for some applications at least.

/* The code above results in the following output:
ABC ABC

123 123
def def
nop nop
890 890
QRS QRS

~-_ ~-_
1 !!! /\w$/mi (3): Array
(
[0] => C
[1] => 0
[2] => _
)

2 !!! /\w\r?$/mi (5): Array
(
[0] => C
[1] => 3
[2] => p
[3] => 0
[4] => _
)

3 !!! /\w\R?$/mi (5): Array
(
[0] => C

[1] => 3
[2] => p
[3] => 0
[4] => _
)

4 !!! /\w\v?$/mi (5): Array
(
[0] => C

[1] => 3
[2] => p
[3] => 0
[4] => _
)

5 !!! /(*ANYCRLF)\w$/mi (7): Array
(
[0] => C
[1] => 3
[2] => f
[3] => p
[4] => 0
[5] => S
[6] => _
)
*/
?>
Unfortunately, I haven't got any access to a server with the latest PHP version - my local PHP is 5.3.8 and my public host's PHP is version 5.2.17.
To Top