Melhor maneira de verificar se um URL é válido

149

Eu quero usar o PHP para verificar se a string armazenada na $myoutputvariável contém uma sintaxe de link válida ou é apenas um texto normal. A função ou solução que estou procurando deve reconhecer todos os formatos de links, incluindo os com parâmetros GET.

Uma solução, sugerida em muitos sites, para realmente consultar a string (usando CURL ou file_get_contents()função) não é possível no meu caso e eu gostaria de evitá-la.

Pensei em expressões regulares ou em outra solução.

Ryan
fonte
Usar CURL ou obter seu conteúdo HTTP pode ser lento; se você quiser algo mais rápido e quase tão confiável, considere usar gethostbyaddr () no nome do host. Se resolver para um IP, provavelmente ele possui um site. Claro que isso depende de suas necessidades.
TravisO 13/01/10

Respostas:

301

Você pode usar um validador de filtro nativo

filter_var($url, FILTER_VALIDATE_URL);

Valida o valor como URL (de acordo com » http://www.faqs.org/rfcs/rfc2396 ), opcionalmente com os componentes necessários. Cuidado: uma URL válida pode não especificar o protocolo HTTP http: //, portanto, uma validação adicional pode ser necessária para determinar se a URL usa um protocolo esperado, por exemplo, ssh: // ou mailto :. Observe que a função encontrará apenas URLs ASCII válidas; nomes de domínio internacionalizados (contendo caracteres não ASCII) falharão.

Exemplo:

if (filter_var($url, FILTER_VALIDATE_URL) === FALSE) {
    die('Not a valid URL');
}
Gordon
fonte
9
@Raveren comportamento esperado, pois esses são URLs válidos.
Gordon
8
Esteja ciente de que FILTER_VALIDATE_URLnão validará o protocolo de um URL. Então ssh://, ftp://etc vai passar.
Seph
3
Comportamento esperado de @SephVelut, pois são URLs válidos.
1055 Gordon
1
ele permite urls como ttp: //amazon.com
Elia Weiss
4
@ JoshHabdas, acho que você está perdendo o objetivo. O código PHP faz exatamente o que ele afirma fazer. Mas não consegue ler sua mente. Há uma enorme diferença entre inválido e indesejado. Indesejável é muito subjetivo, e é por isso que resta ao programador resolver esses detalhes. Você também pode observar que o código valida o URL, mas não prova que ele exista. Não é culpa do PHP que um usuário tenha digitado incorretamente "amazon", "amozon", o que validaria, mas ainda é indesejável.
JB
20

Aqui está o melhor tutorial que encontrei por lá:

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

Sinalizadores possíveis:

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
fonte
1
Apenas um nit: !filter_var(...) === false==> filter_var(...) === trueou apenas filter_var(...). :)
Domenico De Felice
@ ErichGarcía este código não verifica se é um URL HTTP / S válido, como pede o OP. Isso vai passar coisas como ssh: //, ftp: // etc isso só verifica se é um URL sintaticamente válido de acordo com RFC 2396
twigg
Não use FILTER_VALIDATE_URL. É confuso e pouco confiável. Por exemplo, valida ttps://www.youtube.comcomo válida
Jeffz
12

O uso de filter_var () falhará para URLs com caracteres não-ascii, por exemplo ( http://pt.wikipedia.org/wiki/Guimarães ). A função a seguir codifica todos os caracteres não-ascii (por exemplo, http://pt.wikipedia.org/wiki/Guimar%C3%A3es ) antes de chamar filter_var ().

Espero que isso ajude alguém.

<?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
fonte
É isso. Finalmente alguém voltou em 2017
Kyle KIM
Obras para me (os outros não BTW) :)
Jono
Esta é a única solução que funcionou para mim. Obrigado!
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
fonte
3

Pessoalmente, eu gostaria de usar expressões regulares aqui. O código abaixo funcionou perfeitamente para mim.

$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
fonte
1
Esta é a melhor resposta para validar o URL dos sites. Com poucas mudanças, isso funciona perfeitamente. Obrigado
Amir hossein Karimi
3

Dados problemas com filter_var () que precisam de http: //, eu uso:

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

Autumn Leonard
fonte
Não use FILTER_VALIDATE_URL. É confuso e pouco confiável. Por exemplo, valida ttps://www.youtube.comcomo válida
Jeffz
2

Você pode usar esta função, mas ela retornará false se o site estiver offline.

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

Na verdade ... filter_var ($ url, FILTER_VALIDATE_URL); não funciona muito bem. Quando você digita um URL real, ele funciona, mas verifica apenas http: //; portanto, se você digitar algo como " http: // weirtgcyaurbatc ", continuará dizendo que é real.

Hayden Frobenius
fonte
Por exemplo, FILTER_VALIDATE_URL valida ttps://www.youtube.comcomo válido
Jeffz
1

Outra maneira de verificar se o URL especificado é válido é tentar acessá-lo; a função abaixo buscará os cabeçalhos do URL especificado, isso garantirá que o URL seja válido E o servidor da web esteja ativo:

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
fonte
Boa ideia. Isso falhará se o servidor estiver usando HTTP / 1.0 ou HTTP / 2.0, ou retornar um redirecionamento.
iblamefish
Sim, é um ponto de partida, outras melhorias podem ser feitas facilmente.
Bud Damyanov 23/02
1

Deparei com este artigo a partir de 2012. Ele leva em conta variáveis que pode ou não ser URLs apenas simples.

O autor do artigo, David Müeller , fornece essa função que ele diz: "... pode valer a pena [sic]", juntamente com alguns exemplos filter_vare suas deficiências.

/**
 * 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
fonte
0

se alguém estiver interessado em usar o cURL para validação. Você pode usar o seguinte código.

<?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
fonte