Я искал простое регулярное выражение для URL-адресов, есть ли у кого-нибудь под рукой, что хорошо работает? Я не нашел ни одного с классами проверки фреймворка zend и видел несколько реализаций.






Я использовал это в нескольких проектах, я не думаю, что у меня возникли проблемы, но я уверен, что это не исчерпывающий:
$text = preg_replace(
'#((https?|ftp)://(\S*?\.\S*?))([\s)\[\]{},;"\':<]|\.\s|$)#i',
"'<a href=\"$1\" target=\"_blank\">$3</a>$4'",
$text
);
Большая часть случайного мусора в конце предназначена для ситуаций, подобных http://domain.com. в предложении (чтобы избежать совпадения конечной точки). Я уверен, что это можно было бы очистить, но поскольку это сработало. Я более или менее просто скопировал это из проекта в проект.
Некоторые вещи, которые меня бросают в глаза: использование чередования при вызове классов символов (каждая альтернатива соответствует ровно одному символу); и замена не должна была нуждаться во внешних двойных кавычках (они были нужны только из-за бессмысленного модификатора / e в регулярном выражении).
@John Scipione: google.com - это только допустимый относительный URL-адрес, но не действительный абсолютный URL-адрес. И я думаю, это то, что он ищет.
В данном случае это не работает - он включает завершающие ": 3 cantari noi в альбоме <a href="audio.resursecrestine.ro/cantece/index-autori/andrei-r osu /…>"
@Softy, что-то вроде http://example.com/somedir/..., является совершенно законным URL-адресом, запрашивающим файл с именем ..., который является допустимым именем файла.
Я использую Zend \ Validator \ Regex для проверки URL с использованием вашего шаблона, но он по-прежнему определяет, что http://www.example действителен
Пользуюсь этим успешно - не помню, откуда взял
$pattern = "/\b(?:(?:https?|ftp)://|www\.)[-a-z0-9+&@#/%?=~_|!:,.;]*[-a-z0-9+&@#/%=~_|]/i";
^ (http: // | https: //)? (([a-z0-9]? ([-a-z0-9] * [a-z0-9] +)?) {1,63} \.) + [Az] {2,6} (может быть слишком жадным, пока не уверен, но он более гибкий по протоколу и ведущему www)
Используйте функцию filter_var(), чтобы проверить, является ли строка URL-адресом или нет:
var_dump(filter_var('example.com', FILTER_VALIDATE_URL));
Использование регулярных выражений без необходимости - плохая практика.
РЕДАКТИРОВАТЬ: будьте осторожны, это решение не безопасно для юникода и не безопасно для XSS. Если вам нужна сложная проверка, возможно, лучше поискать где-нибудь еще.
это определенно отличная альтернатива, к сожалению, это php 5.2+ (если вы не установите версию PECL)
В 5.2.13 есть ошибка (и я думаю, что в 5.3.2), которая не позволяет URL-адресам с дефисами проверяться с помощью этого метода.
filter_var отклонит test-site.com, у меня есть доменные имена с дефисами, действительны они или нет. Я не думаю, что filter_var - лучший способ проверить URL-адрес. Это позволит использовать URL-адрес типа http://www.
> Это разрешит URL-адрес типа 'www'. Это нормально, когда URL-адрес типа 'localhost'
Одна конкретная проблема: это проверяет URL-адреса в соответствии с RFC 2396, который не допускает подчеркивания в поддоменах, но некоторые веб-сайты имеют подчеркивания в поддоменах.
Другая проблема этого метода в том, что он небезопасен для юникода.
С тех пор функция filter_var была обновлена, и теперь можно эффективно проверять URL-адреса с включенными дефисами, что делает ваш комментарий неверным, @vamin (см. отчет об ошибке здесь).
@zzatkin, в отчете об ошибке указано, что исправление включено в более поздние версии 5.2.14 и 5.3.3 (оно появилось слишком поздно для 5.2.13 и 5.3.2), хотя я согласен, что это больше не проблема, если вы поддерживаете PHP в актуальном состоянии.
Это также подтвердит onedomain.com <br> http://www.anotherone.com <br> http: /…, которое я узнаю сегодня. Не то, что я имел в виду! Возвращение к альтернативе регулярного выражения (версия PHP => 5.4.4)
Не принимать символы UTF-8. Вернет false для http://wiki.com/öva/mä/åäö.
Filter_var, по-видимому, проверяет все типы форматов URL-адресов независимо от того, действительны они или нет, кажется, что регулярное выражение - это способ правильно проверить URL-адреса
еще одна проблема заключается в том, что он не проверяется на новые TLD, такие как .me, .cm .guru и т. д.
Это плохое решение, за которое не должно быть так много голосов "за". Высокая XSS уязвимость.
Проголосовано против как опасное. Прочтите комментарии об этом в онлайн-руководстве по PHP!
FILTER_VALIDATE_URL содержит много проблем, который необходимо исправить. Кроме того, документы, описывающие флаги не отражает фактический исходный код, где ссылки на некоторые флаги были полностью удалены. Подробнее здесь: news.php.net/php.internals/99018
Еще одна статья Hree, объясняющая проблемы с этим: d-mueller.de/blog/…
это плохое решение, потому что a://site.com действителен для FILTER_VALIDATE_URL (PHP 7.2 и более ранние версии)
это дерьмо метод. это действительно для www
Согласно руководству по PHP - parse_url следует использовать нет для проверки URL.
К сожалению, похоже, что filter_var('example.com', FILTER_VALIDATE_URL) не работает лучше.
И parse_url(), и filter_var() будут передавать неверные URL-адреса, такие как http://....
Поэтому в этом случае - regex является лучший метод.
Этот аргумент не следует. Если FILTER_VALIDATE_URL немного более разрешающий, чем вы хотите, сделайте несколько дополнительных проверок, чтобы справиться с этими крайними случаями. Повторное изобретение колеса с вашей собственной попыткой регулярного выражения для URL-адресов только уведет вас от полной проверки.
См. Все сокращенные регулярные выражения на этой странице, чтобы узнать, почему не нужно писать свои собственные.
Вы справедливо отметили Чалвак. Регулярные выражения для чего-то вроде URL-адресов могут быть (согласно другим ответам) очень трудно исправить. Регулярное выражение - это не всегда ответ. И наоборот, регулярное выражение тоже не всегда является неправильным ответом. Важным моментом является выбор правильного инструмента (регулярного выражения или другого) для работы, а не специального «анти» или «профессионального» регулярного выражения. Оглядываясь назад, ваш ответ об использовании filter_var в сочетании с ограничениями на его крайние случаи выглядит как лучший ответ (особенно когда ответы регулярных выражений начинают достигать более 100 символов или около того, что делает обслуживание указанного регулярного выражения кошмаром)
Редактировать:
Как указал заболеваемость, этот код УСТАРЕЛ с выпуском PHP 5.3.0 (2009-06-30) и должен использоваться соответственно.
Всего два цента, но я разработал эту функцию и уже какое-то время успешно ее использую. Он хорошо документирован и отделен, поэтому вы можете легко его изменить.
// Checks if string is a URL
// @param string $url
// @return bool
function isURL($url = NULL) {
if ($url==NULL) return false;
$protocol = '(http://|https://)';
$allowed = '([a-z0-9]([-a-z0-9]*[a-z0-9]+)?)';
$regex = "^". $protocol . // must include the protocol
'(' . $allowed . '{1,63}\.)+'. // 1 or several sub domains with a max of 63 chars
'[a-z]' . '{2,6}'; // followed by a TLD
if (eregi($regex, $url)==true) return true;
else return false;
}
Eregi будет удален в PHP 6.0.0. И домены с «öäåø» не будут подтверждены вашей функцией. Возможно, вам сначала следует преобразовать URL-адрес в punycode?
@incidence абсолютно согласен. Я написал это в марте, а PHP 5.3 вышел только в конце июня, установив для eregi статус УСТАРЕВШИЙ. Спасибо. Буду редактировать и обновлять.
Поправьте меня, если я ошибаюсь, но можем ли мы все же предположить, что TLD будут иметь минимум 2 символа и максимум 6 символов?
@YzmirRamirez (Все эти годы спустя ...) Если были какие-либо сомнения, когда вы писали свой комментарий, их точно нет сейчас, с такими ДВУ в наши дни, как .photography
@NickRice, вы правы ... насколько Интернет изменился за 5 лет. Теперь я не могу дождаться, пока кто-нибудь сделает TLD .supercalifragilisticexpialidocious
Regex Питера мне не подходит по многим причинам. Он позволяет использовать всевозможные специальные символы в доменном имени и не требует особых проверок.
Функция Фрэнки мне нравится, и вы можете создать хорошее регулярное выражение из компонентов, если вам не нужна функция, например:
^(http://|https://)(([a-z0-9]([-a-z0-9]*[a-z0-9]+)?){1,63}\.)+[a-z]{2,6}
Не проверено, но я думаю, что это должно сработать.
Кроме того, ответ Оуэна тоже не выглядит на 100%. Я взял доменную часть регулярного выражения и протестировал ее на инструменте тестера Regex http://erik.eae.net/playground/regexp/regexp.html.
Ставлю такую строчку:
(\S*?\.\S*?)
в разделе "регулярное выражение" и следующая строка:
-hello.com
в разделе «образец текста».
Результат пропустил минус. Потому что \ S означает любой непробельный символ.
Обратите внимание, что регулярное выражение от Frankie обрабатывает минус, потому что в нем есть эта часть для первого символа:
[a-z0-9]
Что не позволяет использовать минус или какой-либо другой специальный символ.
На всякий случай вы хотите узнать, действительно ли существует URL-адрес:
function url_exist($url){//se passar a URL existe
$c=curl_init();
curl_setopt($c,CURLOPT_URL,$url);
curl_setopt($c,CURLOPT_HEADER,1);//get the header
curl_setopt($c,CURLOPT_NOBODY,1);//and *only* get the header
curl_setopt($c,CURLOPT_RETURNTRANSFER,1);//get the response as a string from curl_exec(), rather than echoing it
curl_setopt($c,CURLOPT_FRESH_CONNECT,1);//don't use a cached version of the url
if (!curl_exec($c)){
//echo $url.' inexists';
return false;
}else{
//echo $url.' exists';
return true;
}
//$httpcode=curl_getinfo($c,CURLINFO_HTTP_CODE);
//return ($httpcode<400);
}
Я бы все равно провел некоторую проверку $url, прежде чем фактически проверять, действительно ли URL-адрес, потому что вышеуказанная операция является дорогостоящей - возможно, до 200 миллисекунд в зависимости от размера файла. В некоторых случаях URL-адрес может фактически не иметь доступного ресурса в своем местоположении (например, создание URL-адреса для изображения, которое еще не было загружено). Кроме того, вы не используете кешированную версию, поэтому это не похоже на file_exists(), который кэширует статистику в файле и почти мгновенно возвращается. Однако предоставленное вами решение по-прежнему полезно. Почему бы просто не использовать fopen($url, 'r')?
Спасибо, именно то, что я искал. Однако я совершил ошибку, пытаясь его использовать. Функция "url_exist", а не "url_exists" ой ;-)
Есть ли угроза безопасности при прямом доступе к URL-адресу, введенному пользователем?
вы хотите добавить проверку, было ли найдено 404: <code> $ httpCode = curl_getinfo ($ c, CURLINFO_HTTP_CODE); // эхо $ url. ''. $ httpCode. '<br>'; if ($ httpCode == 404) {echo $ url. ' 404 '; } </code>
Совершенно небезопасно ... любой входной URL-адрес будет активно доступен.
Согласно Джон Грубер (Дерзкий огненный шар):
Регулярное выражение:
(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))
использование в preg_match ():
preg_match("/(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))/", $url)
Вот расширенный шаблон регулярного выражения (с комментариями):
(?xi)
\b
( # Capture 1: entire matched URL
(?:
https?:// # http or https protocol
| # or
www\d{0,3}[.] # "www.", "www1.", "www2." … "www999."
| # or
[a-z0-9.\-]+[.][a-z]{2,4}/ # looks like domain name followed by a slash
)
(?: # One or more:
[^\s()<>]+ # Run of non-space, non-()<>
| # or
\(([^\s()<>]+|(\([^\s()<>]+\)))*\) # balanced parens, up to 2 levels
)+
(?: # End with:
\(([^\s()<>]+|(\([^\s()<>]+\)))*\) # balanced parens, up to 2 levels
| # or
[^\s`!()\[\]{};:'".,<>?«»“”‘’] # not a space or one of these punct chars
)
)
Для более подробной информации смотрите: http://daringfireball.net/2010/07/improved_regex_for_matching_urls
Для работы шаблон должен экранировать косую черту с обратной косой чертой в трех точках: preg_match ("/ (? I) \ b ((?: Https?: \ / \ / | Www \ d {0,3} [.] | [a-z0-9. \ -] + [.] [az] {2,4} \ /) (?: [^ \ s () <>] + | (([^ \ S () <>] + | (([^ \ s () <>] +)) *)) + (?: (([^ \ S () <>] + | ( ([^ \ S () <>] +) )) *) | [^ \ s`! () 1;] {};: '\ "., <>?« »« ”''])) /", $ Url)
function is_valid_url ($url = "") {
if ($url= = "") {
$url=$this->url;
}
$url = @parse_url($url);
if ( ! $url) {
return false;
}
$url = array_map('trim', $url);
$url['port'] = (!isset($url['port'])) ? 80 : (int)$url['port'];
$path = (isset($url['path'])) ? $url['path'] : '';
if ($path == '') {
$path = '/';
}
$path .= ( isset ( $url['query'] ) ) ? "?$url[query]" : '';
if ( isset ( $url['host'] ) AND $url['host'] != gethostbyname ( $url['host'] ) ) {
if ( PHP_VERSION >= 5 ) {
$headers = get_headers("$url[scheme]://$url[host]:$url[port]$path");
}
else {
$fp = fsockopen($url['host'], $url['port'], $errno, $errstr, 30);
if ( ! $fp ) {
return false;
}
fputs($fp, "HEAD $path HTTP/1.1\r\nHost: $url[host]\r\n\r\n");
$headers = fread ( $fp, 128 );
fclose ( $fp );
}
$headers = ( is_array ( $headers ) ) ? implode ( "\n", $headers ) : $headers;
return ( bool ) preg_match ( '#^HTTP/.*\s+[(200|301|302)]+\s#i', $headers );
}
return false;
}
Привет, это хорошее решение, и я поддержал его, но оно не учитывает стандартный порт для https: - предлагаю вам просто заменить 80 на '', где он работает с портом
В итоге я реализовал вариант этого, потому что мой домен заботится о том, существует ли URL на самом деле или нет :)
Я не думаю, что в данном случае разумно использовать регулярные выражения. Невозможно сопоставить все возможности, и даже если вы это сделали, все равно есть вероятность, что URL-адрес просто не существует.
Вот очень простой способ проверить, действительно ли URL существует и доступен для чтения:
if (preg_match("#^https?://.+#", $link) and @fopen($link,"r")) echo "OK";
(если нет preg_match, это также проверит все имена файлов на вашем сервере)
Я обнаружил, что это наиболее полезно для сопоставления URL-адресов.
^(https?://)?([\da-z\.-]+)\.([a-z\.]{2,6})([/\w \.-]*)*/?$
Будет ли это соответствовать URL-адресам, начинающимся с ftp:?
/^(https?://)?([\da-z\.-pting+)\.([az\.pting{2,6})((/\w \ .-] *) * \ /? $ /
function validateURL($URL) {
$pattern_1 = "/^(http|https|ftp)://(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\d+))?/?/i";
$pattern_2 = "/^(www)((\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\d+))?/?/i";
if (preg_match($pattern_1, $URL) || preg_match($pattern_2, $URL)){
return true;
} else{
return false;
}
}
Не работает со ссылкой вроде: 'www.w3schools.com/home/3/?a=l'
И вот ваш ответ =) Попробуй сломать, не получится !!!
function link_validate_url($text) {
$LINK_DOMAINS = 'aero|arpa|asia|biz|com|cat|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|mobi|local';
$LINK_ICHARS_DOMAIN = (string) html_entity_decode(implode("", array( // @TODO completing letters ...
"æ", // æ
"Æ", // Æ
"À", // À
"à", // à
"Á", // Á
"á", // á
"Â", // Â
"â", // â
"å", // å
"Å", // Å
"ä", // ä
"Ä", // Ä
"Ç", // Ç
"ç", // ç
"Ð", // Ð
"ð", // ð
"È", // È
"è", // è
"É", // É
"é", // é
"Ê", // Ê
"ê", // ê
"Ë", // Ë
"ë", // ë
"Î", // Î
"î", // î
"Ï", // Ï
"ï", // ï
"ø", // ø
"Ø", // Ø
"ö", // ö
"Ö", // Ö
"Ô", // Ô
"ô", // ô
"Õ", // Õ
"õ", // õ
"Œ", // Œ
"œ", // œ
"ü", // ü
"Ü", // Ü
"Ù", // Ù
"ù", // ù
"Û", // Û
"û", // û
"Ÿ", // Ÿ
"ÿ", // ÿ
"Ñ", // Ñ
"ñ", // ñ
"þ", // þ
"Þ", // Þ
"ý", // ý
"Ý", // Ý
"¿", // ¿
)), ENT_QUOTES, 'UTF-8');
$LINK_ICHARS = $LINK_ICHARS_DOMAIN . (string) html_entity_decode(implode("", array(
"ß", // ß
)), ENT_QUOTES, 'UTF-8');
$allowed_protocols = array('http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'mailto', 'irc', 'ssh', 'sftp', 'webcal');
// Starting a parenthesis group with (?: means that it is grouped, but is not captured
$protocol = '((?:'. implode("|", $allowed_protocols) .')://)';
$authentication = "(?:(?:(?:[\w\.\-\+!$&'\(\)*\+,; = " . $LINK_ICHARS . "]|%[0-9a-f]{2})+(?::(?:[\w". $LINK_ICHARS ."\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})*)?)?@)";
$domain = '(?:(?:[a-z0-9' . $LINK_ICHARS_DOMAIN . ']([a-z0-9'. $LINK_ICHARS_DOMAIN . '\-_\[\]])*)(\.(([a-z0-9' . $LINK_ICHARS_DOMAIN . '\-_\[\]])+\.)*('. $LINK_DOMAINS .'|[a-z]{2}))?)';
$ipv4 = '(?:[0-9]{1,3}(\.[0-9]{1,3}){3})';
$ipv6 = '(?:[0-9a-fA-F]{1,4}(\:[0-9a-fA-F]{1,4}){7})';
$port = '(?::([0-9]{1,5}))';
// Pattern specific to external links.
$external_pattern = '/^'. $protocol .'?'. $authentication .'?('. $domain .'|'. $ipv4 .'|'. $ipv6 .' |localhost)'. $port .'?';
// Pattern specific to internal links.
$internal_pattern = "/^(?:[a-z0-9". $LINK_ICHARS ."_\-+\[\]]+)";
$internal_pattern_file = "/^(?:[a-z0-9". $LINK_ICHARS ."_\-+\[\]\.]+)$/i";
$directories = "(?:/[a-z0-9". $LINK_ICHARS ."_\-\.~+%=&,$'#!():;*@\[\]]*)*";
// Yes, four backslashes == a single backslash.
$query = "(?:/?\?([?a-z0-9". $LINK_ICHARS ."+_|\-\.~/\\\\%=&,$'():;*@\[\]{} ]*))";
$anchor = "(?:#[a-z0-9". $LINK_ICHARS ."_\-\.~+%=&,$'():;*@\[\]/\?]*)";
// The rest of the path for a standard URL.
$end = $directories .'?'. $query .'?'. $anchor .'?'.'$/i';
$message_id = '[^@].*@'. $domain;
$newsgroup_name = '(?:[0-9a-z+-]*\.)*[0-9a-z+-]*';
$news_pattern = '/^news:('. $newsgroup_name .'|'. $message_id .')$/i';
$user = '[a-zA-Z0-9'. $LINK_ICHARS .'_\-\.\+\^!#\$%&*+/\=\?\`\|\{\}~\'\[\]]+';
$email_pattern = '/^mailto:'. $user .'@'.'(?:'. $domain .'|'. $ipv4 .'|'. $ipv6 .'|localhost)'. $query .'?$/';
if (strpos($text, '<front>') === 0) {
return false;
}
if (in_array('mailto', $allowed_protocols) && preg_match($email_pattern, $text)) {
return false;
}
if (in_array('news', $allowed_protocols) && preg_match($news_pattern, $text)) {
return false;
}
if (preg_match($internal_pattern . $end, $text)) {
return false;
}
if (preg_match($external_pattern . $end, $text)) {
return false;
}
if (preg_match($internal_pattern_file, $text)) {
return false;
}
return true;
}
Есть намного больше домены верхнего уровня.
Хорошо, это немного сложнее, чем простое регулярное выражение, но оно позволяет использовать разные типы URL-адресов.
Примеры:
Все это должно быть отмечено как действительное.
function is_valid_url($url) {
// First check: is the url just a domain name? (allow a slash at the end)
$_domain_regex = "|^[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(\.[A-Za-z]{2,})/?$|";
if (preg_match($_domain_regex, $url)) {
return true;
}
// Second: Check if it's a url with a scheme and all
$_regex = '#^([a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))$#';
if (preg_match($_regex, $url, $matches)) {
// pull out the domain name, and make sure that the domain is valid.
$_parts = parse_url($url);
if (!in_array($_parts['scheme'], array( 'http', 'https' )))
return false;
// Check the domain using the regex, stops domains like "-example.com" passing through
if (!preg_match($_domain_regex, $_parts['host']))
return false;
// This domain looks pretty valid. Only way to check it now is to download it!
return true;
}
return false;
}
Обратите внимание, что есть проверка in_array для протоколов, которые вы хотите разрешить (в настоящее время в этом списке есть только http и https).
var_dump(is_valid_url('google.com')); // true
var_dump(is_valid_url('google.com/')); // true
var_dump(is_valid_url('http://google.com')); // true
var_dump(is_valid_url('http://google.com/')); // true
var_dump(is_valid_url('https://google.com')); // true
Выдает: ErrorException: неопределенный индекс: схема, если протокол не указан, я предлагаю проверить, установлен ли ранее.
@ user3396065, не могли бы вы предоставить пример ввода, который вызывает это?
Вот как я это сделал. Но я хочу сказать, что я не очень уверен в регулярном выражении. Но это должно работать у тебя :)
$pattern = "#((http|https)://(\S*?\.\S*?))(\s|\;|\)|\]|\[|\{|\}|,|”|\"|'|:|\<|$|\.\s)#i";
$text = preg_replace_callback($pattern,function($m){
return "<a href=\"$m[1]\" target=\"_blank\">$m[1]</a>$m[4]";
},
$text);
Таким образом, вам не понадобится маркер eval на вашем шаблоне.
Надеюсь, это поможет :)
Для этого есть встроенная функция PHP:
$url = 'http://www.yoururl.co.uk/sub1/sub2/?param=1¶m2/';
if ( ! filter_var( $url, FILTER_VALIDATE_URL ) ) {
// Wrong
}
else {
// Valid
}
Возвращает отфильтрованные данные или FALSE, если фильтр не работает.
Этот ответ дублирует один из ответов 2008 года!
Вдохновленный в этом вопросе .NET StackOverflow и в этой упомянутой статье из этого вопроса, есть этот валидатор URI (URI означает, что он проверяет и URL, и URN).
if ( ! preg_match( "/^([a-z][a-z0-9+.-]*):(?:\/\/((?:(?=((?:[a-z0-9-._~!$&'()*+,;=:]|%[0-9A-F]{2})*))(\\3)@)?(?=(\\[[0-9A-F:.]{2,}\\]|(?:[a-z0-9-._~!$&'()*+,;=]|%[0-9A-F]{2})*))\\5(?::(?=(\\d*))\\6)?)(\/(?=((?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*))\\8)?|(\/?(?!\/)(?=((?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*))\\10)?)(?:\\?(?=((?:[a-z0-9-._~!$&'()*+,;=:@\/?]|%[0-9A-F]{2})*))\\11)?(?:#(?=((?:[a-z0-9-._~!$&'()*+,;=:@\/?]|%[0-9A-F]{2})*))\\12)?$/i", $uri ) )
{
throw new \RuntimeException( "URI has not a valid format." );
}
Я успешно протестировал эту функцию внутри ValueObject, который я создал с именем Uri и протестировал UriTest.
<?php
declare( strict_types = 1 );
namespace XaviMontero\ThrasherPortage\Tests\Tour;
use XaviMontero\ThrasherPortage\Tour\Uri;
class UriTest extends \PHPUnit_Framework_TestCase
{
private $sut;
public function testCreationIsOfProperClassWhenUriIsValid()
{
$sut = new Uri( 'http://example.com' );
$this->assertInstanceOf( 'XaviMontero\\ThrasherPortage\\Tour\\Uri', $sut );
}
/**
* @dataProvider urlIsValidProvider
* @dataProvider urnIsValidProvider
*/
public function testGetUriAsStringWhenUriIsValid( string $uri )
{
$sut = new Uri( $uri );
$actual = $sut->getUriAsString();
$this->assertInternalType( 'string', $actual );
$this->assertEquals( $uri, $actual );
}
public function urlIsValidProvider()
{
return
[
[ 'http://example-server' ],
[ 'http://example.com' ],
[ 'http://example.com/' ],
[ 'http://subdomain.example.com/path/?parameter1=value1¶meter2=value2' ],
[ 'random-protocol://example.com' ],
[ 'http://example.com:80' ],
[ 'http://example.com?no-path-separator' ],
[ 'http://example.com/pa%20th/' ],
[ 'ftp://example.org/resource.txt' ],
[ 'file://../../../relative/path/needs/protocol/resource.txt' ],
[ 'http://example.com/#one-fragment' ],
[ 'http://example.edu:8080#one-fragment' ],
];
}
public function urnIsValidProvider()
{
return
[
[ 'urn:isbn:0-486-27557-4' ],
[ 'urn:example:mammal:monotreme:echidna' ],
[ 'urn:mpeg:mpeg7:schema:2001' ],
[ 'urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66' ],
[ 'rare-urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66' ],
[ 'urn:FOO:a123,456' ]
];
}
/**
* @dataProvider urlIsNotValidProvider
* @dataProvider urnIsNotValidProvider
*/
public function testCreationThrowsExceptionWhenUriIsNotValid( string $uri )
{
$this->expectException( 'RuntimeException' );
$this->sut = new Uri( $uri );
}
public function urlIsNotValidProvider()
{
return
[
[ 'only-text' ],
[ 'http//missing.colon.example.com/path/?parameter1=value1¶meter2=value2' ],
[ 'missing.protocol.example.com/path/' ],
[ 'http://example.com\\bad-separator' ],
[ 'http://example.com|bad-separator' ],
[ 'ht tp://example.com' ],
[ 'http://exampl e.com' ],
[ 'http://example.com/pa th/' ],
[ '../../../relative/path/needs/protocol/resource.txt' ],
[ 'http://example.com/#two-fragments#not-allowed' ],
[ 'http://example.edu:portMustBeANumber#one-fragment' ],
];
}
public function urnIsNotValidProvider()
{
return
[
[ 'urn:mpeg:mpeg7:sch ema:2001' ],
[ 'urn|mpeg:mpeg7:schema:2001' ],
[ 'urn?mpeg:mpeg7:schema:2001' ],
[ 'urn%mpeg:mpeg7:schema:2001' ],
[ 'urn#mpeg:mpeg7:schema:2001' ],
];
}
}
<?php
declare( strict_types = 1 );
namespace XaviMontero\ThrasherPortage\Tour;
class Uri
{
/** @var string */
private $uri;
public function __construct( string $uri )
{
$this->assertUriIsCorrect( $uri );
$this->uri = $uri;
}
public function getUriAsString()
{
return $this->uri;
}
private function assertUriIsCorrect( string $uri )
{
// https://stackoverflow.com/questions/30847/regex-to-validate-uris
// http://snipplr.com/view/6889/regular-expressions-for-uri-validationparsing/
if ( ! preg_match( "/^([a-z][a-z0-9+.-]*):(?:\/\/((?:(?=((?:[a-z0-9-._~!$&'()*+,;=:]|%[0-9A-F]{2})*))(\\3)@)?(?=(\\[[0-9A-F:.]{2,}\\]|(?:[a-z0-9-._~!$&'()*+,;=]|%[0-9A-F]{2})*))\\5(?::(?=(\\d*))\\6)?)(\/(?=((?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*))\\8)?|(\/?(?!\/)(?=((?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*))\\10)?)(?:\\?(?=((?:[a-z0-9-._~!$&'()*+,;=:@\/?]|%[0-9A-F]{2})*))\\11)?(?:#(?=((?:[a-z0-9-._~!$&'()*+,;=:@\/?]|%[0-9A-F]{2})*))\\12)?$/i", $uri ) )
{
throw new \RuntimeException( "URI has not a valid format." );
}
}
}
В 46 тестах 65 утверждений. Осторожность: есть 2 поставщика данных для действительных и еще 2 для недопустимых выражений. Один предназначен для URL-адресов, а другой - для URN. Если вы используете версию PhpUnit v5.6 * или более раннюю, вам необходимо объединить два поставщика данных в одного.
xavi@bromo:~/custom_www/hello-trip/mutant-migrant$ vendor/bin/phpunit
PHPUnit 5.7.3 by Sebastian Bergmann and contributors.
.............................................. 46 / 46 (100%)
Time: 82 ms, Memory: 4.00MB
OK (46 tests, 65 assertions)
В этом примере средства проверки URI покрытие кода составляет 100%.
Вот простой класс для Проверка URL, использующий RegEx, а затем перекрестные ссылки домена на популярные серверы RBL (Realtime Blackhole Lists):
Установить:
require 'URLValidation.php';
Использование:
require 'URLValidation.php';
$urlVal = new UrlValidation(); //Create Object Instance
Добавьте URL-адрес в качестве параметра метода domain() и проверьте результат.
$urlArray = ['http://www.bokranzr.com/test.php?test=foo&test=dfdf', 'https://en-gb.facebook.com', 'https://www.google.com'];
foreach ($urlArray as $k=>$v) {
echo var_dump($urlVal->domain($v)) . ' URL: ' . $v . '<br>';
}
Выход:
bool(false) URL: http://www.bokranzr.com/test.php?test=foo&test=dfdf
bool(true) URL: https://en-gb.facebook.com
bool(true) URL: https://www.google.com
Как вы можете видеть выше, www.bokranzr.com указан как вредоносный веб-сайт через RBL, поэтому домен был возвращен как ложный.
"/(http(s?)://)([a-z0-9\-]+\.)+[a-z]{2,4}(\.[a-z]{2,4})*(/[^ ]+)*/i"
(http (s?): //) означает http: // или https: //
([a-z0-9 -] +.) + => 2.0 [a-z0-9-] означает любой символ a-z или любой знак 0-9 или (-))
2.1 (+) means the character can be one or more ex: a1w,
a9-,c559s, f)
2.2 \. is (.)sign
2.3. the (+) sign after ([a-z0-9\-]+\.) mean do 2.1,2.2,2.3
at least 1 time
ex: abc.defgh0.ig, aa.b.ced.f.gh. also in case www.yyy.com
3.[a-z]{2,4} mean a-z at least 2 character but not more than
4 characters for check that there will not be
the case
ex: https://www.google.co.kr.asdsdagfsdfsf
4.(\.[a-z]{2,4})*(/[^ ]+)* mean
4.1 \.[a-z]{2,4} means like number 3 but start with
(.)sign
4.2 * means (\.[a-z]{2,4})can be use or not use never mind
4.3 / means \
4.4 [^ ] means any character except blank
4.5 (+) means do 4.3,4.4,4.5 at least 1 times
4.6 (*) after (/[^ ]+) mean use 4.3 - 4.5 or not use
no problem
use for case https://stackoverflow.com/posts/51441301/edit
5. when you use regex write in "/ /" so it come
"/(http(s?)://)([a-z0-9- visible+.)+[a-z provided{2,4}(.[a-z provided{2,4})(/ [^] +)/i"
6. almost forgot: letter i on the back mean ignore case of
Big letter or small letter ex: A same as a, SoRRy same
as sorry.
Примечание: извините за плохой английский. Моя страна не очень хорошо этим пользуется.
Вы заметили, сколько лет этому вопросу? Пожалуйста, объясните свое регулярное выражение, пользователям, которые еще не знают, будет трудно понять его без подробностей.
Для всех, кто разрабатывает на WordPress, просто используйте
esc_url_raw($url) === $url
для проверки URL (вот документация WordPress по esc_url_raw). Он обрабатывает URL-адреса намного лучше, чем filter_var($url, FILTER_VALIDATE_URL), потому что он является unicode и XSS-безопасен. (Вот хорошая статья, в которой упоминаются все проблемы с filter_var.).
Лучшее URL Regex, которое сработало для меня:
function valid_URL($url){
return preg_match('%^(?:(?:https?|ftp)://)(?:\S+(?::\S*)?@|\d{1,3}(?:\.\d{1,3}){3}|(?:(?:[a-z\d\x{00a1}-\x{ffff}]+-?)*[a-z\d\x{00a1}-\x{ffff}]+)(?:\.(?:[a-z\d\x{00a1}-\x{ffff}]+-?)*[a-z\d\x{00a1}-\x{ffff}]+)*(?:\.[a-z\x{00a1}-\x{ffff}]{2,6}))(?::\d+)?(?:[^\s]*)?$%iu', $url);
}
Примеры:
valid_URL('https://twitter.com'); // true
valid_URL('http://twitter.com'); // true
valid_URL('http://twitter.co'); // true
valid_URL('http://t.co'); // true
valid_URL('http://twitter.c'); // false
valid_URL('htt://twitter.com'); // false
valid_URL('http://example.com/?a=1&b=2&c=3'); // true
valid_URL('http://127.0.0.1'); // true
valid_URL(''); // false
valid_URL(1); // false
Источник: http://urlregex.com/
Это довольно хороший ресурс. Дает список множества различных паттернов и тестов: mathiasbynens.be/demo/url-regex