[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Проверка "битых" линков наподобие badlinks.ru
FatCat
Набросал "на коленке". Если на странице не линки на скачивание дивидюков, то даже не очень долго работает и не дюже жрет трафик.
И все же, рекомендую гонять под денвером или под другим локальным сервером, хостеру может не понравиться большой входящий трафик.

Свернутый текст
PHP
define('TIME_LIMIT', 0);
$is_safe_mode = ini_get('safe_mode') == '1' ? 1 : 0;
if (!$is_safe_mode && function_exists('set_time_limit')) set_time_limit(TIME_LIMIT);

header("Expires: Tue, 1 Jul 2003 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Pragma: no-cache");

if(
 !isSet($_GET['test']) )$_GET['test'] = "";

if(
$_GET['test'] == "")$output = "<h2 align=\"center\">Поиск &quot;битых&quot; линков:</h2>".first_form();
else
{
    $output = get_objects($_GET['test'])."<h2 align=\"center\">Новый поиск:</h2>".first_form();
}

echo '<html>
<head>
<title>Поиск &quot;битых&quot; линков и потерянных имиджей</title>
</head>
<body>
'
.$output.'
</body>
</html>'
;

function first_form()
{
    return '<form action=""><div align="center">
    <strong>URL проверяемой страницы</strong>:&nbsp;<input type="text" name="test" id="test" value="http://" size="37" maxlength="128">
    <input type="submit" value="Проверить!">
    <br>(URL должен заканчиваться знаком "/" или именем файла)</div></form>'
;
}

function get_objects($url)
{
    $text = file_get_contents($url);
    $text = str_replace("''","",$text);
    $text = str_replace("\"\"","",$text);
    $links = array();
    
    
// Поиск для конструкций src="..."
    preg_match_all("/src=\"(.+?)\"/is",$text,$tmp_links);
    while(count($tmp_links[0]))
    {
        $links = array_merge($links,$tmp_links[1]);    // добавляем свеженайденые URL в список
        $text = str_replace($tmp_links[0],$tmp_links[1],$text);    // убираем найденые URL из текста
        $text = str_replace("src=\"\"","",$text);
        preg_match_all("/src=\"(.+?)\"/is",$text,$tmp_links);  // продолжаем поиск
    }
    // Повторяем поиск для конструкций src='...'
    preg_match_all("/src='(.+?)'/is",$text,$tmp_links);
    while(count($tmp_links[0]))
    {
        $links = array_merge($links,$tmp_links[1]);
        $text = str_replace($tmp_links[0],$tmp_links[1],$text);
        $text = str_replace("src=''","",$text);
        preg_match_all("/src='(.+?)'/is",$text,$tmp_links);
    }
    // Повторяем поиск для конструкций href="..."
    preg_match_all("/href=\"(.+?)\"/is",$text,$tmp_links);
    while(count($tmp_links[0]))
    {
        $links = array_merge($links,$tmp_links[1]);
        $text = str_replace($tmp_links[0],$tmp_links[1],$text);
        $text = str_replace("src=\"\"","",$text);
        preg_match_all("/href=\"(.+?)\"/is",$text,$tmp_links);
    }
    // Повторяем поиск для конструкций href='...'
    preg_match_all("/href='(.+?)'/is",$text,$tmp_links);
    while(count($tmp_links[0]))
    {
        $links = array_merge($links,$tmp_links[1]);
        $text = str_replace($tmp_links[0],$tmp_links[1],$text);
        $text = str_replace("src=''","",$text);
        preg_match_all("/href='(.+?)'/is",$text,$tmp_links);
    }
    
    $base_href 
= explode("/",$_GET['test']);
    $base_href[(count($base_href)-1)] = "";
    $base_href = implode("/",$base_href);
    
    $links_cleaned 
= Array();
    foreach($links as $link)
    {
        $href = $base_href;
        while( substr($link,0,3)=="../" )
        {
            $link = substr($link,3);
            $href = substr($base_href,0,-1);
            
            $href 
= explode("/",$href);
            $href[(count($href)-1)] = "";
            $href = implode("/",$href);
        }
        if(substr($link,0,7)!="http://")$link = $href.$link;
        $link = str_replace("/./","/",$link);
        if(
        !stristr($link,"javascript:")
        and !stristr($link,"(")
        and !stristr($link,"+")
        and !stristr($link,"mailto:")
        )
        $links_cleaned[] = $link;
    }
    
    $links_cleaned 
= array_unique($links_cleaned);
    error_reporting(0);
    $links = array();
    foreach($links_cleaned as $link)
    {
        $text = file_get_contents($link);
        if( strlen($text)>)$links[] = "<font color=\"#008000\">".$link."</font>";
        else $links[] = "<font color=\"#FF0000\"><strong>".$link."</strong> (битая ссылка)</font>";
    }
    return implode("<br>",$links);
}


Проблемный кусок:
PHP
foreach($links_cleaned as $link)
    {
        $text = file_get_contents($link);

А если на странице линк на скачивание дивидюка с ФТП?
Может будут идеи, чем можно проверить линк на "живость" не скачивая весь контент линка?



Спустя 2 минуты, 3 секунды (5.05.2009 - 17:14) waldicom написал(а):
У меня идея: использовать метод HEAD? Вожможная проблема: теоретически у веб-червера может быть выключена поддержка HEAD (или наткнемся на такой сервер, который это вооще не умеет).

Спустя 1 минута, 14 секунд (5.05.2009 - 17:16) FatCat написал(а):
blink.gif
Что за пхп-функция такая?

Спустя 2 минуты, 1 секунда (5.05.2009 - 17:18) waldicom написал(а):
Не... Есть GET, HEAD, PUT и DELETE. Так вот юзать это тсамый HEAD.

А общий вариант - проверять заголовок, который ворачивает удаленная страница.

http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

Спустя 3 минуты, 36 секунд (5.05.2009 - 17:21) waldicom написал(а):

Спустя 11 минут, 49 секунд (5.05.2009 - 17:33) FatCat написал(а):
Это я понимаю.
Не понимаю, как средствами пхп запросить заголовок, а не сам файл. Потому и спросил о функции пхп, которая бы запрашивала по методу "HEAD".

Спустя 6 минут, 25 секунд (5.05.2009 - 17:39) waldicom написал(а):
сокеты?

Спустя 4 минуты, 49 секунд (5.05.2009 - 17:44) FatCat написал(а):
Не представляю себе, как оно реализуется через сокеты.
Ломал голову, как получить ответ сервера; если не 404-й и т.д., то линк жив... Но пока что-то ничего не могу придумать и нагуглить не получается... sad.gif

Спустя 7 минут, 39 секунд (5.05.2009 - 17:52) waldicom написал(а):
Цитата
Не представляю себе, как оно реализуется через сокеты.

Это довольно просто. Используем функции fsockopen()

Там на странице есть примеры, которые помогут.


Примерчик:

PHP
<?php
    $fp 
= fsockopen('localhost', // 127.0.0.1
                    80,          // Port 80 (HTTP)
                    $errno,    // errorno
                    $error,    // error msg
                    5)           // Timeout sec
          OR                    // or die
          die(                   
              $error
.          
              
"(".               
              $errno
.         
              
")"                
          
);
    fwrite($fp, "HEAD / HTTP/1.0\r\n");
    fwrite($fp, "\r\n"); // Request beenden
    header('Content-Type: text/plain'); // Content-Type change
    while(!feof($fp)) {
        $buffer = fread($fp, 1025);
        $buffer = str_replace("\r\n", '\r\n'."\n", $buffer);
        echo $buffer;
    }
    fclose($fp); // connection end

Спустя 1 час, 48 минут, 1 секунда (5.05.2009 - 19:40) FatCat написал(а):
Спасибо! При случае покопаюсь.
Сделал через curl, нагуглил-таки внятный пример получения кода HTTP-ответа.
PHP
function hget($in){
    
$in=str_replace("\n",'',$in);
    
$in=str_replace("\r",'',$in);
    
$in=str_replace(" ",'',$in);
    
$ch curl_init();
    
curl_setopt($chCURLOPT_FOLLOWLOCATION1);
    
curl_setopt($chCURLOPT_URL$in); // что чекаем
    
curl_setopt($chCURLOPT_HEADER1); // нам _нужен_  заголовок
    
curl_setopt($chCURLOPT_NOBODY1); // нам _НЕ_  нужно мертвое  тело ответа
    
curl_setopt($chCURLOPT_RETURNTRANSFERtrue);
    
curl_setopt($chCURLOPT_REFERER$in);
    
curl_setopt($chCURLINFO_HEADER_OUTtrue);
    
curl_setopt($chCURLOPT_USERAGENT"User-Agent=Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14");
    
$result=curl_exec($ch);// загрузка страницы
    
return curl_getinfo($ch,CURLINFO_HTTP_CODE);
    
curl_close($ch);
}

Спустя 1 час, 20 минут, 14 секунд (5.05.2009 - 21:00) kirik написал(а):
Что-то вы мутите, ребят...
Цитата (FatCat @ 5.05.2009 - 09:44)
Ломал голову, как получить ответ сервера; если не 404-й и т.д., то линк жив...

В curl есть офигенная опция для этого: CURLOPT_FAILONERROR. Что она делает - возвращает ошибку, если код в заголовках > 400 (или 300 - в русской версии php.net). Для проверки "битости" использую такую функцию (если ссылка жива - возвращает true, иначе false):
PHP
function checkStatus($url)
{
    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_HEADER, 1);
    curl_setopt($curl, CURLOPT_NOBODY, 1);
    curl_setopt($curl, CURLOPT_TIMEOUT, 10); // таймаут 10 сек (если больше, знач сервер в висюке)
    curl_setopt($curl, CURLOPT_FAILONERROR, 1); // если код страницы > 400 - вернем ошибку
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // вывод возвращаем, а не выводим
    $status = curl_exec($curl);
    curl_close($curl);
    return !empty($status);
}

Спустя 1 час, 16 минут, 16 секунд (5.05.2009 - 22:16) FatCat написал(а):
kirik
Полезно бывает посмотреть успешные статусы.
Добавил опционально сканирование не только одной страницы, но и сканирование всех страниц, на которые есть линки с начальной.
Свернутый текст
PHP
define('TIME_LIMIT'0);
$is_safe_mode ini_get('safe_mode') == '1' 0;
if (!
$is_safe_mode && function_exists('set_time_limit')) set_time_limit(TIME_LIMIT);

header("Expires: Tue, 1 Jul 2003 05:00:00 GMT");
header("Last-Modified: " gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Pragma: no-cache");

if( !isSet(
$_GET['test']) )$_GET['test'] = "";
list(
$usec$sec) = explode(" "microtime());
$timer_start = ((float)$usec + (float)$sec);
if(
$_GET['test'] == "")$output "<h2 align=\"center\">Поиск &quot;битых&quot; линков:</h2>".first_form();
else
{
    
$output "<h2 align=\"center\">Результаты поиска:</h2>";
    if(
$_GET['who']=="1")
    {
        
$links get_objects($_GET['test'], 2);
        
$output .= implode"<br>"check_curl($links) );
        
$output .= "<h2 align=\"center\">Новый поиск:</h2>".first_form();
    }
    else
    {
        
$first_pass get_objects($_GET['test'], 1);
        
error_reporting(0);
        
$output .= "Проверка страницы ".$_GET['test']." :<ul>";
        
$links get_objects($_GET['test'], 2);
        
$output .= implode"<br>"check_curl($links) );
        
$output .= "</ul>";
        foreach(
$first_pass as $url)
        {
            if( 
$url!=$_GET['test'] and $url!=$_GET['test']."/" and stristr($url,$_GET['test']) )
            {
                
$output .= "Проверка страницы ".$url." :<ul>";
                
$links get_objects($_GET['test'], 2);
                if(
$links == "0")$output .= "Страница недоступна!";
                else 
$output .= implode"<br>"check_curl($links) );
                
$output .= "</ul>";
            }
        }
    }
    list(
$usec$sec) = explode(" "microtime());
    
$timer_end = ((float)$usec + (float)$sec);
    
$output .= "<div align=center>Поиск занял ".($timer_end-$timer_start)." секунд.</div>";
    
$output .= "<h2 align=\"center\">Новый поиск:</h2>".first_form();
}


echo 
'<html>
<head>
<title>Поиск &quot;битых&quot; линков и потерянных имиджей</title>
</head>
<body>
'
.$output.'
</body>
</html>'
;


function 
first_form()
{
    if(
$_GET['test'] == "")$test_URL "http://";
    else 
$test_URL $_GET['test'];
    return 
'<form action=""><div align="center">
    <strong>URL проверяемой страницы</strong>:&nbsp;<input type="text" name="test" id="test" value="'
.$test_URL.'" size="37" maxlength="128">
    <input type="submit" value="Проверить!">
    <br><br><nobr><strong>Проверить</strong>: <input type="radio" name="who" checked=checked value="1">&nbsp;только одну страницу;
    &nbsp;&nbsp;&nbsp;<input type="radio" name="who" value="2">&nbsp;и все связанные с этой страницей на этом сайте.</nobr>
    <br><br>(URL должен заканчиваться знаком "/" или именем файла)</div></form>'
;
}

function 
get_objects($url$pass)
{
    
$text file_get_contents($url);
    if(
strlen($text)==0) return "0";
    
$text str_replace("''","",$text);
    
$text str_replace("\"\"","",$text);
    
$links = array();
    
    if(
$pass==2)
    {
        
// Поиск для конструкций src="..."
        
preg_match_all("/src=\"(.+?)\"/is",$text,$tmp_links);
        while(
count($tmp_links[0]))
        {
            
$links array_merge($links,$tmp_links[1]);    // добавляем свеженайденые URL в список
            
$text str_replace($tmp_links[0],$tmp_links[1],$text);    // убираем найденые URL из текста
            
$text str_replace("src=\"\"","",$text);
            
preg_match_all("/src=\"(.+?)\"/is",$text,$tmp_links);  // продолжаем поиск
        
}
        
// Повторяем поиск для конструкций src='...'
        
preg_match_all("/src='(.+?)'/is",$text,$tmp_links);
        while(
count($tmp_links[0]))
        {
            
$links array_merge($links,$tmp_links[1]);
            
$text str_replace($tmp_links[0],$tmp_links[1],$text);
            
$text str_replace("src=''","",$text);
            
preg_match_all("/src='(.+?)'/is",$text,$tmp_links);
        }
    }
    
// Повторяем поиск для конструкций href="..."
    
preg_match_all("/href=\"(.+?)\"/is",$text,$tmp_links);
    while(
count($tmp_links[0]))
    {
        
$links array_merge($links,$tmp_links[1]);    // добавляем свеженайденые URL в список
        
$text str_replace($tmp_links[0],$tmp_links[1],$text);    // убираем найденые URL из текста
        
$text str_replace("src=\"\"","",$text);
        
preg_match_all("/href=\"(.+?)\"/is",$text,$tmp_links);  // продолжаем поиск
    
}
    
// Повторяем поиск для конструкций href='...'
    
preg_match_all("/href='(.+?)'/is",$text,$tmp_links);
    while(
count($tmp_links[0]))
    {
        
$links array_merge($links,$tmp_links[1]);
        
$text str_replace($tmp_links[0],$tmp_links[1],$text);
        
$text str_replace("src=''","",$text);
        
preg_match_all("/href='(.+?)'/is",$text,$tmp_links);
    }
    
    
$base_href explode("/",$_GET['test']);
    
$base_href[(count($base_href)-1)] = "";
    
$base_href implode("/",$base_href);
    
    
$links_cleaned = Array();
    foreach(
$links as $link)
    {
        
$href $base_href;
        while( 
substr($link,0,3)=="../" )
        {
            
$link substr($link,3);
            
$href substr($base_href,0,-1);
            
            
$href explode("/",$href);
            
$href[(count($href)-1)] = "";
            
$href implode("/",$href);
        }
        if(
substr($link,0,7)!="http://")$link $href.
        
$link str_replace("/./","/",$link);
        if(
        !
stristr($link,"javascript:")
        and !
stristr($link,"(")
        and !
stristr($link,"+")
        and !
stristr($link,"mailto:")
        )
        
$links_cleaned[] = $link;
    }
    
$links_cleaned array_unique($links_cleaned);
    return 
$links_cleaned;
}

function 
check_curl($linksz){
    
$links = array();
    foreach(
$linksz as $link)
    {
        
$kode hget($link);
        if( 
intval($kode)<400 and intval($kode)>99 )$links[] = "<font color=\"#008000\">".$link." (код ".$kode.")</font>";
        else 
$links[] = "<font color=\"#FF0000\"><strong>".$link."</strong> (ошибка ".$kode.")</font>";
    }
    return 
$links;
}

function 
hget($in){
    
$in=str_replace("\n",'',$in);
    
$in=str_replace("\r",'',$in);
    
$in=str_replace(" ",'',$in);
    
$ch curl_init();
    
curl_setopt($chCURLOPT_FOLLOWLOCATION1);
    
curl_setopt($chCURLOPT_URL$in); // что чекаем
    
curl_setopt($chCURLOPT_HEADER1); // нам _нужен_  заголовок
    
curl_setopt($chCURLOPT_NOBODY1); // нам _НЕ_  нужно мертвое  тело ответа
    
curl_setopt($chCURLOPT_RETURNTRANSFERtrue);
    
curl_setopt($chCURLOPT_REFERER$in);
    
curl_setopt($chCURLINFO_HEADER_OUTtrue);
    
curl_setopt($chCURLOPT_USERAGENT"User-Agent=Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14");
    
$result=curl_exec($ch);// загрузка страницы
    
return curl_getinfo($ch,CURLINFO_HTTP_CODE);
    
curl_close($ch);
}

Но ресурсов это жрет уйму.
С локальной машины сканирование главной форума со всеми первого вложения заняло 18 минут.
На шаред-хостинге минут через 5 выдал 502-ю страницу...

Спустя 17 минут, 10 секунд (5.05.2009 - 22:34) waldicom написал(а):
Да, про curl я че-то не подумал...

Спасибо за скрипт.


_____________
Бесплатному сыру в дырки не заглядывают...
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.