Проверка PHP / регулярное выражение для URL

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

Это довольно хороший ресурс. Дает список множества различных паттернов и тестов: mathiasbynens.be/demo/url-regex

omar j 12.11.2014 19:25
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
128
1
172 687
21
Перейти к ответу Данный вопрос помечен как решенный

Ответы 21

Ответ принят как подходящий

Я использовал это в нескольких проектах, я не думаю, что у меня возникли проблемы, но я уверен, что это не исчерпывающий:

$text = preg_replace(
  '#((https?|ftp)://(\S*?\.\S*?))([\s)\[\]{},;"\':<]|\.\s|$)#i',
  "'<a href=\"$1\" target=\"_blank\">$3</a>$4'",
  $text
);

Большая часть случайного мусора в конце предназначена для ситуаций, подобных http://domain.com. в предложении (чтобы избежать совпадения конечной точки). Я уверен, что это можно было бы очистить, но поскольку это сработало. Я более или менее просто скопировал это из проекта в проект.

Некоторые вещи, которые меня бросают в глаза: использование чередования при вызове классов символов (каждая альтернатива соответствует ровно одному символу); и замена не должна была нуждаться во внешних двойных кавычках (они были нужны только из-за бессмысленного модификатора / e в регулярном выражении).

Alan Moore 30.05.2009 09:53

@John Scipione: google.com - это только допустимый относительный URL-адрес, но не действительный абсолютный URL-адрес. И я думаю, это то, что он ищет.

Gumbo 04.01.2010 11:30

В данном случае это не работает - он включает завершающие ": 3 cantari noi в альбоме <a href="audio.resursecrestine.ro/cantece/index-autori/andrei-r‌ osu /…>"

Softy 02.02.2011 12:06

@Softy, что-то вроде http://example.com/somedir/..., является совершенно законным URL-адресом, запрашивающим файл с именем ..., который является допустимым именем файла.

Stephen P 28.07.2011 03:55

Я использую Zend \ Validator \ Regex для проверки URL с использованием вашего шаблона, но он по-прежнему определяет, что http://www.example действителен

Joko Wandiro 26.11.2013 12:03

Пользуюсь этим успешно - не помню, откуда взял

$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)

andrewbadera 26.08.2009 19:54

Используйте функцию filter_var(), чтобы проверить, является ли строка URL-адресом или нет:

var_dump(filter_var('example.com', FILTER_VALIDATE_URL));

Использование регулярных выражений без необходимости - плохая практика.

РЕДАКТИРОВАТЬ: будьте осторожны, это решение не безопасно для юникода и не безопасно для XSS. Если вам нужна сложная проверка, возможно, лучше поискать где-нибудь еще.

это определенно отличная альтернатива, к сожалению, это php 5.2+ (если вы не установите версию PECL)

Owen 19.10.2008 12:07

В 5.2.13 есть ошибка (и я думаю, что в 5.3.2), которая не позволяет URL-адресам с дефисами проверяться с помощью этого метода.

vamin 02.06.2010 03:27

filter_var отклонит test-site.com, у меня есть доменные имена с дефисами, действительны они или нет. Я не думаю, что filter_var - лучший способ проверить URL-адрес. Это позволит использовать URL-адрес типа http://www.

Cesar 06.09.2010 23:30

> Это разрешит URL-адрес типа 'www'. Это нормально, когда URL-адрес типа 'localhost'

Stanislav 07.09.2010 14:34

Одна конкретная проблема: это проверяет URL-адреса в соответствии с RFC 2396, который не допускает подчеркивания в поддоменах, но некоторые веб-сайты имеют подчеркивания в поддоменах.

liviucmg 29.03.2011 21:43

Другая проблема этого метода в том, что он небезопасен для юникода.

Benji XVI 10.05.2011 17:24

С тех пор функция filter_var была обновлена, и теперь можно эффективно проверять URL-адреса с включенными дефисами, что делает ваш комментарий неверным, @vamin (см. отчет об ошибке здесь).

Zack Zatkin-Gold 12.01.2012 06:04

@zzatkin, в отчете об ошибке указано, что исправление включено в более поздние версии 5.2.14 и 5.3.3 (оно появилось слишком поздно для 5.2.13 и 5.3.2), хотя я согласен, что это больше не проблема, если вы поддерживаете PHP в актуальном состоянии.

vamin 23.01.2012 22:12

Это также подтвердит onedomain.com <br> http://www.anotherone.com <br> http: /…, которое я узнаю сегодня. Не то, что я имел в виду! Возвращение к альтернативе регулярного выражения (версия PHP => 5.4.4)

Bretticus 19.11.2012 23:31

Не принимать символы UTF-8. Вернет false для http://wiki.com/öva/mä/åäö.

Sawny 16.12.2012 23:06

Filter_var, по-видимому, проверяет все типы форматов URL-адресов независимо от того, действительны они или нет, кажется, что регулярное выражение - это способ правильно проверить URL-адреса

mic 30.09.2013 13:35

еще одна проблема заключается в том, что он не проверяется на новые TLD, такие как .me, .cm .guru и т. д.

bhaskarc 15.03.2015 20:59

Это плохое решение, за которое не должно быть так много голосов "за". Высокая XSS уязвимость.

RisingSun 04.05.2015 21:46

Проголосовано против как опасное. Прочтите комментарии об этом в онлайн-руководстве по PHP!

Nick Rice 12.09.2016 14:09

FILTER_VALIDATE_URL содержит много проблем, который необходимо исправить. Кроме того, документы, описывающие флаги не отражает фактический исходный код, где ссылки на некоторые флаги были полностью удалены. Подробнее здесь: news.php.net/php.internals/99018

S. Imp 13.05.2017 00:53

Еще одна статья Hree, объясняющая проблемы с этим: d-mueller.de/blog/…

thespacecamel 31.08.2018 21:31

это плохое решение, потому что a://site.com действителен для FILTER_VALIDATE_URL (PHP 7.2 и более ранние версии)

Arris 21.07.2020 14:29

это дерьмо метод. это действительно для www

DealZg 26.01.2021 21:34

Согласно руководству по PHP - parse_url следует использовать нет для проверки URL.

К сожалению, похоже, что filter_var('example.com', FILTER_VALIDATE_URL) не работает лучше.

И parse_url(), и filter_var() будут передавать неверные URL-адреса, такие как http://....

Поэтому в этом случае - regex является лучший метод.

Этот аргумент не следует. Если FILTER_VALIDATE_URL немного более разрешающий, чем вы хотите, сделайте несколько дополнительных проверок, чтобы справиться с этими крайними случаями. Повторное изобретение колеса с вашей собственной попыткой регулярного выражения для URL-адресов только уведет вас от полной проверки.

Kzqai 19.07.2010 04:50

См. Все сокращенные регулярные выражения на этой странице, чтобы узнать, почему не нужно писать свои собственные.

Kzqai 19.07.2010 06:54

Вы справедливо отметили Чалвак. Регулярные выражения для чего-то вроде URL-адресов могут быть (согласно другим ответам) очень трудно исправить. Регулярное выражение - это не всегда ответ. И наоборот, регулярное выражение тоже не всегда является неправильным ответом. Важным моментом является выбор правильного инструмента (регулярного выражения или другого) для работы, а не специального «анти» или «профессионального» регулярного выражения. Оглядываясь назад, ваш ответ об использовании filter_var в сочетании с ограничениями на его крайние случаи выглядит как лучший ответ (особенно когда ответы регулярных выражений начинают достигать более 100 символов или около того, что делает обслуживание указанного регулярного выражения кошмаром)

catchdave 20.07.2010 08:54

Редактировать:
Как указал заболеваемость, этот код УСТАРЕЛ с выпуском 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?

user138016 10.12.2009 18:48

@incidence абсолютно согласен. Я написал это в марте, а PHP 5.3 вышел только в конце июня, установив для eregi статус УСТАРЕВШИЙ. Спасибо. Буду редактировать и обновлять.

Frankie 10.12.2009 21:05

Поправьте меня, если я ошибаюсь, но можем ли мы все же предположить, что TLD будут иметь минимум 2 символа и максимум 6 символов?

Yzmir Ramirez 06.08.2011 22:15

@YzmirRamirez (Все эти годы спустя ...) Если были какие-либо сомнения, когда вы писали свой комментарий, их точно нет сейчас, с такими ДВУ в наши дни, как .photography

Nick Rice 12.09.2016 14:02

@NickRice, вы правы ... насколько Интернет изменился за 5 лет. Теперь я не могу дождаться, пока кто-нибудь сделает TLD .supercalifragilisticexpialidocious

Yzmir Ramirez 13.09.2016 20:03

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')?

Yzmir Ramirez 06.08.2011 22:14

Спасибо, именно то, что я искал. Однако я совершил ошибку, пытаясь его использовать. Функция "url_exist", а не "url_exists" ой ;-)

PJ Brunet 21.03.2012 00:24

Есть ли угроза безопасности при прямом доступе к URL-адресу, введенному пользователем?

siliconpi 10.05.2012 11:14

вы хотите добавить проверку, было ли найдено 404: <code> $ httpCode = curl_getinfo ($ c, CURLINFO_HTTP_CODE); // эхо $ url. ''. $ httpCode. '<br>'; if ($ httpCode == 404) {echo $ url. ' 404 '; } </code>

Camaleo 12.03.2018 16:28

Совершенно небезопасно ... любой входной URL-адрес будет активно доступен.

dmmd 28.10.2019 20:36

Согласно Джон Грубер (Дерзкий огненный шар):

Регулярное выражение:

(?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)

Ben Birney 03.10.2020 12:45

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 на '', где он работает с портом

pgee70 29.09.2014 01:41

В итоге я реализовал вариант этого, потому что мой домен заботится о том, существует ли URL на самом деле или нет :)

Raz0rwire 18.07.2016 16:34

Я не думаю, что в данном случае разумно использовать регулярные выражения. Невозможно сопоставить все возможности, и даже если вы это сделали, все равно есть вероятность, что 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:?

andrewsi 01.10.2012 00:27

/^(https?://)?([\da-z\.-pting+)\.([az\.pting{2,6})((/\w \ .-] *) * \ /? $ /

Shahbaz 26.09.2013 15:43

    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'

user3396065 20.11.2016 18:20

И вот ваш ответ =) Попробуй сломать, не получится !!!

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 ...
    "&#x00E6;", // æ
    "&#x00C6;", // Æ
    "&#x00C0;", // À
    "&#x00E0;", // à
    "&#x00C1;", // Á
    "&#x00E1;", // á
    "&#x00C2;", // Â
    "&#x00E2;", // â
    "&#x00E5;", // å
    "&#x00C5;", // Å
    "&#x00E4;", // ä
    "&#x00C4;", // Ä
    "&#x00C7;", // Ç
    "&#x00E7;", // ç
    "&#x00D0;", // Ð
    "&#x00F0;", // ð
    "&#x00C8;", // È
    "&#x00E8;", // è
    "&#x00C9;", // É
    "&#x00E9;", // é
    "&#x00CA;", // Ê
    "&#x00EA;", // ê
    "&#x00CB;", // Ë
    "&#x00EB;", // ë
    "&#x00CE;", // Î
    "&#x00EE;", // î
    "&#x00CF;", // Ï
    "&#x00EF;", // ï
    "&#x00F8;", // ø
    "&#x00D8;", // Ø
    "&#x00F6;", // ö
    "&#x00D6;", // Ö
    "&#x00D4;", // Ô
    "&#x00F4;", // ô
    "&#x00D5;", // Õ
    "&#x00F5;", // õ
    "&#x0152;", // Œ
    "&#x0153;", // œ
    "&#x00FC;", // ü
    "&#x00DC;", // Ü
    "&#x00D9;", // Ù
    "&#x00F9;", // ù
    "&#x00DB;", // Û
    "&#x00FB;", // û
    "&#x0178;", // Ÿ
    "&#x00FF;", // ÿ 
    "&#x00D1;", // Ñ
    "&#x00F1;", // ñ
    "&#x00FE;", // þ
    "&#x00DE;", // Þ
    "&#x00FD;", // ý
    "&#x00DD;", // Ý
    "&#x00BF;", // ¿
  )), ENT_QUOTES, 'UTF-8');

  $LINK_ICHARS = $LINK_ICHARS_DOMAIN . (string) html_entity_decode(implode("", array(
    "&#x00DF;", // ß
  )), 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;
}

Есть намного больше домены верхнего уровня.

Jeff Puckett 26.09.2016 23:17

Хорошо, это немного сложнее, чем простое регулярное выражение, но оно позволяет использовать разные типы 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 20.11.2016 18:34

@ user3396065, не могли бы вы предоставить пример ввода, который вызывает это?

Tim Groeneveld 28.11.2016 04:31

Вот как я это сделал. Но я хочу сказать, что я не очень уверен в регулярном выражении. Но это должно работать у тебя :)

$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&param2/';

if ( ! filter_var( $url, FILTER_VALIDATE_URL ) ) {
    // Wrong
}
else {
    // Valid
}

Возвращает отфильтрованные данные или FALSE, если фильтр не работает.

Проверить это здесь

Этот ответ дублирует один из ответов 2008 года!

suspectus 30.06.2015 15:13

Вдохновленный в этом вопросе .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.

UriTest.php (содержит допустимые и недопустимые случаи для URL-адресов и URN)

<?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&parameter2=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&parameter2=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' ],
            ];
    }
}

Uri.php (объект значения)

<?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"
  1. (http (s?): //) означает http: // или https: //

  2. ([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.
    

Примечание: извините за плохой английский. Моя страна не очень хорошо этим пользуется.

Вы заметили, сколько лет этому вопросу? Пожалуйста, объясните свое регулярное выражение, пользователям, которые еще не знают, будет трудно понять его без подробностей.

Nic3500 20.07.2018 14:41

Для всех, кто разрабатывает на 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/

Другие вопросы по теме