Cómo verificar si una cadena es una URL válida
WordPress proporciona una función útil llamada is_email()
que verifica si una dirección de correo electrónico es válida. ¿Existe una función similar disponible para verificar si una URL es válida?
Intenté usar is_url()
pero eso fue solo un pensamiento optimista de mi parte.

Utiliza la función nativa de php Filtro Validador
if (filter_var($url, FILTER_VALIDATE_URL) === FALSE) {
die('No es una URL válida');
}

¡Buen hallazgo y gracias @shanebp - no sabía que existía ese filtro!

FILTER_VALIDATE_URL parece bueno pero tiene algunos problemas serios: https://d-mueller.de/blog/why-url-validation-with-filter_var-might-not-be-a-good-idea/

@tobltobs: Esos no son problemas, son características. El autor se queja de que URLs válidas son reportadas como válidas. Es como quejarse de que PDO está roto porque permite $pdo->query("SELECT pw FROM users WHERE id={$_GET['id']}")
.

Puede que tengas razón @dotancohen, que esas URLs sean técnicamente válidas. Así que quizás el problema está realmente en nuestra pregunta. No solo queremos "URLs técnicamente válidas", queremos "URLs seguras". Es decir, URLs que ayuden a prevenir ataques XSS u otras malicias. La sugerencia de @orionrush evita varios de esos problemas, mientras que FILTER_VALIDATE_URL
no lo hace.

Encontré wp_http_validate_url
bastante conveniente para verificar si una cadena es una URL válida o no mientras trabajaba en mi proyecto.
Consulta la referencia aquí: https://developer.wordpress.org/reference/functions/wp_http_validate_url/
Por ejemplo:
$val = 'http://somevalidurl.com';
if ( wp_http_validate_url( $val ) ) {
// Es una URL válida;
} else {
// NO es una URL válida;
}
Devuelve la URL misma si es válida, de lo contrario devuelve false.

Esta función suena genial, pero creo que cometió algunos errores con respecto a los datos enviados por el usuario.
Encontró que la URL localhost
no es válida;
pero encontró que http://example.com/"><script>alert("xss")</script>
sí es válida.

lo siento, SO no me permite modificar mi comentario. Quise decir que encuentra que http://localhost
no es válida.

@thespacecamel Puedes usar el filtro http_request_host_is_external
para permitir localhost:
`function allow_some_url( $external, $host, $url ) { return ( $host === 'localhost' ) ? true : $external;
} add_filter( 'http_request_host_is_external', 'allow_some_url', 10, 3 );
if ( wp_http_validate_url( 'http://localhost/wordpress/' ) ) { echo 'válida'; } else { echo 'no válida'; }`

Sé que esta es una publicación antigua, pero para cualquiera que la visite, también vale la pena considerar las funciones de WP esc_url()
y esc_url_raw()
, siendo la última segura para entradas en bases de datos, etc., ya que no codifica entidades. esc_url()
sí codifica entidades y por lo tanto es buena para mostrar a los usuarios.
En el código fuente puedes ver que esc_url()
verifica una lista blanca de protocolos permitidos y su estructura, evitando así algunas de las vulnerabilidades de FILTER_VALIDATE_URL
mencionadas en el enlace compartido por @tobltobs.

En mi opinión es mejor usar wp_http_validate_url.
Ejemplo 1:
filter_var( '//website.com', FILTER_VALIDATE_URL )
Devuelve falso.
Ejemplo 2:
wp_http_validate_url( '//website.com' )
Devuelve la URL.
- Si no sabes si el sitio web usa el protocolo https o http, es mejor usar '//'.
- wp_http_validate_url está mejorado por los desarrolladores de WP (es más específico).
- Puedes mejorar o cambiar wp_http_validate_url usando hooks (filtros y acciones). No puedes usar hooks para filter_var.
Ref: https://developer.wordpress.org/reference/functions/wp_http_validate_url/

Estoy de acuerdo, wp_http_validate_url()
es un validador mejor, permitiendo direcciones IP así como forzando una validación extra para URLs de localhost con el filtro http_request_host_is_external
que por defecto devuelve false como medida de seguridad adicional

Analicemos nuestras opciones para validar URLs en WordPress, comenzando con las más obvias.
filter_var()
con el filtroFILTER_VALIDATE_URL
en PHP no funciona para nombres de dominio internacionalizados que contienen caracteres no ASCII comohttp://스타벅스코리아.com
. También tiene otros problemas, como señala David Müller, al aceptarhttp://example.com/"><script>alert("xss")</script>
como URL válida aunque claramente es maliciosa.wp_http_validate_url()
en WordPress podría hacer un mejor trabajo, aunque fue diseñada específicamente para usarse en la API HTTP y no para la validación general de URLs. Pero aún no resuelve los dos problemas específicos mencionados anteriormente.preg_match()
en PHP podría funcionar o no. Escribir expresiones regulares anticipando todos los escenarios posibles no siempre es la solución más ideal y hacerlo de manera universalmente correcta puede no ser posible en ocasiones.esc_url_raw()
en WordPress no está diseñada para validar URLs, pero parece hacer un mejor trabajo que las demás. Funcionará con caracteres no ASCII y resolverá los otros problemas mencionados. Esta función básicamente sanitiza cualquier cadena para guardarla en la base de datos de WordPress como una URL, eliminando o alterando cualquier carácter que sea inválido o malicioso. Por lo tanto, si la versión sanitizada no es igual a la versión original, se puede decir con bastante confianza que la URL no es válida y, lo más importante, no es segura.
Aquí se muestra cómo se puede realizar la verificación de URL con la función esc_url_raw()
, aprovechando también la función strtolower()
para hacer la verificación insensible a mayúsculas y minúsculas.
function validateUrl($url) {
if ( strtolower(esc_url_raw($url)) === strtolower($url) ) {
return $url;
} else {
return false;
}
}

Para asegurar que una URL enviada por el usuario sea válida y segura para almacenar y mostrar posteriormente, sugiero:
esc_url_raw($url) === $url
esc_url_raw()
, como mencionó @orionrush anteriormente, sanitiza la URL eliminando cualquier cosa inválida o maliciosa. Por lo tanto, si la cadena no tiene nada inválido o malicioso, entonces está bien.
Ejemplo:
if( esc_url_raw($url) === $url ) {
// La URL es válida. Úsala...
} else {
// La URL es inválida o maliciosa. No la uses...
}
Escribí un artículo más extenso sobre esto aquí: https://cmljnelson.wordpress.com/2018/08/31/url-validation-in-wordpress/

is_email()
en realidad no verifica si una dirección de correo electrónico es válida, solo si cumple con las especificaciones. El correo que con gusto proporciono para muchos sitios que muestran un interés innecesario en mi dirección de correo es a@b.com, que cumple con las especificaciones pero es poco probable que alguien lo esté usando.
La mejor manera de verificar URLs es haciendo ping a ellas. Puedes intentar verificar el cumplimiento de las especificaciones, pero en teoría hay muy pocas limitaciones sobre lo que puede ser una URL codificada.
