Для проверки пути URL из пользовательского ввода, я использую функцию PHP filter_var.
Вход содержит только путь (/path/path/script.php).
При проверке пути я добавляю хост. Я немного поиграюсь, проверяю правильность ввода и т. Д. При этом я замечаю странное (??) поведение функции фильтра URL.
Код:
$url = "http://www.domain.nl/http://www.google.nl/modules/authorize/test/normal.php";
var_dump(filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_HOST_REQUIRED)); //valid
Может кто-нибудь объяснить, почему это действительный URL? Спасибо!
Краткий ответ: PHP FILTER_VALIDATE_URL проверяет URL только по RFC 2396, и ваш URL, хотя и странный, действителен в соответствии с указанным стандартом.
Длинный ответ:
Используемый вами фильтр объявлен совместимым с RFC, поэтому давайте проверим этот стандарт (RFC 2396).
Регулярное выражение, используемое для анализа URL-адреса и перечисленное там:
^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
12 3 4 5 6 7 8 9
Куда:
scheme = $2
authority = $4
path = $5
query = $7
fragment = $9
Как мы видим, символ «:» зарезервирован только в контексте схемы, и с этого момента «:» является честной игрой (это подтверждается текстом стандарта). Например, он свободно используется в схеме http: для обозначения порта. Косая черта также может появиться в любом месте, и ничто не запрещает URL иметь «//» где-то посередине. Так что «http: //» в середине должно быть допустимым.
Давайте посмотрим на ваш URL и попробуем сопоставить его с этим регулярным выражением:
$url = "http://www.domain.nl/http://www.google.nl/modules/authorize/test/normal.php";
//Escaped a couple slashes to make things work, still the same regexp
$result_rfc = preg_match('/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/',$url);
echo '<p>'.$result_rfc.'</p>';
Тест возвращает «1», поэтому этот URL-адрес действителен. Этого и следовало ожидать, так как правила не объявляют недействительными, как мы видели, URL-адреса, имеющие в середине что-то вроде http: //. PHP просто отражает это поведение с помощью FILTER_VALIDATE_URL.
Если вы хотите более строгий тест, вам нужно будет написать необходимый код самостоятельно. Например, вы можете предотвратить появление «: //» более одного раза:
$url = "http://www.domain.nl/http://www.google.nl/modules/authorize/test/normal.php";
$result_rfc = preg_match('/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/',$url);
if (substr_count($url,'://') != 1) {
$result_non_rfc = false;
} else {
$result_non_rfc = $result_rfc;
}
Вы также можете попробовать настроить само регулярное выражение.
Других решений пока нет …