Как проверить, является ли строка допустимым URL
WordPress предоставляет полезную функцию is_email()
, которая проверяет, является ли указанный email адрес действительным. Существует ли аналогичная функция для проверки корректности URL?
Я пробовал использовать is_url()
, но это было лишь желаемое с моей стороны.
Ссылка: http://codex.wordpress.org/Function_Reference/is_email
Используйте нативную PHP функцию Фильтр Валидатор
if (filter_var($url, FILTER_VALIDATE_URL) === FALSE) {
die('Недопустимый URL');
}

Отличная находка и спасибо @shanebp - даже не знал о существовании этого фильтра!

FILTER_VALIDATE_URL выглядит хорошо, но имеет серьёзные проблемы: https://d-mueller.de/blog/why-url-validation-with-filter_var-might-not-be-a-good-idea/

@tobltobs: Это не проблемы, а особенности. Автор жалуется, что валидные URL распознаются как валидные. Это всё равно что жаловаться на PDO, потому что он позволяет выполнять $pdo->query("SELECT pw FROM users WHERE id={$_GET['id']}")
.

Возможно, ты прав, @dotancohen, что технически это валидные URL. Поэтому, возможно, проблема действительно в нашем вопросе. Нам нужны не просто "технически валидные URL", а "безопасные URL". Например, URL, которые помогают предотвратить XSS-атаки или другие злонамеренные действия. Предложение @orionrush позволяет избежать многих таких проблем, в то время как FILTER_VALIDATE_URL
этого не делает.

Я нашёл функцию wp_http_validate_url
очень удобной для проверки, является ли строка валидным URL, во время работы над своим проектом.
Ознакомьтесь с документацией: https://developer.wordpress.org/reference/functions/wp_http_validate_url/
Например:
$val = 'http://somevalidurl.com';
if ( wp_http_validate_url( $val ) ) {
// Это валидный URL;
} else {
// Это НЕ валидный URL;
}
Функция возвращает сам URL, если он валиден, в противном случае — false.

Эта функция звучит отлично, но, кажется, она допускает ошибки при обработке пользовательских данных.
Она посчитала URL localhost
недействительным,
но при этом сочла http://example.com/"><script>alert("xss")</script>
валидным.

Извините, SO не позволяет мне отредактировать комментарий. Я имел в виду, что она считает http://localhost
недействительным.

@thespacecamel Вы можете использовать фильтр http_request_host_is_external
, чтобы разрешить 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 'valid'; } else { echo 'invalid'; }`

Я знаю, что это старая запись, но для тех, кто ее читает, стоит также рассмотреть функции WordPress esc_url()
и esc_url_raw()
. Последняя безопасна для записи в базы данных и т.д., так как не кодирует сущности. esc_url()
кодирует сущности и поэтому хорошо подходит для отображения пользователям.
В исходном коде можно увидеть, что esc_url()
проверяет URL на соответствие белого списка разрешенных протоколов и структуры, тем самым избегая некоторых уязвимостей FILTER_VALIDATE_URL
, упомянутых в ссылке от @tobltobs.

По моему мнению, лучше использовать wp_http_validate_url.
Пример 1:
filter_var( '//website.com', FILTER_VALIDATE_URL )
Возвращает false.
Пример 2:
wp_http_validate_url( '//website.com' )
Возвращает URL.
- Если вы не знаете, использует ли сайт протокол https или http, лучше использовать '//'.
- wp_http_validate_url улучшена разработчиками WordPress (более специфична).
- Вы можете улучшить или изменить wp_http_validate_url с помощью хуков (фильтров и действий). Вы не можете использовать хуки для filter_var.
Ссылка: https://developer.wordpress.org/reference/functions/wp_http_validate_url/
Ссылка: https://www.php.net/manual/en/function.filter-var.php

Я согласен, wp_http_validate_url()
— это более надежный валидатор, который допускает IP-адреса, а также принудительно выполняет дополнительную проверку для локальных URL с помощью фильтра http_request_host_is_external
, который по умолчанию возвращает false в качестве дополнительной меры безопасности

Давайте рассмотрим наши варианты для проверки URL в WordPress, начиная с самых очевидных.
filter_var()
с фильтромFILTER_VALIDATE_URL
в PHP не работает с интернационализированными доменными именами, содержащими символы не из ASCII, такие какhttp://스타벅스코리아.com
. У него также есть другие проблемы, как отмечал Дэвид Мюллер, например, принятиеhttp://example.com/"><script>alert("xss")</script>
за валидный URL, хотя он явно вредоносный.wp_http_validate_url()
в WordPress может справляться лучше, хотя изначально эта функция предназначалась для использования в HTTP API, а не для общей проверки URL. Однако она всё равно не решает две конкретные проблемы, упомянутые ранее.preg_match()
в PHP может работать или нет. Написание регулярных выражений, предугадывающих все возможные сценарии, не всегда является идеальным решением, и добиться универсальной правильности может быть сложно.esc_url_raw()
в WordPress не предназначена для проверки URL, но, кажется, справляется с этой задачей лучше других. Она работает с не-ASCII символами, а также решает другие упомянутые проблемы. Эта функция санирует любую строку для сохранения в базе данных WordPress в качестве URL, удаляя или изменяя символы, которые являются недопустимыми или вредоносными. Таким образом, если санированная версия не совпадает с исходной, можно с уверенностью сказать, что URL невалиден и, что важнее всего, небезопасен.
Вот как можно проверить URL с помощью функции esc_url_raw()
, дополнительно используя strtolower()
для регистронезависимой проверки.
function validateUrl($url) {
if ( strtolower(esc_url_raw($url)) === strtolower($url) ) {
return $url;
} else {
return false;
}
}

Чтобы убедиться, что URL, предоставленный пользователем, является действительным и безопасным для хранения и последующего отображения, я предлагаю:
esc_url_raw($url) === $url
esc_url_raw()
, как упомянул @orionrush выше, санирует URL, удаляя из него всё недопустимое или вредоносное. Таким образом, если строка не содержит ничего недопустимого или вредоносного, значит она в порядке.
Например:
if( esc_url_raw($url) === $url ) {
// URL действителен. Используйте его...
} else {
// URL недействителен или вредоносен. Не используйте его...
}
Я написал более подробную статью на эту тему здесь: https://cmljnelson.wordpress.com/2018/08/31/url-validation-in-wordpress/

is_email()
на самом деле не проверяет, действителен ли email-адрес, а только соответствует ли он спецификации. Email, который я с удовольствием указываю на многих сайтах, проявляющих бесполезный интерес к моему email-адресу — это a@b.com, который соответствует спецификации, но маловероятно, что кто-то им пользуется.
Проверка URL лучше всего осуществляется через пингование. Можно попытаться проверить соответствие спецификации, но теоретически существует очень мало ограничений на то, каким может быть закодированный URL.
