Meilleur moyen de vérifier si une URL est valide

149

Je veux utiliser PHP pour vérifier si la chaîne stockée dans la $myoutputvariable contient une syntaxe de lien valide ou s'il s'agit simplement d'un texte normal. La fonction ou la solution que je recherche doit reconnaître tous les formats de liens, y compris ceux avec des paramètres GET.

Une solution, suggérée sur de nombreux sites, pour interroger réellement la chaîne (en utilisant CURL ou la file_get_contents()fonction) n'est pas possible dans mon cas et je voudrais l'éviter.

J'ai pensé aux expressions régulières ou à une autre solution.

Ryan
la source
Utiliser CURL ou obtenir son contenu HTTP peut être lent, si vous voulez quelque chose de plus rapide et presque aussi fiable, envisagez d'utiliser gethostbyaddr () sur le nom d'hôte. S'il se résout en une adresse IP, il a probablement un site Web. Bien sûr, cela dépend de vos besoins.
TravisO

Réponses:

301

Vous pouvez utiliser un validateur de filtre natif

filter_var($url, FILTER_VALIDATE_URL);

Valide la valeur comme URL (selon » http://www.faqs.org/rfcs/rfc2396 ), éventuellement avec les composants requis. Attention, une URL valide peut ne pas spécifier le protocole HTTP http: // donc une validation supplémentaire peut être nécessaire pour déterminer que l'URL utilise un protocole attendu, par exemple ssh: // ou mailto :. Notez que la fonction ne trouvera que les URL ASCII valides; les noms de domaine internationalisés (contenant des caractères non ASCII) échoueront.

Exemple:

if (filter_var($url, FILTER_VALIDATE_URL) === FALSE) {
    die('Not a valid URL');
}
Gordon
la source
9
Comportement attendu de @Raveren car ce sont des URL valides.
Gordon
8
Sachez que FILTER_VALIDATE_URLcela ne validera pas le protocole d'une URL. Ainsi ssh://, ftp://etc. passera.
Seph
3
Comportement attendu de @SephVelut car ce sont des URL valides.
Gordon
1
il autorise les URL comme ttp: //amazon.com
Elia Weiss
4
@JoshHabdas, je pense que vous manquez le point. Le code PHP fait exactement ce qu'il prétend faire. Mais il ne peut pas lire dans vos pensées. Il y a une énorme différence entre invalide et indésirable. Indésirable est très subjectif, c'est pourquoi c'est au programmeur de travailler sur ce détail. Vous pouvez également noter que le code valide l'URL, mais ne prouve pas qu'elle existe. Ce n'est pas la faute de PHP si un utilisateur a mal tapé «amazon», «amozon», ce qui validerait, mais qui est toujours indésirable.
JBH
20

Voici le meilleur tutoriel que j'ai trouvé là-bas:

http://www.w3schools.com/php/filter_validate_url.asp

<?php
$url = "http://www.qbaki.com";

// Remove all illegal characters from a url
$url = filter_var($url, FILTER_SANITIZE_URL);

// Validate url
if (filter_var($url, FILTER_VALIDATE_URL) !== false) {
echo("$url is a valid URL");
} else {
echo("$url is not a valid URL");
}
?>

Drapeaux possibles:

FILTER_FLAG_SCHEME_REQUIRED - URL must be RFC compliant (like http://example)
FILTER_FLAG_HOST_REQUIRED - URL must include host name (like http://www.example.com)
FILTER_FLAG_PATH_REQUIRED - URL must have a path after the domain name (like www.example.com/example1/)
FILTER_FLAG_QUERY_REQUIRED - URL must have a query string (like "example.php?name=Peter&age=37")
Erich García
la source
1
Juste un peu: !filter_var(...) === false==> filter_var(...) === trueou tout simplement filter_var(...). :)
Domenico De Felice
@ ErichGarcía ce code ne vérifie pas qu'il s'agit d'une URL HTTP / S valide comme le demande l'OP. Cela passera des choses comme ssh: //, ftp: // etc cela ne vérifie que si c'est une URL syntaxiquement valide selon RFC 2396
twigg
N'utilisez pas FILTER_VALIDATE_URL. C'est désordonné et peu fiable. Par exemple, il valide ttps://www.youtube.comcomme valide
Jeffz
12

L'utilisation de filter_var () échouera pour les URL avec des caractères non-ascii, par exemple ( http://pt.wikipedia.org/wiki/Guimarães ). La fonction suivante encode tous les caractères non-ascii (par exemple http://pt.wikipedia.org/wiki/Guimar%C3%A3es ) avant d'appeler filter_var ().

J'espère que cela aide quelqu'un.

<?php

function validate_url($url) {
    $path = parse_url($url, PHP_URL_PATH);
    $encoded_path = array_map('urlencode', explode('/', $path));
    $url = str_replace($path, implode('/', $encoded_path), $url);

    return filter_var($url, FILTER_VALIDATE_URL) ? true : false;
}

// example
if(!validate_url("http://somedomain.com/some/path/file1.jpg")) {
    echo "NOT A URL";
}
else {
    echo "IS A URL";
}
Huey Ly
la source
Ça y est. Enfin quelqu'un est revenu en 2017
Kyle KIM
Fonctionne pour moi (les autres ne font pas BTW) :)
Jono
C'est la SEULE solution qui a fonctionné pour moi. Merci!
Silas
10
function is_url($uri){
    if(preg_match( '/^(http|https):\\/\\/[a-z0-9_]+([\\-\\.]{1}[a-z_0-9]+)*\\.[_a-z]{2,5}'.'((:[0-9]{1,5})?\\/.*)?$/i' ,$uri)){
      return $uri;
    }
    else{
        return false;
    }
}
mghhgm
la source
3

Personnellement, j'aimerais utiliser l'expression régulière ici. Le code ci-dessous a parfaitement fonctionné pour moi.

$baseUrl     = url('/'); // for my case https://www.xrepeater.com
$posted_url  = "home";
// Test with one by one
/*$posted_url  = "/home";
$posted_url  = "xrepeater.com";
$posted_url  = "www.xrepeater.com";
$posted_url  = "http://www.xrepeater.com";
$posted_url  = "https://www.xrepeater.com";
$posted_url  = "https://xrepeater.com/services";
$posted_url  = "xrepeater.dev/home/test";
$posted_url  = "home/test";*/

$regularExpression  = "((https?|ftp)\:\/\/)?"; // SCHEME Check
$regularExpression .= "([a-z0-9+!*(),;?&=\$_.-]+(\:[a-z0-9+!*(),;?&=\$_.-]+)?@)?"; // User and Pass Check
$regularExpression .= "([a-z0-9-.]*)\.([a-z]{2,3})"; // Host or IP Check
$regularExpression .= "(\:[0-9]{2,5})?"; // Port Check
$regularExpression .= "(\/([a-z0-9+\$_-]\.?)+)*\/?"; // Path Check
$regularExpression .= "(\?[a-z+&\$_.-][a-z0-9;:@&%=+\/\$_.-]*)?"; // GET Query String Check
$regularExpression .= "(#[a-z_.-][a-z0-9+\$_.-]*)?"; // Anchor Check

if(preg_match("/^$regularExpression$/i", $posted_url)) { 
    if(preg_match("@^http|https://@i",$posted_url)) {
        $final_url = preg_replace("@(http://)+@i",'http://',$posted_url);
        // return "*** - ***Match : ".$final_url;
    }
    else { 
          $final_url = 'http://'.$posted_url;
          // return "*** / ***Match : ".$final_url;
         }
    }
else {
     if (substr($posted_url, 0, 1) === '/') { 
         // return "*** / ***Not Match :".$final_url."<br>".$baseUrl.$posted_url;
         $final_url = $baseUrl.$posted_url;
     }
     else { 
         // return "*** - ***Not Match :".$posted_url."<br>".$baseUrl."/".$posted_url;
         $final_url = $baseUrl."/".$final_url; }
}
Md. Noor-A-Alam Siddique
la source
1
C'est la meilleure réponse pour valider l'URL des sites Web. Avec quelques changements, cela fonctionne parfaitement. Merci
Amir hossein Karimi
3

Compte tenu des problèmes avec filter_var () nécessitant http: //, j'utilise:

$is_url = filter_var($filename, FILTER_VALIDATE_URL) || array_key_exists('scheme', parse_url($filename));

Leonard d'automne
la source
N'utilisez pas FILTER_VALIDATE_URL. C'est désordonné et peu fiable. Par exemple, il valide ttps://www.youtube.comcomme valide
Jeffz
2

Vous pouvez utiliser cette fonction, mais elle retournera false si le site Web est hors ligne.

  function isValidUrl($url) {
    $url = parse_url($url);
    if (!isset($url["host"])) return false;
    return !(gethostbyname($url["host"]) == $url["host"]);
}
Hasan Veli Soyalan
la source
2

En fait ... filter_var ($ url, FILTER_VALIDATE_URL); ne fonctionne pas très bien. Lorsque vous tapez une vraie URL, cela fonctionne mais, il ne vérifie que http: // donc si vous tapez quelque chose comme " http: // weirtgcyaurbatc ", il dira toujours que c'est réel.

Hayden Frobenius
la source
Pour intance FILTER_VALIDATE_URL valide ttps://www.youtube.comcomme valide
Jeffz
1

Une autre façon de vérifier si l'URL donnée est valide est d'essayer d'y accéder, la fonction ci-dessous récupérera les en-têtes de l'URL donnée, cela garantira que l'URL est valide ET que le serveur Web est actif:

function is_url($url){
        $response = array();
        //Check if URL is empty
        if(!empty($url)) {
            $response = get_headers($url);
        }
        return (bool)in_array("HTTP/1.1 200 OK", $response, true);
/*Array
(
    [0] => HTTP/1.1 200 OK 
    [Date] => Sat, 29 May 2004 12:28:14 GMT
    [Server] => Apache/1.3.27 (Unix)  (Red-Hat/Linux)
    [Last-Modified] => Wed, 08 Jan 2003 23:11:55 GMT
    [ETag] => "3f80f-1b6-3e1cb03b"
    [Accept-Ranges] => bytes
    [Content-Length] => 438
    [Connection] => close
    [Content-Type] => text/html
)*/ 
    }   
Bud Damyanov
la source
Bonne idée. Cela échouera si le serveur utilise HTTP / 1.0 ou HTTP / 2.0, ou renvoie une redirection.
iblamefish
Oui, c'est un point de départ, d'autres améliorations peuvent être apportées facilement.
Bud Damyanov
1

Je suis tombé sur cet article de 2012. Il prend en compte les variables qui peuvent ou non être simplement des URL simples.

L'auteur de l'article, David Müeller , fournit cette fonction qui, selon lui, "... pourrait valoir la peine [sic]", ainsi que quelques exemples filter_varet ses lacunes.

/**
 * Modified version of `filter_var`.
 *
 * @param  mixed $url Could be a URL or possibly much more.
 * @return bool
 */
function validate_url( $url ) {
    $url = trim( $url );

    return (
        ( strpos( $url, 'http://' ) === 0 || strpos( $url, 'https://' ) === 0 ) &&
        filter_var(
            $url,
            FILTER_VALIDATE_URL,
            FILTER_FLAG_SCHEME_REQUIRED || FILTER_FLAG_HOST_REQUIRED
        ) !== false
    );
}
DaveyJake
la source
0

si quelqu'un est intéressé à utiliser le cURL pour la validation. Vous pouvez utiliser le code suivant.

<?php 
public function validationUrl($Url){
        if ($Url == NULL){
            return $false;
        }
        $ch = curl_init($Url);
        curl_setopt($ch, CURLOPT_TIMEOUT, 5);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $data = curl_exec($ch);
        $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        return ($httpcode >= 200 && $httpcode < 300) ? true : false; 
    }
VishalParkash
la source