webentwicklung-frage-antwort-db.com.de

Einfache Möglichkeit, eine URL für 404 in PHP zu testen?

Ich unterrichte mich selbst im grundlegenden Scraping und habe festgestellt, dass manchmal die URLs, die ich in meinen Code eingebe, den Wert 404 ergeben, der den gesamten Rest meines Codes zusammenfasst.

Ich brauche also einen Test am oberen Rand des Codes, um zu überprüfen, ob die URL 404 zurückgibt oder nicht.

Dies scheint eine ziemlich einfache Aufgabe zu sein, aber Google gibt mir keine Antworten. Ich mache mir Sorgen, ich suche nach den falschen Sachen.

Ein Blog hat mir empfohlen, dies zu benutzen:

$valid = @fsockopen($url, 80, $errno, $errstr, 30);

und dann testen, ob $ gültig ist, wenn leer oder nicht.

Aber ich denke, dass die URL, die mir Probleme bereitet, eine Umleitung enthält, sodass $ valid für alle Werte leer ist. Oder vielleicht mache ich etwas anderes falsch.

Ich habe auch eine "Kopfanfrage" geprüft, aber ich habe noch keine konkreten Codebeispiele gefunden, mit denen ich spielen oder ausprobieren kann.

Vorschläge? Und was ist das mit Locken?

144
bflora

Wenn Sie PHP's curl Bindings verwenden, können Sie den Fehlercode mit curl_getinfo als solche:

$handle = curl_init($url);
curl_setopt($handle,  CURLOPT_RETURNTRANSFER, TRUE);

/* Get the HTML or whatever is linked in $url. */
$response = curl_exec($handle);

/* Check for 404 (file not found). */
$httpCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
    /* Handle 404 here. */
}

curl_close($handle);

/* Handle $response here. */
261
strager

Wenn Sie PHP5 verwenden, können Sie Folgendes verwenden:

$url = 'http://www.example.com';
print_r(get_headers($url, 1));

Alternativ hat ein Benutzer mit php4 Folgendes beigetragen:

/**
This is a modified version of code from "stuart at sixletterwords dot com", at 14-Sep-2005 04:52. This version tries to emulate get_headers() function at PHP4. I think it works fairly well, and is simple. It is not the best emulation available, but it works.

Features:
- supports (and requires) full URLs.
- supports changing of default port in URL.
- stops downloading from socket as soon as end-of-headers is detected.

Limitations:
- only gets the root URL (see line with "GET / HTTP/1.1").
- don't support HTTPS (nor the default HTTPS port).
*/

if(!function_exists('get_headers'))
{
    function get_headers($url,$format=0)
    {
        $url=parse_url($url);
        $end = "\r\n\r\n";
        $fp = fsockopen($url['Host'], (empty($url['port'])?80:$url['port']), $errno, $errstr, 30);
        if ($fp)
        {
            $out  = "GET / HTTP/1.1\r\n";
            $out .= "Host: ".$url['Host']."\r\n";
            $out .= "Connection: Close\r\n\r\n";
            $var  = '';
            fwrite($fp, $out);
            while (!feof($fp))
            {
                $var.=fgets($fp, 1280);
                if(strpos($var,$end))
                    break;
            }
            fclose($fp);

            $var=preg_replace("/\r\n\r\n.*\$/",'',$var);
            $var=explode("\r\n",$var);
            if($format)
            {
                foreach($var as $i)
                {
                    if(preg_match('/^([a-zA-Z -]+): +(.*)$/',$i,$parts))
                        $v[$parts[1]]=$parts[2];
                }
                return $v;
            }
            else
                return $var;
        }
    }
}

Beide hätten ein ähnliches Ergebnis wie:

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
)

Daher können Sie einfach überprüfen, ob die Header-Antwort in Ordnung ist, z. B .:

$headers = get_headers($url, 1);
if ($headers[0] == 'HTTP/1.1 200 OK') {
//valid 
}

if ($headers[0] == 'HTTP/1.1 301 Moved Permanently') {
//moved or redirect page
}

W3C-Codes und Definitionen

98
Asciant

Mit dem Code von strager können Sie auch den CURLINFO_HTTP_CODE auf andere Codes überprüfen. Einige Websites melden kein 404, sondern leiten einfach auf eine benutzerdefinierte 404-Seite um und geben 302 (Weiterleitung) oder ähnliches zurück. Ich habe das benutzt, um zu prüfen, ob eine aktuelle Datei (zB robots.txt) auf dem Server existiert oder nicht. Natürlich würde diese Art von Datei keine Weiterleitung verursachen, wenn sie vorhanden wäre, aber wenn sie nicht vorhanden wäre, würde sie auf eine 404-Seite weiterleiten, die, wie ich bereits sagte, möglicherweise keinen 404-Code hat.

function is_404($url) {
    $handle = curl_init($url);
    curl_setopt($handle,  CURLOPT_RETURNTRANSFER, TRUE);

    /* Get the HTML or whatever is linked in $url. */
    $response = curl_exec($handle);

    /* Check for 404 (file not found). */
    $httpCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
    curl_close($handle);

    /* If the document has loaded successfully without any redirection or error */
    if ($httpCode >= 200 && $httpCode < 300) {
        return false;
    } else {
        return true;
    }
}
33
Aram Kocharyan

Sehen Sie sich die Verwendung von cURL an, wie es Strager vorschlägt. Sie könnten auch daran interessiert sein, CURLOPT_NOBODY mit curl_setopt festzulegen, um das Herunterladen der gesamten Seite zu überspringen (Sie möchten nur die Überschriften).

21
Beau Simensen

Wenn Sie auf der Suche nach einer einfachsten und schnellsten Lösung sind, können Sie in einem Durchgang PHP5 ausprobieren

file_get_contents('www.yoursite.com');
//and check by echoing
echo $http_response_header[0];
15
Nasaralla

Ich fand diese Antwort hier :

if(($Twitter_XML_raw=file_get_contents($timeline))==false){
    // Retrieve HTTP status code
    list($version,$status_code,$msg) = explode(' ',$http_response_header[0], 3);

    // Check the HTTP Status code
    switch($status_code) {
        case 200:
                $error_status="200: Success";
                break;
        case 401:
                $error_status="401: Login failure.  Try logging out and back in.  Password are ONLY used when posting.";
                break;
        case 400:
                $error_status="400: Invalid request.  You may have exceeded your rate limit.";
                break;
        case 404:
                $error_status="404: Not found.  This shouldn't happen.  Please let me know what happened using the feedback link above.";
                break;
        case 500:
                $error_status="500: Twitter servers replied with an error. Hopefully they'll be OK soon!";
                break;
        case 502:
                $error_status="502: Twitter servers may be down or being upgraded. Hopefully they'll be OK soon!";
                break;
        case 503:
                $error_status="503: Twitter service unavailable. Hopefully they'll be OK soon!";
                break;
        default:
                $error_status="Undocumented error: " . $status_code;
                break;
    }

Im Wesentlichen verwenden Sie die Methode "file get contents", um die URL abzurufen, die die HTTP-Antwortheader-Variable automatisch mit dem Statuscode auffüllt.

6
Ross

nachtrag: Diese drei Methoden wurden unter Berücksichtigung der Leistung getestet.

Das Ergebnis, zumindest in meiner Testumgebung:

Locke gewinnt

Dieser Test erfolgt unter der Überlegung, dass nur die Header (noBody) benötigt werden. Teste dich selbst:

$url = "http://de.wikipedia.org/wiki/Pinocchio";

$start_time = microtime(TRUE);
$headers = get_headers($url);
echo $headers[0]."<br>";
$end_time = microtime(TRUE);
echo $end_time - $start_time."<br>";


$start_time = microtime(TRUE);
$response = file_get_contents($url);
echo $http_response_header[0]."<br>";
$end_time = microtime(TRUE);
echo $end_time - $start_time."<br>";

$start_time = microtime(TRUE);
$handle = curl_init($url);
curl_setopt($handle,  CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($handle, CURLOPT_NOBODY, 1); // and *only* get the header 
/* Get the HTML or whatever is linked in $url. */
$response = curl_exec($handle);
/* Check for 404 (file not found). */
$httpCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
// if($httpCode == 404) {
    // /* Handle 404 here. */
// }
echo $httpCode."<br>";
curl_close($handle);
$end_time = microtime(TRUE);
echo $end_time - $start_time."<br>";
4
Email

Dies gibt true zurück, wenn url nicht 200 OK zurückgibt

function check_404($url) {
   $headers=get_headers($url, 1);
   if ($headers[0]!='HTTP/1.1 200 OK') return true; else return false;
}
2
Juergen

Als zusätzlichen Hinweis auf die großartig akzeptierte Antwort:

Bei der Verwendung einer Variante der vorgeschlagenen Lösung kam es aufgrund der PHP-Einstellung 'max_execution_time' zu Fehlern. Also habe ich folgendes getan:

set_time_limit(120);
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_NOBODY, true);
$result = curl_exec($curl);
set_time_limit(ini_get('max_execution_time'));
curl_close($curl);

Zuerst setze ich das Zeitlimit auf eine höhere Anzahl von Sekunden, dann setze ich es wieder auf den in den PHP-Einstellungen definierten Wert.

2
markus
<?php

$url= 'www.something.com';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, true);   
curl_setopt($ch, CURLOPT_NOBODY, true);    
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.4");
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_TIMEOUT,10);
curl_setopt($ch, CURLOPT_ENCODING, "gzip");
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
$output = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);


echo $httpcode;
?>

Sie können diesen Code auch verwenden, um den Status eines Links anzuzeigen:

<?php

function get_url_status($url, $timeout = 10) 
{
$ch = curl_init();
// set cURL options
$opts = array(CURLOPT_RETURNTRANSFER => true, // do not output to browser
            CURLOPT_URL => $url,            // set URL
            CURLOPT_NOBODY => true,         // do a HEAD request only
            CURLOPT_TIMEOUT => $timeout);   // set timeout
curl_setopt_array($ch, $opts);
curl_exec($ch); // do it!
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE); // find HTTP status
curl_close($ch); // close handle
echo $status; //or return $status;
    //example checking
    if ($status == '302') { echo 'HEY, redirection';}
}

get_url_status('http://yourpage.comm');
?>
1
T.Todua

Hier ist eine kurze Lösung.

$handle = curl_init($uri);
curl_setopt($handle,  CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($handle,CURLOPT_HTTPHEADER,array ("Accept: application/rdf+xml"));
curl_setopt($handle, CURLOPT_NOBODY, true);
curl_exec($handle);
$httpCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
if($httpCode == 200||$httpCode == 303) 
{
    echo "you might get a reply";
}
curl_close($handle);

In Ihrem Fall können Sie application/rdf+xml zu was auch immer Sie verwenden.

1
Andreas

das ist gerecht und ein Stück Code, die Hoffnung funktioniert für Sie

            $ch = @curl_init();
            @curl_setopt($ch, CURLOPT_URL, 'http://example.com');
            @curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1");
            @curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
            @curl_setopt($ch, CURLOPT_TIMEOUT, 10);

            $response       = @curl_exec($ch);
            $errno          = @curl_errno($ch);
            $error          = @curl_error($ch);

                    $response = $response;
                    $info = @curl_getinfo($ch);
return $info['http_code'];
0
gabriel

Um alle Fehler abzufangen: 4XX und 5XX, benutze ich dieses kleine Skript:

function URLIsValid($URL){
    $headers = @get_headers($URL);
    preg_match("/ [45][0-9]{2} /", (string)$headers[0] , $match);
    return count($match) === 0;
}
0
wawan