Сканирование сайта с помощью PHP
Иногда требуется посканировать сайт "снаружи", т.е. посмотреть на него так, как видят его роботы. Для этого можно воспользоваться уже готовыми программами, а можно написать свою.
Чаще всего готовые программы многого не умеют, либо делают что-то не так, как хочется.
Собственная программа на php сделает все именно так как задумано.
Когда может пригодиться сканирование сайта
- Создание карты сайта
- Поиск ссылок ведущих на чужие сайты
- Проверка html-кода
- Поиск битых картинок
Создание карты сайта
Это может потребоваться если используется какая-нибудь нестандартная CMS, у которой нет модуля для создания карты сайта. Или модуль выдает не то что хочется, например, добавляет лишние ссылки или не добавляет страницы, которые на сайте видны, но модуль о них не знает. Или нет времени, сил или знаний чтобы чинить или дорабатывать этот модуль. А может быть карта нужна разово и нет смысла разбираться с модулями.
Поиск ссылок ведущих на чужие сайты
Если сайт наполняли путем копирования-вставки, то есть вероятность того что с текстом были скопированы ссылки, которые в лучшем случае будут отдавать "вес" вашего сайта чужому, а в худшем по ним уйдут ваши посетители. Или можно опозориться, когда хозяева сайта с которого вы копировали текст вместе с сылками на картинки обнаружат это и заменят картинки на что-нибудь неприличное и ваши посетители это увидят.
Проверка html-кода
Иногда бывают ситуации когда в нескольких разных статьях используется одинаковая разметка и когда статьи выводятся блогом, то на одной странице могут оказаться теги с одинаковыми id. Большинство CMS не проводят валидацию получившихся страниц, а одинаковые id могут вызвать неработоспособность js-скриптов.
Поиск битых картинок
В случаях когда картинки отсутствуют на диске, но в базе данных есть записи об этих картинках, возникает эффект битых ссылок. Ссылка есть, а файла нет. Это тоже труднообнаружимая проблема на сайте с огромным количеством страниц.
---
Из всего вышеперечисленного наш скрипт будет создавать только карту сайта. А уже в последующих статьях мы будем добавлять другой функционал. Если вам это нужно и вы попросите доработать скрипт. Пишите об этом в комментариях.
Установка интерпретатора php
Для работы скрипта, как можно догадаться, понадобится установить php в Windows. Делается это очень просто. Скачиваем дистрибутив PHP в виде zip-архива отсюда https://windows.php.net/download/
Распаковываем архив в папочку C:\php и добавляем ее в переменную окружения PATH, чтобы в командной строке не набирать каждый раз полный путь к php.exe.
Скрипт сканирования сайта
А это собственно сам скрипт, который скачивает главную страницу сайта, ищет на ней все ссылки и добавляет их в очередь на сканирование.
Для уже проверенных страниц и очереди используются два массива. Третий массив используется для хранения регулярных выражений, описывающих адреса страниц, которые нужно пропустить. На большинстве сайтов таких страниц очень много, и если их не просеивать, то процесс сканирования может затянуться надолго.
Поскольку в задачи нашего скрипта входит построить "карту сайта", то адреса страниц мы будем просто скидывать в файл sitemap.txt.
<?php
// адрес сайта c закрывающим слешем
$site = "https://coffee-cms.ru/";
// массив для очереди обрабатываемых страниц
$queue[] = $site; // стартуем с главной
// массив для уже скачанных, чтобы не повторяться
$checked = array();
// массив для учета где найдена ссылка
$found = array();
// максимальное количество проверяемых
$limit = 10000;
$ignored = array(
"/\/sites\//", // drupal
"/\/misc\//", // drupal
"/\/flag\//", // drupal
"/\/christmas\//", // coffee-cms.ru
"/\/baseBlog\//", // coffee-cms.ru
"/\/jquery/", // coffee-cms.ru
"/\/\\\$\{src\}/", // in js coffee-cms.ru
"/<\?php/", // in examples coffee-cms.ru
//"/\.zip\$/", // не искать битые ссылки
//"/\.png\$/", // не искать битые ссылки
//"/\.svg\$/", // не искать битые ссылки
//"/\.xml\$/", // не искать битые ссылки
//"/\.mp4\$/", // не искать битые ссылки
//"/\.jpg\$/", // не искать битые ссылки
);
file_put_contents( "sitemap.txt", "" ); // очистить файл
file_put_contents( "error.txt", "" ); // очистить файл
while ( count( $queue ) > 0 && $limit > 0 ) {
$page = array_shift( $queue );
if ( ! in_array( $page, $checked ) ) {
// качаем только с нашего сайта
if ( substr( $page, 0, strlen( $site ) ) == $site ) {
$content = @file_get_contents( $page );
if ( $content === false ) {
file_put_contents( "error.txt",
"page: {$page}\n", FILE_APPEND );
foreach( $found[ $page ] as $f ) {
file_put_contents( "error.txt",
" found: {$f}\n", FILE_APPEND );
}
continue;
}
}
// ищем все ссылки на странице
preg_match_all( "#(src|href)=[\"'](?!//|\#|mailto:)(.*?)[\"']#",
$content, $matches, PREG_SET_ORDER );
// добавляем найденные ссылки в очередь
foreach ( $matches as $match ) {
$link = $match[2];
// корректируем относительные ссылки
if ( substr( $link, 0, 7 ) != "http://"
&& substr( $link, 0, 8 ) != "https://" )
{
if ( $link[0] == "/" ) {
$link = substr( $link, 1 ); // убрать ведущий слеш
}
$link = $site . $link;
}
$found[ $link ][] = $page;
if ( ! in_array( $link, $queue ) && // не в очереди
! in_array( $link, $checked ) && // не проверена
substr( $link, 0, strlen( $site ) ) == $site ) // с нашего сайта
{
$ignore = false;
foreach ( $ignored as $regex ) {
$ignore = $ignore || preg_match( $regex, $link );
if ( $ignore ) { break; } // не проверять остальные
}
if ( ! $ignore ) { $queue[] = $link; } // ставим в очередь
}
}
$checked[] = $page; // добавляем в массив проверенных
file_put_contents( "sitemap.txt", $page . "\n", FILE_APPEND );
// отображаем какая ссылка обработана
echo "checked " . count( $checked ) .
", queue " . count( $queue ) . ", page $page\n";
$limit--;
}
}