alguns sites têm uma $file_headers[0]página de erro diferente . por exemplo, youtube.com. sua página de erro tendo esse valor como HTTP/1.0 404 Not Found(a diferença é 1.0 e 1.1). o que fazer então?
Krishna Raj K
21
Talvez usando strpos($headers[0], '404 Not Found')pode fazer o truque
alexandru.topliceanu
12
@ Mark concordou! Para esclarecer, strpos($headers[0], '404')é melhor!
alexandru.topliceanu
1
@ karim79 ser cuidado de ataques SSRF e XSPA
M Rostami
55
Ao descobrir se existe um URL a partir do php, há algumas coisas a serem observadas:
O próprio URL é válido (uma string, não vazia, com boa sintaxe); é rápido verificar o lado do servidor.
Esperar por uma resposta pode levar tempo e bloquear a execução do código.
Nem todos os cabeçalhos retornados por get_headers () são bem formados.
Use enrolar (se você puder).
Evite buscar o corpo / conteúdo inteiro, mas solicite apenas os cabeçalhos.
Considere redirecionar URLs:
Deseja que o primeiro código seja retornado?
Ou siga todos os redirecionamentos e retorne o último código?
Você pode acabar com um 200, mas pode redirecionar usando metatags ou javascript. Descobrir o que acontece depois é difícil.
Lembre-se de que, independentemente do método usado, leva tempo para aguardar uma resposta.
Todo o código pode (e provavelmente será) parar até que você saiba o resultado ou o tempo limite das solicitações.
Por exemplo: o código abaixo pode demorar muito para exibir a página se os URLs forem inválidos ou inacessíveis:
<?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/>";}
As funções abaixo podem ser úteis, você provavelmente deseja modificá-las para atender às suas necessidades:
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 por ser a única resposta para lidar com redirecionamentos. Mudou o return $codea if($code == 200){return true;} return false;resolver apenas os sucessos
Birrel
@PKHunter: Não. Meu regex preg_match rápido foi um exemplo simples e não corresponderá a todos os URLs listados lá. Consulte este URL de teste: regex101.com/r/EpyDDc/2 Se você quiser um melhor, substitua-o pelo listado no seu link ( mathiasbynens.be/demo/url-regex ) da diegoperini; parece combinar com todos eles, consulte este link de teste: regex101.com/r/qMQp23/1
Como muitas pessoas pediram que o karim79 corrigisse a solução cURL, aqui está a solução que eu construí hoje.
/**
* 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;}
Deixe-me explicar as opções de ondulação:
CURLOPT_RETURNTRANSFER : retorna uma string em vez de exibir a página de chamada na tela.
CURLOPT_SSL_VERIFYPEER : cUrl não fará check-out do certificado
CURLOPT_HEADER : inclua o cabeçalho na string
CURLOPT_NOBODY : não inclua o corpo na string
CURLOPT_USERAGENT : alguns sites precisam disso para funcionar corretamente (por exemplo: https://plus.google.com )
Nota adicional : Nesta função, estou usando o regex de Diego Perini para validar a URL antes de enviar a solicitação:
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
Nota adicional 2 : Eu explodo a string do cabeçalho e os cabeçalhos do usuário [0] para ter certeza de validar apenas o código de retorno e a mensagem (exemplo: 200, 404, 405, etc.)
Nota adicional 3 : Às vezes, validar apenas o código 404 não é suficiente (consulte o teste de unidade); portanto, há um parâmetro $ failCodeList opcional para fornecer toda a lista de códigos a ser rejeitada.
E, claro, aqui está o teste de unidade (incluindo toda a rede social popular) para legitimar minha codificação:
eu recebo este exceptionn quando existe a url: Não foi possível chamar o CURLOPT_HEADERFUNCTION
safiot
3
Todas as soluções acima mencionadas + açúcar extra. (Solução Ultimate AIO)
/**
* 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');}
Aqui está uma solução que lê apenas o primeiro byte do código-fonte ... retornando false se o file_get_contents falhar ... Isso também funcionará para arquivos remotos como imagens.
function urlExists($url){if(@file_get_contents($url,false,NULL,0,1)){returntrue;}returnfalse;}
Outra maneira de verificar se um URL é válido ou não pode ser:
<?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 () retorna uma matriz com os cabeçalhos enviados pelo servidor em resposta a uma solicitação 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>';}
Uma coisa a considerar quando você verifica o cabeçalho para um 404 é o caso em que um site não gera um 404 imediatamente.
Muitos sites verificam se uma página existe ou não na fonte PHP / ASP (etc.) e o encaminham para uma página 404. Nesses casos, o cabeçalho é basicamente estendido pelo cabeçalho do 404 que é gerado. Nesses casos, o erro 404 não está na primeira linha do cabeçalho, mas na décima.
Realizo alguns testes para verificar se os links do meu site são válidos - me avisa quando terceiros alteram seus links. Eu estava tendo um problema com um site que tinha um certificado mal configurado que significava que os get_headers do php não funcionavam.
Então, li que o enrolamento era mais rápido e decidi tentar. tive um problema com o linkedin que me deu um erro 999, que acabou sendo um problema de agente do usuário.
Não me importei se o certificado não era válido para este teste e não me importei se a resposta foi redirecionada.
Então imaginei usar get_headers de qualquer maneira, se o curl estivesse falhando ....
Dê uma chance....
/**
* 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, obviamente, não está em -2. Eu provavelmente publicado esta tarde da noite quando eu estava meio dormindo após olhando para telas de todo o dia ..
Respostas:
Aqui:
A partir daqui e logo abaixo da postagem acima, há uma solução de ondulação :
fonte
$file_headers[0]
página de erro diferente . por exemplo, youtube.com. sua página de erro tendo esse valor comoHTTP/1.0 404 Not Found
(a diferença é 1.0 e 1.1). o que fazer então?strpos($headers[0], '404 Not Found')
pode fazer o truquestrpos($headers[0], '404')
é melhor!Ao descobrir se existe um URL a partir do php, há algumas coisas a serem observadas:
Lembre-se de que, independentemente do método usado, leva tempo para aguardar uma resposta.
Todo o código pode (e provavelmente será) parar até que você saiba o resultado ou o tempo limite das solicitações.
Por exemplo: o código abaixo pode demorar muito para exibir a página se os URLs forem inválidos ou inacessíveis:
As funções abaixo podem ser úteis, você provavelmente deseja modificá-las para atender às suas necessidades:
fonte
return $code
aif($code == 200){return true;} return false;
resolver apenas os sucessossempre que você entrar em contato com um site e obter algo além de 200, ok, ele funcionará
fonte
return strpos(@get_headers($url)[0],'200') === false ? false : true
. Pode ser útil.você não pode usar curl em certos servidores u pode usar esse código
fonte
fonte
fonte
Eu uso esta função:
fonte
A solução get_headers () de karim79 não funcionou para mim, pois obtive resultados loucos com o Pinterest.
De qualquer forma, esse desenvolvedor demonstra que o cURL é muito mais rápido que o get_headers ():
http://php.net/manual/fr/function.get-headers.php#104723
Como muitas pessoas pediram que o karim79 corrigisse a solução cURL, aqui está a solução que eu construí hoje.
Deixe-me explicar as opções de ondulação:
CURLOPT_RETURNTRANSFER : retorna uma string em vez de exibir a página de chamada na tela.
CURLOPT_SSL_VERIFYPEER : cUrl não fará check-out do certificado
CURLOPT_HEADER : inclua o cabeçalho na string
CURLOPT_NOBODY : não inclua o corpo na string
CURLOPT_USERAGENT : alguns sites precisam disso para funcionar corretamente (por exemplo: https://plus.google.com )
Nota adicional : Nesta função, estou usando o regex de Diego Perini para validar a URL antes de enviar a solicitação:
Nota adicional 2 : Eu explodo a string do cabeçalho e os cabeçalhos do usuário [0] para ter certeza de validar apenas o código de retorno e a mensagem (exemplo: 200, 404, 405, etc.)
Nota adicional 3 : Às vezes, validar apenas o código 404 não é suficiente (consulte o teste de unidade); portanto, há um parâmetro $ failCodeList opcional para fornecer toda a lista de códigos a ser rejeitada.
E, claro, aqui está o teste de unidade (incluindo toda a rede social popular) para legitimar minha codificação:
Grande sucesso para todos,
Jonathan Parent-Lévesque de Montreal
fonte
fonte
muito rápido:
fonte
Todas as soluções acima mencionadas + açúcar extra. (Solução Ultimate AIO)
Exemplo:
fonte
para verificar se o URL está online ou offline ---
fonte
fonte
Aqui está uma solução que lê apenas o primeiro byte do código-fonte ... retornando false se o file_get_contents falhar ... Isso também funcionará para arquivos remotos como imagens.
fonte
a maneira simples é enrolar (e mais rápido também)
fonte
Outra maneira de verificar se um URL é válido ou não pode ser:
fonte
get_headers () retorna uma matriz com os cabeçalhos enviados pelo servidor em resposta a uma solicitação HTTP.
fonte
cURL pode retornar código HTTP Eu não acho que todo esse código extra seja necessário?
fonte
Uma coisa a considerar quando você verifica o cabeçalho para um 404 é o caso em que um site não gera um 404 imediatamente.
Muitos sites verificam se uma página existe ou não na fonte PHP / ASP (etc.) e o encaminham para uma página 404. Nesses casos, o cabeçalho é basicamente estendido pelo cabeçalho do 404 que é gerado. Nesses casos, o erro 404 não está na primeira linha do cabeçalho, mas na décima.
fonte
Realizo alguns testes para verificar se os links do meu site são válidos - me avisa quando terceiros alteram seus links. Eu estava tendo um problema com um site que tinha um certificado mal configurado que significava que os get_headers do php não funcionavam.
Então, li que o enrolamento era mais rápido e decidi tentar. tive um problema com o linkedin que me deu um erro 999, que acabou sendo um problema de agente do usuário.
Não me importei se o certificado não era válido para este teste e não me importei se a resposta foi redirecionada.
Então imaginei usar get_headers de qualquer maneira, se o curl estivesse falhando ....
Dê uma chance....
fonte
tipo de um tópico antigo, mas .. eu faço isso:
fonte