Un modo semplice per testare un URL per 404 in PHP?
-
03-07-2019 - |
Domanda
Mi sto insegnando un po 'di raschiatura di base e ho scoperto che a volte l'URL che inserisco nel mio codice restituisce 404, il che fa impazzire tutto il resto del mio codice.
Quindi ho bisogno di un test nella parte superiore del codice per verificare se l'URL restituisce 404 o meno.
Sembrerebbe un compito piuttosto diretto, ma Google non mi sta dando alcuna risposta. Temo di cercare cose sbagliate.
Un blog mi consiglia di utilizzare questo:
$valid = @fsockopen($url, 80, $errno, $errstr, 30);
e quindi prova per vedere se $ valido se vuoto o meno.
Ma penso che l'URL che mi sta dando problemi abbia un reindirizzamento su di esso, quindi $ valid sta diventando vuoto per tutti i valori. O forse sto sbagliando qualcos'altro.
Ho anche esaminato una richiesta "testa" " ma devo ancora trovare esempi di codice reali con cui posso giocare o provare.
Suggerimenti? E di cosa si tratta il ricciolo?
Soluzione
Se stai usando i collegamenti curl
di PHP , puoi controllare il codice di errore usando curl_getinfo
come tale:
$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. */
Altri suggerimenti
Se stai utilizzando php5 puoi usare:
$url = 'http://www.example.com';
print_r(get_headers($url, 1));
In alternativa con php4 un utente ha contribuito con:
/**
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;
}
}
}
Entrambi avrebbero un risultato simile a:
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
)
Pertanto, è possibile verificare che la risposta dell'intestazione sia corretta, ad esempio:
$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
}
Con il codice dello strager, puoi anche controllare CURLINFO_HTTP_CODE per altri codici. Alcuni siti Web non riportano un 404, ma semplicemente reindirizzano a una pagina 404 personalizzata e restituiscono 302 (reindirizzamento) o qualcosa di simile. Ho usato questo per verificare se sul server esisteva o meno un file reale (es. Robots.txt). Chiaramente questo tipo di file non provocherebbe un reindirizzamento se esistesse, ma in caso contrario reindirizzerebbe a una pagina 404, che come ho detto prima potrebbe non avere un codice 404.
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;
}
}
Come suggerisce strager, guarda usando cURL. Potresti anche essere interessato a impostare CURLOPT_NOBODY con curl_setopt per saltare il download dell'intero pagina (vuoi solo le intestazioni).
Se stai cercando una soluzione più semplice e quella che puoi provare in una volta, vai su php5
file_get_contents('www.yoursite.com');
//and check by echoing
echo $http_response_header[0];
Ho trovato questa risposta qui :
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;
}
In sostanza, usi il file " ottieni contenuti " metodo per recuperare l'URL, che popola automaticamente la variabile di intestazione della risposta http con il codice di stato.
addendum; testato quei 3 metodi considerando le prestazioni.
Il risultato, almeno nel mio ambiente di test:
Il ricciolo vince
Questo test viene eseguito considerando che sono necessarie solo le intestazioni (noBody). Mettiti alla prova:
$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>";
Come ulteriore suggerimento per l'ottima risposta accettata:
Quando utilizzo una variante della soluzione proposta, ho ricevuto degli errori a causa dell'impostazione php 'max_execution_time'. Quindi quello che ho fatto è stato il seguente:
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);
Per prima cosa ho impostato il limite di tempo su un numero maggiore di secondi, alla fine l'ho riportato al valore definito nelle impostazioni php.
<?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;
?>
Questo ti darà vero se l'URL non restituisce 200 OK
function check_404($url) {
$headers=get_headers($url, 1);
if ($headers[0]!='HTTP/1.1 200 OK') return true; else return false;
}
Puoi usare anche questo codice per vedere lo stato di qualsiasi link:
<?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');
?>
Ecco una soluzione breve.
$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);
Nel tuo caso, puoi cambiare application / rdf + xml
in qualunque cosa tu usi.
questo è solo una porzione di codice, la speranza funziona per te
$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'];
Per rilevare tutti gli errori: 4XX e 5XX, utilizzo questo piccolo script:
function URLIsValid($URL){
$headers = @get_headers($URL);
preg_match("/ [45][0-9]{2} /", (string)$headers[0] , $match);
return count($match) === 0;
}