Validation PHP / regex pour URL

125

Je cherchais une simple expression régulière pour les URL, est-ce que quelqu'un en a une qui fonctionne bien? Je n'en ai pas trouvé avec les classes de validation du framework zend et j'ai vu plusieurs implémentations.

AndreLiem
la source
1
C'est une très bonne ressource. Donne une liste de nombreux modèles et tests différents: mathiasbynens.be/demo/url-regex
omar j

Réponses:

79

J'ai utilisé ceci sur quelques projets, je ne pense pas avoir rencontré de problèmes, mais je suis sûr que ce n'est pas exhaustif:

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

La plupart des indésirables aléatoires à la fin sont de traiter des situations comme http://domain.com.dans une phrase (pour éviter de faire correspondre le point final). Je suis sûr qu'il pourrait être nettoyé mais depuis cela a fonctionné. Je l'ai plus ou moins simplement copié de projet en projet.

Owen
la source
7
Certaines choses me sautent aux yeux: l'utilisation de l'alternance où les classes de caractères sont appelées (chaque alternative correspond exactement à un caractère); et le remplacement n'aurait pas dû avoir besoin des guillemets externes (ils n'étaient nécessaires qu'à cause du modificateur inutile / e sur l'expression régulière).
Alan Moore
1
@John Scipione: google.comn'est qu'un chemin d'URL relative valide mais pas une URL absolue valide. Et je pense que c'est ce qu'il recherche.
Gumbo le
Cela ne fonctionne pas dans ce cas - il comprend la fuite « : 3 cantari noi dans albumul <a href=" audio.resursecrestine.ro/cantece/index-autori/andrei-rosu/...>
Softy
1
@Softy quelque chose comme http://example.com/somedir/...est une URL parfaitement légitime, demandant le fichier nommé ...- qui est un nom de fichier légitime.
Stephen P
J'utilise Zend \ Validator \ Regex pour valider l'url en utilisant votre modèle, mais il détecte toujours http://www.examplequ'il est valide
Joko Wandiro
207

Utilisez la filter_var()fonction pour valider si une chaîne est une URL ou non:

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

Il est déconseillé d'utiliser des expressions régulières lorsque cela n'est pas nécessaire.

EDIT : Attention, cette solution n'est pas sûre unicode et non XSS. Si vous avez besoin d'une validation complexe, il vaut peut-être mieux chercher ailleurs.

Stanislav
la source
29
Il y a un bogue dans 5.2.13 (et je pense 5.3.2) qui empêche les URL contenant des tirets de se valider en utilisant cette méthode.
vamin
14
filter_var rejettera test-site.com , j'ai des noms de domaine avec des tirets, qu'ils soient valides ou non. Je ne pense pas que filter_var soit le meilleur moyen de valider une URL. Cela permettra une URL commehttp://www
Cesar
4
> Cela autorisera une URL comme ' www ' C'est OK quand une URL comme ' localhost '
Stanislav
12
L'autre problème avec cette méthode est qu'elle n'est pas compatible avec unicode.
Benji XVI
3
FILTER_VALIDATE_URL présente de nombreux problèmes qui doivent être résolus . De plus, les documents décrivant les indicateurs ne reflètent pas le code source réel où les références à certains indicateurs ont été entièrement supprimées. Plus d'infos ici: news.php.net/php.internals/99018
S. Imp
29

Selon le manuel PHP - parse_url ne doit pas être utilisé pour valider une URL.

Malheureusement, il semble que filter_var('example.com', FILTER_VALIDATE_URL)cela ne fonctionne pas mieux.

Les deux parse_url()et filter_var()transmettront des URL malformées telles quehttp://...

Par conséquent, dans ce cas - regex est la meilleure méthode.

catchdave
la source
10
Cet argument ne suit pas. Si FILTER_VALIDATE_URL est un peu plus permissif que vous ne le souhaitez, effectuez des vérifications supplémentaires pour gérer ces cas extrêmes. Réinventer la roue avec votre propre tentative de regex contre les URL ne fera que vous éloigner d'une vérification complète.
Kzqai
2
Voir toutes les expressions rationnelles abattues sur cette page pour des exemples de pourquoi -pas- d'écrire les vôtres.
Kzqai
3
Vous faites un bon point Tchalvak. Les expressions régulières pour quelque chose comme les URL peuvent (comme d'autres réponses) être très difficiles à obtenir correctement. Regex n'est pas toujours la réponse. Inversement, regex n'est pas toujours la mauvaise réponse non plus. Le point important est de choisir le bon outil (regex ou autre) pour le travail et de ne pas être spécifiquement "anti" ou "pro" regex. Avec le recul, votre réponse concernant l'utilisation de filter_var en combinaison avec des contraintes sur ses cas de bord, semble être la meilleure réponse (en particulier lorsque les réponses de regex commencent à atteindre plus de 100 caractères environ - faisant de la maintenance de ladite regex un cauchemar)
catchdave
12

Juste au cas où vous voudriez savoir si l'URL existe vraiment:

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);
}
Roger
la source
1
Je ferais toujours une sorte de validation $urlavant de vérifier que l'URL est réelle parce que l'opération ci-dessus est coûteuse - peut-être jusqu'à 200 millisecondes selon la taille du fichier. Dans certains cas, l'URL peut ne pas avoir de ressource à son emplacement encore disponible (par exemple, créer une URL vers une image qui n'a pas encore été téléchargée). De plus, vous n'utilisez pas de version mise en cache, donc ce n'est pas comme si file_exists()cela mettra en cache une statistique sur un fichier et retournera presque instantanément. La solution que vous avez fournie reste cependant utile. Pourquoi ne pas simplement utiliser fopen($url, 'r')?
Yzmir Ramirez
Merci, exactement ce que je cherchais. Cependant, j'ai fait une erreur en essayant de l'utiliser. La fonction est "url_exist" pas "url_exists" oups ;-)
PJ Brunet
9
Y a-t-il un risque de sécurité en accédant directement à l'URL saisie par l'utilisateur?
siliconpi
vous souhaitez ajouter un contrôle si un 404 a été trouvé: <code> $ httpCode = curl_getinfo ($ c, CURLINFO_HTTP_CODE); // echo $ url. ''. $ httpCode. «<br>»; if ($ httpCode == 404) {echo $ url. ' 404 '; } </code>
Camaleo
N'est pas sûr du tout .. n'importe quelle URL d'entrée serait activement accédée.
dmmd
11

Selon John Gruber (Daring Fireball):

Regex:

(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))

en utilisant dans 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)

Voici le modèle de regex étendu (avec des commentaires):

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

Pour plus de détails, veuillez consulter: http://daringfireball.net/2010/07/improved_regex_for_matching_urls

abhiomkar
la source
9

Je ne pense pas que l'utilisation d'expressions régulières soit une chose intelligente à faire dans ce cas. Il est impossible de faire correspondre toutes les possibilités et même si vous l'avez fait, il y a toujours une chance que l'URL n'existe tout simplement pas.

Voici un moyen très simple de tester si l'URL existe réellement et est lisible:

if (preg_match("#^https?://.+#", $link) and @fopen($link,"r")) echo "OK";

(s'il n'y a pas, preg_matchcela validera également tous les noms de fichiers sur votre serveur)

promatie
la source
7

J'ai utilisé celui-ci avec un bon succès - je ne me souviens pas d'où je l'ai obtenu

$pattern = "/\b(?:(?:https?|ftp):\/\/|www\.)[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i";
Peter Bailey
la source
^ (http: // | https: //)? (([a-z0-9]? ([-a-z0-9] * [a-z0-9] +)?) {1,63} \ .) + [az] {2,6} (peut-être trop gourmand, pas encore sûr, mais c'est plus flexible sur le protocole et le premier www)
andrewbadera
7
    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;
      }
    }
Vikash Kumar
la source
Ne fonctionne pas avec un lien comme: 'www.w3schools.com/home/3/?a=l'
user3396065
5

Et il y a votre réponse =) Essayez de le casser, vous ne pouvez pas !!!

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;
}
George Milonas
la source
Il existe beaucoup plus de domaines de premier niveau .
Jeff Puckett du
4

Edit:
Comme l' incidence l'a souligné, ce code a été déprécié avec la sortie de PHP 5.3.0 (30/06/2009) et doit être utilisé en conséquence.


Juste mes deux cents mais j'ai développé cette fonction et l'utilise depuis un moment avec succès. Il est bien documenté et séparé afin que vous puissiez facilement le changer.

// 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;
}
Frankie
la source
1
Eregi sera supprimé dans PHP 6.0.0. Et les domaines avec "öäåø" ne seront pas validés avec votre fonction. Vous devriez probablement d'abord convertir l'URL en punycode?
@incidence est tout à fait d'accord. J'ai écrit ceci en mars et PHP 5.3 n'est sorti que fin juin en définissant eregi comme DEPRECATED. Je vous remercie. Je vais éditer et mettre à jour.
Frankie
Corrigez-moi si je me trompe, mais pouvons-nous toujours supposer que les TLD auront un minimum de 2 caractères et un maximum de 6 caractères?
Yzmir Ramirez
2
@YzmirRamirez (Toutes ces années plus tard ...) S'il y avait un doute quand vous avez écrit votre commentaire, il n'y en a certainement pas maintenant, avec des TLD de nos jours tels que .photography
Nick Rice
@NickRice vous avez raison ... combien le web change en 5 ans. Maintenant, je ne peux pas attendre que quelqu'un fasse le TLD .supercalifragilisticexpialidocious
Yzmir Ramirez
4
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;
    }
jini
la source
Salut, cette solution est bonne, et je l'ai votée positivement, mais elle ne prend pas en compte le port standard pour https: - vous suggérons de remplacer simplement 80 par `` là où cela fonctionne sur le port
pgee70
J'ai fini par implémenter une variante à ce sujet, car mon domaine se soucie de savoir si une URL existe réellement ou non :)
Raz0rwire
2

Inspiré de cette question .NET StackOverflow et de cet article référencé de cette question, il y a ce validateur d'URI (URI signifie qu'il valide à la fois l'URL et l'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." );
}

J'ai testé avec succès cette fonction dans un ValueObject que j'ai créé Uriet testé par UriTest.

UriTest.php (contient des cas valides et non valides pour les URL et les 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 (objet de valeur)

<?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 )
    {
        // /programming/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." );
        }
    }
}

Unité en cours d'exécution

Il y a 65 affirmations dans 46 tests. Attention: il existe 2 fournisseurs de données pour les expressions valides et 2 autres pour les expressions non valides. L'un est pour les URL et l'autre pour les URN. Si vous utilisez une version de PhpUnit v5.6 * ou antérieure, vous devez joindre les deux fournisseurs de données en un seul.

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)

Couverture de code

Il y a 100% de couverture de code dans cet exemple de vérificateur d'URI.

Xavi Montero
la source
2
"/(http(s?):\/\/)([a-z0-9\-]+\.)+[a-z]{2,4}(\.[a-z]{2,4})*(\/[^ ]+)*/i"
  1. (http (s?): //) signifie http: // ou https: //

  2. ([a-z0-9 -] +.) + => 2.0 [a-z0-9-] signifie tout caractère az ou tout signe 0-9 ou (-))

                 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- < /font>+.)+[ az .{2,4} (.[ az . ) / 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.

Remarque: Désolé pour le mauvais anglais. Mon pays ne l'utilise pas bien.

Some_North_korea_kid
la source
4
Avez-vous remarqué l'âge de cette question? Veuillez expliquer votre regex, les utilisateurs qui ne le savent pas déjà auront du mal à le comprendre sans détails.
Nic3500
1

OK, donc c'est un peu plus complexe qu'une simple regex, mais cela permet différents types d'urls.

Exemples:

Tout ce qui doit être marqué comme valide.

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;
}

Notez qu'il existe une vérification in_array pour les protocoles que vous souhaitez autoriser (actuellement, seuls http et https sont dans cette liste).

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
Tim Groeneveld
la source
Jette: ErrorException: Index non défini: schéma si le protocole n'est pas spécifié, je suggère de vérifier s'il est défini avant.
user3396065
@ user3396065, pouvez-vous s'il vous plaît fournir un exemple d'entrée qui jette cela?
Tim Groeneveld
1

La meilleure URL Regex qui a fonctionné pour moi:

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);
}

Exemples:

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

Source: http://urlregex.com/

Fred Vanelli
la source
0

Peter's Regex ne me semble pas correct pour de nombreuses raisons. Il autorise toutes sortes de caractères spéciaux dans le nom de domaine et ne teste pas beaucoup.

La fonction de Frankie me semble bonne et vous pouvez créer une bonne regex à partir des composants si vous ne voulez pas de fonction, comme ceci:

^(http://|https://)(([a-z0-9]([-a-z0-9]*[a-z0-9]+)?){1,63}\.)+[a-z]{2,6}

Non testé mais je pense que cela devrait fonctionner.

De plus, la réponse d'Owen ne semble pas non plus à 100%. J'ai pris la partie domaine de l'expression régulière et l'ai testée sur un outil de test Regex http://erik.eae.net/playground/regexp/regexp.html

Je mets la ligne suivante:

(\S*?\.\S*?)

dans la section "regexp" et la ligne suivante:

-hello.com

dans la section "exemple de texte".

Le résultat a permis au caractère moins de passer. Parce que \ S signifie tout caractère non espace.

Notez que l'expression régulière de Frankie gère le moins car elle a cette partie pour le premier caractère:

[a-z0-9]

Ce qui ne permettra pas le moins ou tout autre caractère spécial.

Joedevon
la source
0

Voici comment je l'ai fait. Mais je tiens à souligner que je ne suis pas si sûr de l'expression régulière. Mais ça devrait marcher toi :)

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

De cette façon, vous n'aurez pas besoin du marqueur d'évaluation sur votre motif.

J'espère que ça aide :)

Thomas Venturini
la source
0

Voici une classe simple pour la validation d'URL à l' aide de RegEx, puis croise le domaine avec les serveurs RBL (Realtime Blackhole Lists) populaires:

Installer:

require 'URLValidation.php';

Usage:

require 'URLValidation.php';
$urlVal = new UrlValidation(); //Create Object Instance

Ajoutez une URL comme paramètre de la domain()méthode et vérifiez le retour.

$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>';

}

Production:

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

Comme vous pouvez le voir ci-dessus, www.bokranzr.com est répertorié comme site Web malveillant via un RBL, de sorte que le domaine a été renvoyé comme faux.

Kitson88
la source
-1

J'ai trouvé que c'était le plus utile pour faire correspondre une URL.

^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$
Jeremy Moore
la source
1
Cela correspondra-t-il aux URL commençant par ftp:?
andrewsi
/^(https?:\/\/)?([\da-z\.- </font>+)\.([az\. </font>{2,6})([\/\w \ .-] *) * \ /? $ /
Shahbaz
-1

Il existe une fonction native PHP pour cela:

$url = 'http://www.yoururl.co.uk/sub1/sub2/?param=1&param2/';

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

Renvoie les données filtrées, ou FALSE si le filtre échoue.

Vérifiez-le ici

Fredmat
la source
Cette réponse reproduit une des réponses de 2008!
suspectus