certains sites Web ont une $file_headers[0]page d'erreur différente . par exemple, youtube.com. sa page d'erreur ayant cette valeur comme HTTP/1.0 404 Not Found(la différence est 1,0 et 1,1). que faire alors?
Krishna Raj K
21
Peut-être que l'utilisation strpos($headers[0], '404 Not Found')pourrait faire l'affaire
alexandru.topliceanu
12
@Mark est d'accord! Pour clarifier, strpos($headers[0], '404')c'est mieux!
alexandru.topliceanu
1
@ karim79 attention aux attaques SSRF et XSPA
M Rostami
55
Lorsque vous déterminez si une URL existe depuis php, il y a quelques points à prendre en compte:
Est-ce que l'url elle-même est valide (une chaîne, pas vide, bonne syntaxe), c'est rapide à vérifier côté serveur.
Attendre une réponse peut prendre du temps et bloquer l'exécution du code.
Tous les en-têtes renvoyés par get_headers () ne sont pas bien formés.
Utilisez curl (si vous le pouvez).
Empêchez de récupérer tout le corps / contenu, mais ne demandez que les en-têtes.
Pensez à rediriger les URL:
Voulez-vous que le premier code soit renvoyé?
Ou suivre toutes les redirections et renvoyer le dernier code?
Vous pourriez vous retrouver avec un 200, mais il pourrait rediriger à l'aide de balises méta ou de javascript. Il est difficile de comprendre ce qui se passe après.
Gardez à l'esprit que quelle que soit la méthode que vous utilisez, il faut du temps pour attendre une réponse.
Tout le code peut (et le fera probablement) s'arrêter jusqu'à ce que vous connaissiez le résultat ou que les requêtes aient expiré.
Par exemple: le code ci-dessous peut mettre LONGTEMPS à afficher la page si les URL sont invalides ou inaccessibles:
<?php
$urls = getUrls();// some function getting say 10 or more external linksforeach($urls as $k=>$url){// this could potentially take 0-30 seconds each// (more or less depending on connection, target site, timeout settings...)if(! isValidUrl($url)){
unset($urls[$k]);}}
echo "yay all done! now show my site";foreach($urls as $url){
echo "<a href=\"{$url}\">{$url}</a><br/>";}
Les fonctions ci-dessous pourraient être utiles, vous souhaiterez probablement les modifier en fonction de vos besoins:
function isValidUrl($url){// first do some quick sanity checks:if(!$url ||!is_string($url)){returnfalse;}// quick check url is roughly a valid http request: ( http://blah/... ) if(! preg_match('/^http(s)?:\/\/[a-z0-9-]+(\.[a-z0-9-]+)*(:[0-9]+)?(\/.*)?$/i', $url)){returnfalse;}// the next bit could be slow:if(getHttpResponseCode_using_curl($url)!=200){// if(getHttpResponseCode_using_getheaders($url) != 200){ // use this one if you cant use curlreturnfalse;}// all good!returntrue;}function getHttpResponseCode_using_curl($url, $followredirects =true){// returns int responsecode, or false (if url does not exist or connection timeout occurs)// NOTE: could potentially take up to 0-30 seconds , blocking further code execution (more or less depending on connection, target site, and local timeout settings))// if $followredirects == false: return the FIRST known httpcode (ignore redirects)// if $followredirects == true : return the LAST known httpcode (when redirected)if(! $url ||! is_string($url)){returnfalse;}
$ch =@curl_init($url);if($ch ===false){returnfalse;}@curl_setopt($ch, CURLOPT_HEADER ,true);// we want headers@curl_setopt($ch, CURLOPT_NOBODY ,true);// dont need body@curl_setopt($ch, CURLOPT_RETURNTRANSFER ,true);// catch output (do NOT print!)if($followredirects){@curl_setopt($ch, CURLOPT_FOLLOWLOCATION ,true);@curl_setopt($ch, CURLOPT_MAXREDIRS ,10);// fairly random number, but could prevent unwanted endless redirects with followlocation=true}else{@curl_setopt($ch, CURLOPT_FOLLOWLOCATION ,false);}// @curl_setopt($ch, CURLOPT_CONNECTTIMEOUT ,5); // fairly random number (seconds)... but could prevent waiting forever to get a result// @curl_setopt($ch, CURLOPT_TIMEOUT ,6); // fairly random number (seconds)... but could prevent waiting forever to get a result// @curl_setopt($ch, CURLOPT_USERAGENT ,"Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1"); // pretend we're a regular browser@curl_exec($ch);if(@curl_errno($ch)){// should be 0@curl_close($ch);returnfalse;}
$code =@curl_getinfo($ch, CURLINFO_HTTP_CODE);// note: php.net documentation shows this returns a string, but really it returns an int@curl_close($ch);return $code;}function getHttpResponseCode_using_getheaders($url, $followredirects =true){// returns string responsecode, or false if no responsecode found in headers (or url does not exist)// NOTE: could potentially take up to 0-30 seconds , blocking further code execution (more or less depending on connection, target site, and local timeout settings))// if $followredirects == false: return the FIRST known httpcode (ignore redirects)// if $followredirects == true : return the LAST known httpcode (when redirected)if(! $url ||! is_string($url)){returnfalse;}
$headers =@get_headers($url);if($headers && is_array($headers)){if($followredirects){// we want the the last errorcode, reverse array so we start at the end:
$headers = array_reverse($headers);}foreach($headers as $hline){// search for things like "HTTP/1.1 200 OK" , "HTTP/1.0 200 OK" , "HTTP/1.1 301 PERMANENTLY MOVED" , "HTTP/1.1 400 Not Found" , etc.// note that the exact syntax/version/output differs, so there is some string magic involved hereif(preg_match('/^HTTP\/\S+\s+([1-9][0-9][0-9])\s+.*/', $hline, $matches)){// "HTTP/*** ### ***"
$code = $matches[1];return $code;}}// no HTTP/xxx found in headers:returnfalse;}// no headers :returnfalse;}
+1 pour être la seule réponse pour traiter les redirections. Changé le return $codepour if($code == 200){return true;} return false;trier uniquement les succès
Birrel
@PKHunter: Non. Mon expression régulière preg_match rapide était un exemple simple et ne correspondra pas à toutes les URL listées ici. Voir cette url de test: regex101.com/r/EpyDDc/2 Si vous en voulez une meilleure, remplacez-la par celle répertoriée sur votre lien ( mathiasbynens.be/demo/url-regex ) de diegoperini; il semble correspondre à tous, voir ce lien de test: regex101.com/r/qMQp23/1
Étant donné que de nombreuses personnes ont demandé que karim79 répare sa solution cURL, voici la solution que j'ai construite aujourd'hui.
/**
* Send an HTTP request to a the $url and check the header posted back.
*
* @param $url String url to which we must send the request.
* @param $failCodeList Int array list of code for which the page is considered invalid.
*
* @return Boolean
*/publicstaticfunction isUrlExists($url, array $failCodeList = array(404)){
$exists =false;if(!StringManager::stringStartWith($url,"http")and!StringManager::stringStartWith($url,"ftp")){
$url ="https://". $url;}if(preg_match(RegularExpression::URL, $url)){
$handle = curl_init($url);
curl_setopt($handle, CURLOPT_RETURNTRANSFER,true);
curl_setopt($handle, CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($handle, CURLOPT_HEADER,true);
curl_setopt($handle, CURLOPT_NOBODY,true);
curl_setopt($handle, CURLOPT_USERAGENT,true);
$headers = curl_exec($handle);
curl_close($handle);if(empty($failCodeList)or!is_array($failCodeList)){
$failCodeList = array(404);}if(!empty($headers)){
$exists =true;
$headers = explode(PHP_EOL, $headers);foreach($failCodeList as $code){if(is_numeric($code)and strpos($headers[0], strval($code))!==false){
$exists =false;break;}}}}return $exists;}
Laissez-moi vous expliquer les options de curl:
CURLOPT_RETURNTRANSFER : renvoie une chaîne au lieu d'afficher la page appelante à l'écran.
CURLOPT_SSL_VERIFYPEER : cUrl ne récupérera pas le certificat
CURLOPT_HEADER : inclure l'en-tête dans la chaîne
CURLOPT_NOBODY : ne pas inclure le corps dans la chaîne
CURLOPT_USERAGENT : certains sites en ont besoin pour fonctionner correctement (par exemple: https://plus.google.com )
Note supplémentaire : Dans cette fonction, j'utilise l'expression régulière de Diego Perini pour valider l'URL avant d'envoyer la requête:
const URL ="%^(?:(?:https?|ftp)://)(?:\S+(?::\S*)?@|\d{1,3}(?:\.\d{1,3}){3}|(?:(?:[a-z\d\x{00a1}-\x{ffff}]+-?)*[a-z\d\x{00a1}-\x{ffff}]+)(?:\.(?:[a-z\d\x{00a1}-\x{ffff}]+-?)*[a-z\d\x{00a1}-\x{ffff}]+)*(?:\.[a-z\x{00a1}-\x{ffff}]{2,6}))(?::\d+)?(?:[^\s]*)?$%iu";//@copyright Diego Perini
Note complémentaire 2 : j'explose la chaîne d'en-tête et les en-têtes utilisateur [0] pour être sûr de ne valider que le code retour et le message (exemple: 200, 404, 405, etc.)
Note supplémentaire 3 : Parfois, valider uniquement le code 404 ne suffit pas (voir le test unitaire), il existe donc un paramètre facultatif $ failCodeList pour fournir toute la liste de codes à rejeter.
Et, bien sûr, voici le test unitaire (y compris tout le réseau social populaire) pour légitimer mon codage:
Toutes les solutions ci-dessus + sucre supplémentaire. (Solution AIO ultime)
/**
* Check that given URL is valid and exists.
* @param string $url URL to check
* @return bool TRUE when valid | FALSE anyway
*/function urlExists ( $url ){// Remove all illegal characters from a url
$url = filter_var($url, FILTER_SANITIZE_URL);// Validate URIif(filter_var($url, FILTER_VALIDATE_URL)=== FALSE
// check only for http/https schemes.||!in_array(strtolower(parse_url($url, PHP_URL_SCHEME)),['http','https'],true)){returnfalse;}// Check that URL exists
$file_headers =@get_headers($url);return!(!$file_headers || $file_headers[0]==='HTTP/1.1 404 Not Found');}
Voici une solution qui ne lit que le premier octet du code source ... renvoyant false si le file_get_contents échoue ... Cela fonctionnera également pour les fichiers distants comme les images.
function urlExists($url){if(@file_get_contents($url,false,NULL,0,1)){returntrue;}returnfalse;}
Une autre façon de vérifier si une URL est valide ou non peut être:
<?php
if(isValidURL("http://www.gimepix.com")){
echo "URL is valid...";}else{
echo "URL is not valid...";}function isValidURL($url){
$file_headers =@get_headers($url);if(strpos($file_headers[0],"200 OK")>0){returntrue;}else{returnfalse;}}?>
get_headers () retourne un tableau avec les en-têtes envoyés par le serveur en réponse à une requête HTTP.
$image_path ='https://your-domain.com/assets/img/image.jpg';
$file_headers =@get_headers($image_path);//Prints the response out in an array//print_r($file_headers); if($file_headers[0]=='HTTP/1.1 404 Not Found'){
echo 'Failed because path does not exist.</br>';}else{
echo 'It works. Your good to go!</br>';}
Une chose à prendre en compte lorsque vous vérifiez l'en-tête d'un 404 est le cas où un site ne génère pas immédiatement un 404.
De nombreux sites vérifient si une page existe ou non dans la source PHP / ASP (et cetera) et vous redirigent vers une page 404. Dans ces cas, l'en-tête est essentiellement étendu par l'en-tête du 404 qui est généré. Dans ces cas, l'erreur 404 n'est pas dans la première ligne de l'en-tête, mais dans la dixième.
J'exécute des tests pour voir si les liens sur mon site sont valides - m'alerte lorsque des tiers modifient leurs liens. J'avais un problème avec un site qui avait un certificat mal configuré qui signifiait que les get_headers de php ne fonctionnaient pas.
Donc, j'ai lu que curl était plus rapide et j'ai décidé de l'essayer. puis j'ai eu un problème avec linkedin qui m'a donné une erreur 999, qui s'est avérée être un problème d'agent utilisateur.
Je m'en fichais si le certificat n'était pas valide pour ce test, et je m'en fichais si la réponse était une redirection.
Ensuite, j'ai pensé utiliser get_headers de toute façon si curl échouait ...
Essayez....
/**
* returns true/false if the $url is present.
*
* @param string $url assumes this is a valid url.
*
* @return bool
*/privatefunction url_exists (string $url):bool{
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_NOBODY, TRUE);// this does a head request to make it faster.
curl_setopt($ch, CURLOPT_HEADER, TRUE);// just the headers
curl_setopt($ch, CURLOPT_SSL_VERIFYSTATUS, FALSE);// turn off that pesky ssl stuff - some sys admins can't get it right.
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);// set a real user agent to stop linkedin getting upset.
curl_setopt($ch, CURLOPT_USERAGENT,'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36');
curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);if(($http_code >= HTTP_OK && $http_code < HTTP_BAD_REQUEST)|| $http_code ===999){
curl_close($ch);return TRUE;}
$error = curl_error($ch);// used for debugging.
curl_close($ch);// just try the get_headers - it might work!
stream_context_set_default(array('http'=> array('method'=>'HEAD')));
$file_headers =@get_headers($url);if($file_headers){
$response_code = substr($file_headers[0],9,3);return $response_code >=200&& $response_code <400;}return FALSE;}
@Jah c'est évidemment pas c'est à -2. J'ai probablement posté ça tard dans la nuit alors que j'étais à moitié endormi après avoir regardé des écrans toute la journée ..
Réponses:
Ici:
À partir d' ici et juste en dessous du post ci -dessus, il existe une solution curl :
la source
$file_headers[0]
page d'erreur différente . par exemple, youtube.com. sa page d'erreur ayant cette valeur commeHTTP/1.0 404 Not Found
(la différence est 1,0 et 1,1). que faire alors?strpos($headers[0], '404 Not Found')
pourrait faire l'affairestrpos($headers[0], '404')
c'est mieux!Lorsque vous déterminez si une URL existe depuis php, il y a quelques points à prendre en compte:
Gardez à l'esprit que quelle que soit la méthode que vous utilisez, il faut du temps pour attendre une réponse.
Tout le code peut (et le fera probablement) s'arrêter jusqu'à ce que vous connaissiez le résultat ou que les requêtes aient expiré.
Par exemple: le code ci-dessous peut mettre LONGTEMPS à afficher la page si les URL sont invalides ou inaccessibles:
Les fonctions ci-dessous pourraient être utiles, vous souhaiterez probablement les modifier en fonction de vos besoins:
la source
return $code
pourif($code == 200){return true;} return false;
trier uniquement les succèsdonc chaque fois que vous contactez un site Web et obtenez autre chose que 200 ok, cela fonctionnera
la source
return strpos(@get_headers($url)[0],'200') === false ? false : true
. Cela pourrait être utile.vous ne pouvez pas utiliser curl sur certains serveurs vous pouvez utiliser ce code
la source
la source
la source
J'utilise cette fonction:
la source
La solution get_headers () de karim79 n'a pas fonctionné pour moi car j'ai obtenu des résultats fous avec Pinterest.
Quoi qu'il en soit, ce développeur démontre que cURL est bien plus rapide que get_headers ():
http://php.net/manual/fr/function.get-headers.php#104723
Étant donné que de nombreuses personnes ont demandé que karim79 répare sa solution cURL, voici la solution que j'ai construite aujourd'hui.
Laissez-moi vous expliquer les options de curl:
CURLOPT_RETURNTRANSFER : renvoie une chaîne au lieu d'afficher la page appelante à l'écran.
CURLOPT_SSL_VERIFYPEER : cUrl ne récupérera pas le certificat
CURLOPT_HEADER : inclure l'en-tête dans la chaîne
CURLOPT_NOBODY : ne pas inclure le corps dans la chaîne
CURLOPT_USERAGENT : certains sites en ont besoin pour fonctionner correctement (par exemple: https://plus.google.com )
Note supplémentaire : Dans cette fonction, j'utilise l'expression régulière de Diego Perini pour valider l'URL avant d'envoyer la requête:
Note complémentaire 2 : j'explose la chaîne d'en-tête et les en-têtes utilisateur [0] pour être sûr de ne valider que le code retour et le message (exemple: 200, 404, 405, etc.)
Note supplémentaire 3 : Parfois, valider uniquement le code 404 ne suffit pas (voir le test unitaire), il existe donc un paramètre facultatif $ failCodeList pour fournir toute la liste de codes à rejeter.
Et, bien sûr, voici le test unitaire (y compris tout le réseau social populaire) pour légitimer mon codage:
Grand succès à tous,
Jonathan Parent-Lévesque de Montréal
la source
la source
assez vite:
la source
Toutes les solutions ci-dessus + sucre supplémentaire. (Solution AIO ultime)
Exemple:
la source
pour vérifier si l'URL est en ligne ou hors ligne ---
la source
la source
Voici une solution qui ne lit que le premier octet du code source ... renvoyant false si le file_get_contents échoue ... Cela fonctionnera également pour les fichiers distants comme les images.
la source
la manière simple est de boucler (et plus rapide aussi)
la source
Une autre façon de vérifier si une URL est valide ou non peut être:
la source
get_headers () retourne un tableau avec les en-têtes envoyés par le serveur en réponse à une requête HTTP.
la source
cURL peut renvoyer du code HTTP Je ne pense pas que tout ce code supplémentaire soit nécessaire?
la source
Une chose à prendre en compte lorsque vous vérifiez l'en-tête d'un 404 est le cas où un site ne génère pas immédiatement un 404.
De nombreux sites vérifient si une page existe ou non dans la source PHP / ASP (et cetera) et vous redirigent vers une page 404. Dans ces cas, l'en-tête est essentiellement étendu par l'en-tête du 404 qui est généré. Dans ces cas, l'erreur 404 n'est pas dans la première ligne de l'en-tête, mais dans la dixième.
la source
J'exécute des tests pour voir si les liens sur mon site sont valides - m'alerte lorsque des tiers modifient leurs liens. J'avais un problème avec un site qui avait un certificat mal configuré qui signifiait que les get_headers de php ne fonctionnaient pas.
Donc, j'ai lu que curl était plus rapide et j'ai décidé de l'essayer. puis j'ai eu un problème avec linkedin qui m'a donné une erreur 999, qui s'est avérée être un problème d'agent utilisateur.
Je m'en fichais si le certificat n'était pas valide pour ce test, et je m'en fichais si la réponse était une redirection.
Ensuite, j'ai pensé utiliser get_headers de toute façon si curl échouait ...
Essayez....
la source
sorte d'un vieux fil, mais .. je fais ceci:
la source