2011-01-17 23 views
16

Hay pregunta por el casi el mismo nombre ya: What is the best regular expression to check if a string is a valid URL¿Cuál es el complicant RFC y trabajando expresión regular para comprobar si una cadena es una URL válida

No entiendo este stackoverflow. Parece que necesito reputación para comentar una respuesta. Como no lo tengo, no sé cómo decirlo/preguntarle que la solución propuesta no parece funcionar. ¿Entonces me veo obligado a hacer una nueva pregunta y pedir la solución de esta manera?

ACTUALIZACIÓN: Parece que Reg Exp admite IPV6 y yo tenía la culpa, ya que el IPv6 es y se supone que debe funcionar como http://[2620:0:1cfe:face:b00c::3]/.

Entonces, el único problema real que sé con eso es que acepta example.org: como URL válida.

¿O tiene PHP la culpa?

/** 
    * Validate URL - RFC 3987 (IRI) 
    * 
    * https://stackoverflow.com/questions/161738/what-is-the-best-regular-expression-to-check-if-a-string-is-a-valid-url 
    * 
    * @param string $str_url 
    * @return boolean 
    */ 
function is_url($str_url) 
{ 
    // RFC 3987 For absolute IRIs (internationalized): 
    return (bool) preg_match('/^[a-z](?:[-a-z0-9\+\.])*:(?:\/\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&\'\(\)\*\+,;=:])*@)?(?:\[(?:(?:(?:[0-9a-f]{1,4}:){6}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|::(?:[0-9a-f]{1,4}:){5}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:[0-9a-f]{1,4}:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+[-a-z0-9\._~!\$&\'\(\)\*\+,;=:]+)\]|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}|(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&\'\(\)\*\+,;[email protected]])*)(?::[0-9]*)?(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&\'\(\)\*\+,;=:@]))*)*|\/(?:(?:(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&\'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&\'\(\)\*\+,;=:@]))*)*)?|(?:(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&\'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&\'\(\)\*\+,;=:@]))*)*|(?!(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&\'\(\)\*\+,;=:@])))(?:\?(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&\'\(\)\*\+,;=:@])|[\x{E000}-\x{F8FF}\x{F0000}-\x{FFFFD}|\x{100000}-\x{10FFFD}\/\?])*)?(?:\#(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&\'\(\)\*\+,;=:@])|[\/\?])*)?$/iu',$str_url); 
} 

Aquí está la prueba de que:

$urls=array('http://www.example.org/','http://www.example.org:80/','example.org','ftp://user:[email protected]/','http://example.org/?cat=5&test=joo','http://www.fi/?cat=5&test=joo','http://[::1]/','http://[2620:0:1cfe:face:b00c::3]/','http://[2620:0:1cfe:face:b00c::3]:80/',''); 
foreach ($urls as $a) 
{ 
    echo $a."\n"; 
    $a=is_url($a); 
    var_dump($a); 
} 

Y eso salidas:

"http://www.example.org/" bool(true) 
"http://www.example.org:80/" bool(true) 
"example.org" bool(false) 
"ftp://user:[email protected]/" bool(true) 
"http://example.org/?cat=5&test=joo" bool(true) 
"http://www.fi/?cat=5&test=joo" bool(true) 
"http://[::1]/" bool(true) 
"http://[2620:0:1cfe:face:b00c::3]/" bool(true) 
"http://[2620:0:1cfe:face:b00c::3]:80/" bool(true) 
"" bool(false) 

Entonces, ¿cuál es el compilicant RFC y la expresión regular de trabajo?

+0

+1 para una pregunta útil, en mi opinión, estás actuando registrado correctamente haciendo una nueva pregunta ya que difieren en el otro (que obviamente es solo para IPv4). Obtendrás más representantes pronto si publicas más aquí en SO, y las barreras de baja reputación son parte de lo que mantiene la calidad alta aquí. ;-) – Lucero

+3

Está buscando URI absolutos, ¿verdad? Porque incluso una cadena vacía es una referencia de URI válida. – Gumbo

+1

Su ejemplo de IPv6 no es correcto, debe ser 'http: // [2620: 0: 1cfe: cara: b00c :: 3]: 80 /' por lo que los analizadores pueden diferenciar entre los delimitadores hexadecimales y opcional: 80 número de puerto. – mario

Respuesta

3

Después de leer el RFC 3986, tengo que decir que estaba equivocado. Esa expresión regular está funcionando plenamente (eso lo sé). El primer error que tuve fue sintaxis de direcciones IPv6, se pusieron alrededor de [], y el segundo fue sobre example.org: (nota doble punto posterior :). Pero como el RFC dice que el esquema puede tener puntos, también es válido.

Así que esa es una forma válida de RFC para hacerlo, pero la gente generalmente (como yo lo haré) tendrá que modificarlo para aceptar solo algunos esquemas.

0

Aquí hay RFC que puedes estudiar: RFC 3986 - Uniform Resource Identifier (URI): Generic Syntax. La sección 3.2.2 Host es lo que estás buscando.

Desafortunadamente función filter_var() construir-en PHP no es compatible con IPv6 sintaxis:

<?php 

var_dump(filter_var('http://[2620:0:1cfe:face:b00c::3]:80/', FILTER_VALIDATE_URL)); 
// Output: boolean false 
+0

Bueno, no estoy buscando una forma de validar url en PHP, pero para reemplazar url's a enlaces href. Ah, pero ese IPv6 se supone que debe estar en [], ayudará. Bueno, entonces ese RegExp funciona con esos, pero falla en esa sintaxis 'example.org:'. – bestis

+0

'example.org' en URL no válida (falta el esquema (por ejemplo,' http: // ')). – Crozin

+0

Acepto, example.org no es válido, tampoco lo es example.org: (tenga en cuenta ese doble punto final). Pero esa expresión regular en la pregunta dice que es válida: example.org bool (falsa) example.org: bool (verdad) – bestis

4

Bueno, si nos fijamos en él, la especificación se divide en "trozos". Así es como sugeriría construir la expresión regular para que sea más fácil de leer, más fácil de mantener y comprensible. Por lo tanto, las partes de la expresión regular son (Opcional están en cursiva):

  1. Esquema
  2. nombre de usuario/contraseña
  3. dominio o dirección IP
  4. Puerto
  5. Ruta
  6. Consulta
  7. Ancla

Entonces, necesitamos construir una subparte regex para cada uno.

  1. Esquema:

    $scheme = "[a-z][a-z0-9+.-]*"; 
    
  2. nombre de usuario/contraseña:

    $username = "([^:@/](:[^:@/])[email protected])?"; 
    
  3. de dominio o dirección IP:

    Ahora, tenemos que construir los 3 anfitriones posibles:

    1. de nombres de dominio
    2. IPv4
    3. IPv6

    de nombres de dominio:

    $segment = "([a-z][a-z0-9-]*?[a-z0-9])"; 
    $domain = "({$segment}\.)*{$segment}"; 
    

    IPv4:

    $segment = "([0|1][0-9]{2}|2([0-4][0-9]|5[0-5]))"; 
    $ipv4 = "({$segment}\.{$segment}\.{$segment}\.{$segment})"; 
    

    IPv6:

    $block = "([a-f0-9]{0,4})"; 
    $rawIpv6 = "({$block}:){2,8}"; 
    $ipv4sub = "(::ffff:{$ipv4})"; 
    $ipv6 = "([({$rawIpv6}|{$ipv4sub})])"; 
    

    Por último:

    $host = "($domain|$ipv4|$ipv6)"; 
    
  4. puerto:

    $port = "(:[\d]{1,5})?"; 
    
  5. Path:

    $path = "([^?;\#]*)?"; 
    
  6. Consulta:

    $query = "(\?[^\#;]*)?"; 
    
  7. Ancla:

    $anchor = "(\#.*)?"; 
    

Y la expresión regular definitiva:

$regex = "#^{$scheme}://{$username}{$host}{$port}(/{$path}{$query}{$anchor}|)$#i"; 

Tenga en cuenta que la / está en la expresión regular, y no a la parte de la ruta desde el camino puede estar vacío.

También tenga en cuenta que no he probado esto. Debería funcionar, pero definitivamente necesita confirmar que cada parte es correcta (en cuanto a qué esperar en la url).

También tenga en cuenta que esta es solo una forma de hacerlo. Puede usar otras herramientas que no necesitan expresiones regulares o una biblioteca o marco que sea más fácil de mantener a largo plazo.

mejor de la suerte

+1

La apariencia rápida parece que fallará en muchas direcciones IPv6. La validación de IPv6 no puede ser tan simple. ¿Qué tal http: // [:: 1]/o http: // [2620: 0: 1cfe: cara: b00c :: 3] /? Como es normal, la dirección IPv6 se escribe más rápido. – bestis

0

Gracias ircmaxell pero tuve que ajustar un poco la expresión regular IPV6 para PHP para compilar con preg_match.

me cambió:

$ipv6 = "([({$rawIpv6}|{$ipv4sub})])"; 

Para:

$ipv6 = "({$rawIpv6}|{$ipv4sub})"; 
Cuestiones relacionadas