SunshinePHP Developer Conference 2015

Modificadores de Patrón

Los modificadores PCRE disponibles son listados a continuación. Los nombres entre paréntesis se refieren a nombres internos de PCRE para dichos modificadores. Los espacios y nuevas líneas son ignorados en los modificadores, otros caracteres generan error.

i (PCRE_CASELESS)
Si se aplica este modificador, las letras en el patrón coincidirán tanto con letras mayúsculas como minúsculas.
m (PCRE_MULTILINE)
Por defecto, PCRE trata la cadena objetivo como si fuera una única "línea" de caracteres (incluso si en realidad contiene varias nuevas líneas). El meta-carácter "inicio de línea" (^) coincide sólo con el inicio de la cadena, mientras que el meta-carácter "final de línea" ($) coincide sólo con el final de la cadena, o antes del final de una nueva línea (a menos que el modificador D se aplique). Esto es igual que en Perl. Cuando se aplica este modificador, los constructores "inicio de línea" y "final de línea" coinciden inmediatamente después o inmediatamente antes que cualquier nueva línea de la cadena objetivo, respectivamente, así como al inicio y final absolutos. Esto es equivalente al modificador /m de Perl. Si no hay caracteres "\n" en una cadena objetivo, o no hay incidencias de ^ o $ en el patrón, la aplicación de este modificador no tiene efecto.
s (PCRE_DOTALL)
Si se aplica este modificador, un meta-carácter punto en el patrón coincide con todos los caracteres, incluyendo nuevas líneas. Sin él, las nuevas líneas son excluidas. Este modificador es equivalente al modificador /s de Perl. Una clase negativa como [^a] siempre coincidirá con un carácter de nueva línea, independientemente de la aplicación de este modificador.
x (PCRE_EXTENDED)
Si se aplica este modificador, los caracteres de información de espacios en blanco en el patrón se ignoran totalmente excepto cuando están escapados o dentro de una clase carácter, y los caracteres entre un # sin escapar fuera de una clase carácter y el siguiente carácter nueva línea, inclusive, también son ignorados. Esto es equivalente al modificador /x de Perl, y hace posible incluir comentarios dentro de patrones complicados. Observe, sin embargo, que esto se aplica sólo a caracteres de información. Los caracteres espacio en blanco nunca pueden aparecer dentro de secuencias de caracteres especiales en un patrón, por ejemplo dentro de la secuencia (?( la cual inicia un sub-patrón condicional.
e (PREG_REPLACE_EVAL)
Advertencia

Esta característica ha sido declarada OBSOLETA desde PHP 5.5.0. Su uso está totalmente desaconsejado.

Si se aplica este modificador obsoleto, preg_replace() realiza las sustituciones normales de retro-referencias en la cadena a sustituir, la evalúa como código PHP, y usa el resultado para sustituir la cadena de búsqueda. Las comillas simples, comillas dobles, barras invertidas (\) y caracteres NULL serán escapados con barras invertidas en las retro-referencias sustituidas.
Precaución

La función addslashes() se ejecuta en cada retroreferencia que coincida antes de que se realice la sustitución. Por lo tanto, cuando la retroreferencia se usa como una cadena entrecomillada, los caracteres escapados serán convertidos a literales. to literals. Sin embargo, los caracteres que son escapados, los cuales normalmente no serían convertidos, mantendrán sus barras. Esto hace que el uso de este modificador sea muy complicado.

Precaución

Asegúrese de que replacement constituye una cadena de código PHP válida; de otro modo PHP responderá con un error de análisis en la línea que contiene preg_replace().

Precaución

El uso de este modificador está desaconsejado, ya que puede introducir fácilmente vulnerabilidades de seguridad:

<?php
$html 
$_POST['html'];

// cabeceras en mayúsculas
$html preg_replace(
    
'(<h([1-6])>(.*?)</h\1>)e',
    
'"<h$1>" . strtoupper("$2") . "</h$1>"',
    
$html
);

En el código de ejemplo de arriba puede ser explotado fácilmente pasando una cadena de texto como <h1>{${eval($_GET[php_code])}}</h1>. Esto proporciona al atacante la capacidad de ejecutar código de PHP arbitrario y tener acceso casi completo al servidor.

Para evitar este tipo de vulnerabilidad de ejecución de código remoto, se debería usar la función preg_replace_callback() en su lugar:

<?php
$html 
$_POST['html'];

// cabeceras en mayúsculas
$html preg_replace_callback(
    
'(<h([1-6])>(.*?)</h\1>)',
    function (
$m) {
        return 
"<h$m[1]>" strtoupper($m[2]) . "</h$m[1]>";
    },
    
$html
);

Nota:

Sólamente preg_replace() utiliza este modificador; es ingnorado por otras funciones PCRE.

A (PCRE_ANCHORED)
Si se aplica este modificador, el patrón es forzado a ser "anclado", es decir, se le obliga a coincidir sólo con el inicio de la cadena que está siendo buscada (la "cadena objetivo"). Este efecto también se puede lograr mediante construcciones apropiadas en el patrón mismo, lo cual es la única manera de hacerlo en Perl.
D (PCRE_DOLLAR_ENDONLY)
Si se aplica este modificador, un meta-carácter dólar en el patrón coincidirá sólo con el final de la cadena objetivo. Sin este modificador, un dólar coincide también inmediatamente antes del carácter final si éste es una nueva línea (pero no antes de cualquier otra nueva línea). Este modificador es ignorado si el modificadr m se aplica. No existe equivalente a este modificador en Perl.
S
Cuando un patrón se va a usar varias veces, merece la pena dedicar más tiempo a analizarlo a fin de acelerar el tiempo tomado para las comparaciones. Si se aplica este modificador, se realiza este análisis extra. Actualmente, estudiar un patrón es útil sólamente para patrones no anclados que no tienen un carácter de inicio único fijo.
U (PCRE_UNGREEDY)
Este modificador invierte la "codicia" de los cuantificadores de modo que no sean codiciosos por defecto, pero se vuelven codiciosos si son seguidos por ?. Esto no es compatible con Perl. También se puede aplicar por un modificador de ajuste dentro del patrón (?U) o por un signo de interrogación detrás del cuantificador (p.ej. .*?).

Nota:

Normalmente no es posible hacer coincidir más de pcre.backtrack_limit caracteres en el modo no codicioso.

X (PCRE_EXTRA)
Este modificador pone en marcha funcionalidad adicional de PCRE que es incompatible con Perl. Cualquier barra invertida en un patrón que esté seguida por una letra que no tenga un significado especial causa un error, por lo que se reservan estas combinaciones para futuras expansiones. Por defecto, como en Perl, una barra invertida seguida de una letra que no tenga un significado especial se trata como un literal. No hay en la actualidad otras características controladas por este modificador.
J (PCRE_INFO_JCHANGED)
El ajuste de opción interna (?J) cambia la opción local PCRE_DUPNAMES. Permite nombres duplicados para sub-patrones.
u (PCRE_UTF8)
Este modificador pone en marcha funcionalidad adicional de PCRE que es incompatible con Perl. Los string de patrones y objetivos son tratados como UTF-8. Este modificador está disponible a partir de PHP 4.1.0 o posterior en Unix y desde PHP 4.2.3 en win32. La validez de UTF-8 del patrón y del objetivo es verificada desde PHP 4.3.5. Un objetivo inválido causará que la función preg_* no haga coincidir nada; un patrón inválido desencadenará un error de nivel E_WARNING. Las secuencias UTF-8 de cinco o seis octetos se consideran como no válidas desde PHP 5.3.4 (resp. PCRE 7.3 2007-08-28); anteriormente se consideraban como UTF-8 válido.

add a note add a note

User Contributed Notes 6 notes

up
9
hfuecks at nospam dot org
9 years ago
Regarding the validity of a UTF-8 string when using the /u pattern modifier, some things to be aware of;

1. If the pattern itself contains an invalid UTF-8 character, you get an error (as mentioned in the docs above - "UTF-8 validity of the pattern is checked since PHP 4.3.5"

2. When the subject string contains invalid UTF-8 sequences / codepoints, it basically result in a "quiet death" for the preg_* functions, where nothing is matched but without indication that the string is invalid UTF-8

3. PCRE regards five and six octet UTF-8 character sequences as valid (both in patterns and the subject string) but these are not supported in Unicode ( see section 5.9 "Character Encoding" of the "Secure Programming for Linux and Unix HOWTO" - can be found at http://www.tldp.org/ and other places )

4. For an example algorithm in PHP which tests the validity of a UTF-8 string (and discards five / six octet sequences) head to: http://hsivonen.iki.fi/php-utf8/

The following script should give you an idea of what works and what doesn't;

<?php
$examples
= array(
   
'Valid ASCII' => "a",
   
'Valid 2 Octet Sequence' => "\xc3\xb1",
   
'Invalid 2 Octet Sequence' => "\xc3\x28",
   
'Invalid Sequence Identifier' => "\xa0\xa1",
   
'Valid 3 Octet Sequence' => "\xe2\x82\xa1",
   
'Invalid 3 Octet Sequence (in 2nd Octet)' => "\xe2\x28\xa1",
   
'Invalid 3 Octet Sequence (in 3rd Octet)' => "\xe2\x82\x28",

   
'Valid 4 Octet Sequence' => "\xf0\x90\x8c\xbc",
   
'Invalid 4 Octet Sequence (in 2nd Octet)' => "\xf0\x28\x8c\xbc",
   
'Invalid 4 Octet Sequence (in 3rd Octet)' => "\xf0\x90\x28\xbc",
   
'Invalid 4 Octet Sequence (in 4th Octet)' => "\xf0\x28\x8c\x28",
   
'Valid 5 Octet Sequence (but not Unicode!)' => "\xf8\xa1\xa1\xa1\xa1",
   
'Valid 6 Octet Sequence (but not Unicode!)' => "\xfc\xa1\xa1\xa1\xa1\xa1",
);

echo
"++Invalid UTF-8 in pattern\n";
foreach (
$examples as $name => $str ) {
    echo
"$name\n";
   
preg_match("/".$str."/u",'Testing');
}

echo
"++ preg_match() examples\n";
foreach (
$examples as $name => $str ) {
   
   
preg_match("/\xf8\xa1\xa1\xa1\xa1/u", $str, $ar);
    echo
"$name: ";

    if (
count($ar) == 0 ) {
        echo
"Matched nothing!\n";
    } else {
        echo
"Matched {$ar[0]}\n";
    }
   
}

echo
"++ preg_match_all() examples\n";
foreach (
$examples as $name => $str ) {
   
preg_match_all('/./u', $str, $ar);
    echo
"$name: ";
   
   
$num_utf8_chars = count($ar[0]);
    if (
$num_utf8_chars == 0 ) {
        echo
"Matched nothing!\n";
    } else {
        echo
"Matched $num_utf8_chars character\n";
    }
   
}
?>
up
7
Daniel Klein
2 years ago
If the _subject_ contains utf-8 sequences the 'u' modifier should be set, otherwise a pattern such as /./ could match a utf-8 sequence as two to four individual ASCII characters. It is not a requirement, however, as you may have a need to break apart utf-8 sequences into single bytes. Most of the time, though, if you're working with utf-8 strings you should use the 'u' modifier.

If the subject doesn't contain any utf-8 sequences (i.e. characters in the range 0x00-0x7F only) but the pattern does, as far as I can work out, setting the 'u' modifier would have no effect on the result.
up
4
phpman at crustynet dot org dot uk
3 years ago
The description of the "u" flag is a bit misleading. It suggests that it is only required if the pattern contains UTF-8 characters, when in fact it is required if either the pattern or the subject contain UTF-8. Without it, I was having problems with preg_match_all returning invalid multibyte characters when given a UTF-8 subject string.

It's fairly clear if you read the documentation for libpcre:

       In  order  process  UTF-8 strings, you must build PCRE to include UTF-8
       support in the code, and, in addition,  you  must  call  pcre_compile()
       with  the  PCRE_UTF8  option  flag,  or the pattern must start with the
       sequence (*UTF8). When either of these is the case,  both  the  pattern
       and  any  subject  strings  that  are matched against it are treated as
       UTF-8 strings instead of strings of 1-byte characters.

[from http://www.pcre.org/pcre.txt]
up
2
ebarnard at marathonmultimedia dot com
7 years ago
When adding comments with the /x modifier, don't use the pattern delimiter in the comments. It may not be ignored in the comments area. Example:

<?php
$target
= 'some text';
if(
preg_match('/
                e # Comments here
               /x'
,$target)) {
    print
"Target 1 hit.\n";
}
if(
preg_match('/
                e # /Comments here with slash
               /x'
,$target)) {
    print
"Target 1 hit.\n";
}
?>

prints "Target 1 hit." but then generates a PHP warning message for the second preg_match():

Warning:  preg_match() [function.preg-match]: Unknown modifier 'C' in /ebarnard/x-modifier.php on line 11
up
2
michal dot kocarek at brainbox dot cz
5 years ago
In case you're wondering, what is the meaning of "S" modifier, this paragraph might be useful:

When "S" modifier is set, PHP calls the pcre_study() function from the PCRE API before executing the regexp. Result from the function is passed directly to pcre_exec().

For more information about pcre_study() and "Studying the pattern" check the PCRE manual on http://www.pcre.org/pcre.txt

PS: Note that function names "pcre_study" and "pcre_exec" used here refer to PCRE library functions written in C language and not to any PHP functions.
up
-1
varrah NO_GARBAGE_OR_SPAM AT mail DOT ru
8 years ago
Spent a few days, trying to understand how to create a pattern for Unicode chars, using the hex codes. Finally made it, after reading several manuals, that weren't giving any practical PHP-valid examples. So here's one of them:

For example we would like to search for Japanese-standard circled numbers 1-9 (Unicode codes are 0x2460-0x2468) in order to make it through the hex-codes the following call should be used:
preg_match('/[\x{2460}-\x{2468}]/u', $str);

Here $str is a haystack string
\x{hex} - is an UTF-8 hex char-code
and /u is used for identifying the class as a class of Unicode chars.

Hope, it'll be useful.
To Top