Najlepszy sposób na sprawdzenie, czy adres URL jest prawidłowy

149

Chcę użyć PHP, aby sprawdzić, czy ciąg przechowywany w $myoutputzmiennej zawiera prawidłową składnię linku, czy jest to tylko zwykły tekst. Funkcja lub rozwiązanie, którego szukam, powinno rozpoznawać wszystkie formaty linków, w tym te z parametrami GET.

Rozwiązanie, sugerowane na wielu stronach, aby faktycznie zapytać o string (używając CURL lub file_get_contents()funkcji) nie jest możliwe w moim przypadku i chciałbym tego uniknąć.

Myślałem o wyrażeniach regularnych lub innym rozwiązaniu.

Ryan
źródło
Używanie CURL lub uzyskiwanie zawartości HTTP może być powolne, jeśli chcesz czegoś szybszego i prawie tak samo niezawodnego, rozważ użycie gethostbyaddr () na nazwie hosta. Jeśli przekształca się w adres IP, prawdopodobnie ma witrynę internetową. Oczywiście zależy to od Twoich potrzeb.
TravisO

Odpowiedzi:

301

Możesz użyć natywnego walidatora filtra

filter_var($url, FILTER_VALIDATE_URL);

Sprawdza wartość jako URL (zgodnie z » http://www.faqs.org/rfcs/rfc2396 ), opcjonalnie z wymaganymi komponentami. Uwaga, prawidłowy adres URL może nie określać protokołu HTTP http: //, więc może być wymagana dalsza weryfikacja w celu ustalenia, czy adres URL korzysta z oczekiwanego protokołu, np. Ssh: // lub mailto :. Zauważ, że funkcja znajdzie tylko adresy URL ASCII jako prawidłowe; umiędzynarodowione nazwy domen (zawierające znaki spoza zestawu ASCII) nie będą działać.

Przykład:

if (filter_var($url, FILTER_VALIDATE_URL) === FALSE) {
    die('Not a valid URL');
}
Gordon
źródło
9
@Raveren oczekiwane zachowanie, ponieważ są to prawidłowe adresy URL.
Gordon
8
Należy pamiętać, że FILTER_VALIDATE_URLnie spowoduje to sprawdzenia protokołu adresu URL. Więc ssh://, ftp://itp minie.
Seph
3
Oczekiwano zachowania @SephVelut, ponieważ są to prawidłowe adresy URL.
Gordon
1
zezwala na adresy URL, takie jak ttp: //amazon.com
Elia Weiss
4
@JoshHabdas, myślę, że nie rozumiesz. Kod PHP robi dokładnie to, co twierdzi. Ale nie może czytać w twoich myślach. Istnieje ogromna różnica między nieprawidłowym a niechcianym. Niechciane jest bardzo subiektywne, dlatego to programiście muszą opracować ten szczegół. Możesz również zauważyć, że kod sprawdza poprawność adresu URL, ale nie dowodzi, że istnieje. To nie wina PHP, że użytkownik błędnie wpisał „amazon”, „amozon”, co mogłoby sprawdzić poprawność, ale nadal jest niepożądane.
JBH
20

Oto najlepszy samouczek, jaki tam znalazłem:

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

Możliwe flagi:

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
źródło
1
Tylko nitka: !filter_var(...) === false==> filter_var(...) === truelub po prostu filter_var(...). :)
Domenico De Felice
@ ErichGarcía ten kod nie sprawdza, czy jest to prawidłowy adres URL HTTP / S, o który pyta OP. Spowoduje to przekazanie takich rzeczy, jak ssh: //, ftp: // itd. Sprawdza tylko, czy jest to poprawny składniowo adres URL zgodnie z RFC 2396
twigg
Nie używaj FILTER_VALIDATE_URL. Jest brudny i zawodny. Np. ttps://www.youtube.com
Sprawdza się
12

Użycie filter_var () nie powiedzie się dla adresów URL ze znakami innymi niż ASCII, np. ( Http://pt.wikipedia.org/wiki/Guimarães ). Poniższa funkcja kodować wszystkie znaki spoza ASCII (np http://pt.wikipedia.org/wiki/Guimar%C3%A3es ) przed wywołaniem filter_var ().

Mam nadzieję, że to komuś pomoże.

<?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
źródło
To jest to. W końcu ktoś wrócił w 2017 roku
Kyle KIM
U mnie działa (przy okazji inni nie) :)
Jono
To JEDYNE rozwiązanie, które u mnie zadziałało. Dzięki!
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
źródło
3

Osobiście chciałbym tutaj użyć wyrażenia regularnego. Poniższy kod idealnie działał dla mnie.

$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
źródło
1
To najlepsza odpowiedź na weryfikację adresu URL witryny. Z kilkoma zmianami działa to doskonale. Dzięki
Amir hossein Karimi
3

Biorąc pod uwagę problemy z filter_var () wymagającą http: //, używam:

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

Jesienny Leonard
źródło
Nie używaj FILTER_VALIDATE_URL. Jest brudny i zawodny. Np. ttps://www.youtube.com
Sprawdza się
2

Możesz użyć tej funkcji, ale zwróci ona wartość false, jeśli witryna jest offline.

  function isValidUrl($url) {
    $url = parse_url($url);
    if (!isset($url["host"])) return false;
    return !(gethostbyname($url["host"]) == $url["host"]);
}
Hasan Veli Soyalan
źródło
2

Właściwie ... filter_var ($ url, FILTER_VALIDATE_URL); nie działa zbyt dobrze. Kiedy wpisujesz prawdziwy adres URL, działa, ale sprawdza tylko http: //, więc jeśli wpiszesz coś w rodzaju „ http: // weirtgcyaurbatc ”, nadal będzie mówić, że jest prawdziwy.

Hayden Frobenius
źródło
Dla intencji FILTER_VALIDATE_URL sprawdza się ttps://www.youtube.comjako ważny
Jeffz
1

Innym sposobem sprawdzenia, czy podany adres URL jest prawidłowy, jest próba uzyskania do niego dostępu, poniższa funkcja pobierze nagłówki z podanego adresu URL, zapewni to poprawność adresu URL ORAZ serwer sieciowy:

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
źródło
Dobry pomysł. To się nie powiedzie, jeśli serwer używa protokołu HTTP / 1.0 lub HTTP / 2.0 albo zwraca przekierowanie.
iblamefish
Tak, to jest punkt wyjścia, dalsze ulepszenia można łatwo wprowadzić.
Bud Damyanov
1

Pojawił się w tym artykule od 2012 roku. Uwzględnia zmienne, które mogą, ale nie muszą być zwykłymi adresami URL.

Autor artykułu, David Müeller , zapewnia tę funkcję, o której mówi: „... może być warta [sic]”, wraz z kilkoma przykładami filter_vari jej wadami.

/**
 * 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
źródło
0

jeśli ktoś jest zainteresowany używaniem cURL do walidacji. Możesz użyć następującego kodu.

<?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
źródło