Доработка [issue #1]

This commit is contained in:
RedHood 2020-09-17 00:32:33 +10:00
parent dc5b301adf
commit 1d4f5d270a
5 changed files with 47 additions and 100 deletions

1
.gitignore vendored
View File

@ -1,3 +1,2 @@
vendor/ vendor/
dumps/ dumps/
runtime/

View File

@ -1,11 +1,10 @@
<?php <?php
namespace app\models; namespace app;
use \Exception; use DateTime;
use \DateTime; use Yii;
use \Yii; use linslin\yii2\curl\Curl;
use \linslin\yii2\curl\Curl;
/** /**
* Модель для выгрузки страниц в автономное хранилище * Модель для выгрузки страниц в автономное хранилище
@ -26,7 +25,7 @@ use \linslin\yii2\curl\Curl;
* 2. Исправить обработку ссылки: zakupki.gov.ru/data/common-info.html?regNumber=0816500000619001511 * 2. Исправить обработку ссылки: zakupki.gov.ru/data/common-info.html?regNumber=0816500000619001511
* 4. Конструкцию <base> надо доработать на проверку уже существующего тега * 4. Конструкцию <base> надо доработать на проверку уже существующего тега
*/ */
class Dump extends \yii\base\Component class Dumper extends \yii\base\Component
{ {
/** /**
* Глубина поиска страниц относительно первичной * Глубина поиска страниц относительно первичной
@ -252,19 +251,9 @@ class Dump extends \yii\base\Component
// Добавление стартовой ссылки в регистр // Добавление стартовой ссылки в регистр
array_unshift($this->links, $link); array_unshift($this->links, $link);
// Инициализация цели в статистике // Инициализация данных для статистики
// if (YII_DEBUG) { $this->statistics[0] = $this->target;
$this->statistics[0] = $this->target; $this->statistics[2][1] = 1;
// }
// Прибавление стартовой ссылки для вывода в статистике
// if (YII_DEBUG) {
// if (!isset($this->statistics[2][1])) {
// $this->statistics[2][1] = 0;
// }
// $this->statistics[2][1]++;
$this->statistics[2][1] = 1;
// }
} else if ($this->subdownload && $depth === 0) { } else if ($this->subdownload && $depth === 0) {
// Иначе если это дополнительное скачивание и глубина равна нулю // Иначе если это дополнительное скачивание и глубина равна нулю
@ -290,11 +279,9 @@ class Dump extends \yii\base\Component
$request = ($this->connectionProtocol ?? 'http') . '://' . ($targetMatch[3][0] ?? $this->connectionHost) . $link; $request = ($this->connectionProtocol ?? 'http') . '://' . ($targetMatch[3][0] ?? $this->connectionHost) . $link;
} else if (preg_match('/(^[^\/\\\\\s\.]+(\/|\\\|$)([^\/\\\\\s]*$|[^\/\\\\\s]+(\/|\\\).*))/', $link)) { } else if (preg_match('/(^[^\/\\\\\s\.]+(\/|\\\|$)([^\/\\\\\s]*$|[^\/\\\\\s]+(\/|\\\).*))/', $link)) {
// Паттерн: 'foo/index.html', 'foo/bar/index.html', 'foo', 'foo/' // Паттерн: 'foo/index.html', 'foo/bar/index.html', 'foo', 'foo/'
// Не помню почему регулярное выражение такое сложное, разбираться сейчас не стал, так как главное, что работает
$request = ($this->connectionProtocol ?? 'http') . '://' . ($targetMatch[3][0] ?? $this->connectionHost) . '/' . $link; $request = ($this->connectionProtocol ?? 'http') . '://' . ($targetMatch[3][0] ?? $this->connectionHost) . '/' . $link;
} else { } else {
unset($this->links[$link]); unset($this->links[$link]);
// throw new Exception('Не удалось идентифицировать запрос');
return $this; return $this;
} }
unset($match); // Очистка на всякий случай, так как переменные остаются unset($match); // Очистка на всякий случай, так как переменные остаются
@ -332,9 +319,7 @@ class Dump extends \yii\base\Component
$this->linksNew += count($match[2]); $this->linksNew += count($match[2]);
// Прибавление количества новых ссылок для вывода в статистике // Прибавление количества новых ссылок для вывода в статистике
// if (YII_DEBUG) { $this->statistics[2][0] += count($match[2]);
$this->statistics[2][0] += count($match[2]);
// }
// Добавление ссылок в общий регистр // Добавление ссылок в общий регистр
foreach ($match[2] as $link) { foreach ($match[2] as $link) {
@ -408,15 +393,9 @@ class Dump extends \yii\base\Component
$this->links[$link][1] = '/' . $this->links[$link][1]; $this->links[$link][1] = '/' . $this->links[$link][1];
} }
// if (!isset($this->links[$link])) {
// $this->convertLinks();
// }
// Проверка существования каталога и его создание // Проверка существования каталога и его создание
if (/** isset($this->links[$link] && */ !file_exists(Yii::$app->params['basePath'] . $this->links[$link][1])) { if (!file_exists(Yii::$app->params['basePath'] . $this->links[$link][1])) {
if (!mkdir(Yii::$app->params['basePath'] . $this->links[$link][1], 0755, true)) { mkdir(Yii::$app->params['basePath'] . $this->links[$link][1], 0755, true);
// throw new Exception('Не удалось создать каталог');
}
} }
// Сохранение файла // Сохранение файла
@ -424,8 +403,6 @@ class Dump extends \yii\base\Component
if (file_put_contents(Yii::$app->params['basePath'] . $this->links[$link][1] . $this->links[$link][0], $file[1])) { if (file_put_contents(Yii::$app->params['basePath'] . $this->links[$link][1] . $this->links[$link][0], $file[1])) {
$this->files[$link][0] = $file[0]; $this->files[$link][0] = $file[0];
$this->files[$link][1] = $file[1]; $this->files[$link][1] = $file[1];
} else {
// throw new Exception('Не удалось сохранить файл');
} }
} }
$savedFiles[$link] = $files[$link]; $savedFiles[$link] = $files[$link];
@ -434,9 +411,7 @@ class Dump extends \yii\base\Component
unset($link, $file); // Очистка на всякий случай, так как переменные остаются unset($link, $file); // Очистка на всякий случай, так как переменные остаются
// Указание сборщику статистики, что парсер успешно завершил свою работу // Указание сборщику статистики, что парсер успешно завершил свою работу
// if (YII_DEBUG) { $this->statistics[1] = 0;
$this->statistics[1] = 0;
// }
return $savedFiles; return $savedFiles;
} }
@ -479,13 +454,11 @@ class Dump extends \yii\base\Component
$unidentifiedCount = $this->statistics[4][7] ?? 'Ошибка'; $unidentifiedCount = $this->statistics[4][7] ?? 'Ошибка';
if (!file_exists(Yii::getAlias('@runtime/logs'))) { if (!file_exists(Yii::getAlias('@runtime/logs'))) {
if (!mkdir(Yii::getAlias('@runtime/logs'), 0755, true)) { mkdir(Yii::getAlias('@runtime/logs'), 0755, true);
// throw new Exception('Не удалось создать каталог');
}
} }
$file = fopen(Yii::getAlias('@runtime/logs') . '/' . $date . uniqid('_DUMPER_', true) . '.log', 'a+'); $file = fopen(Yii::getAlias('@runtime/logs') . '/' . $date . uniqid('_DUMPER_', true) . '.log', 'a+');
if (!fwrite($file, <<<EOT fwrite($file, <<<EOT
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
/// Статистика выполнения /// /// Статистика выполнения ///
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
@ -520,14 +493,10 @@ class Dump extends \yii\base\Component
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
EOT EOT
)) { );
// throw new Exception('Не удалось записать статистику');
}
fclose($file); fclose($file);
unset($i, $date, $dateFull, $file); // Очистка на всякий случай, так как переменные остаются unset($i, $date, $dateFull, $file); // Очистка на всякий случай, так как переменные остаются
// return true;
} }
/** /**
@ -559,14 +528,13 @@ EOT
$uri = $this->initLink($link); $uri = $this->initLink($link);
// !!!!!!!!!!!!!!!!!!!!!!! preg_match_all('/(\/\/|\\\\)(.*)((\/|\\\|$).*$)/U', $uri, $uriMatch);
preg_match_all('/\/\/(.*)((\/|$).*$)/U', $uri, $uriMatch); preg_match_all('/(\/\/|\\\\)(.*)((\/|\\\|$).*$)/U', $this->target, $targetMatch);
preg_match_all('/\/\/(.*)((\/|$).*$)/U', $this->target, $targetMatch);
if ($targetMatch[1][0] === $uriMatch[1][0]) { if ($targetMatch[2][0] === $uriMatch[2][0]) {
$location = ''; $location = '';
} else { } else {
$location = Yii::$app->params['externalLinksPath'] . '/' . $uriMatch[1][0]; $location = Yii::$app->params['externalLinksPath'] . '/' . $uriMatch[2][0];
} }
unset($uriMatch, $targetMatch); unset($uriMatch, $targetMatch);
@ -590,10 +558,8 @@ EOT
} }
// Обновление статистики // Обновление статистики
// if (YII_DEBUG) { $this->statistics[4][0]++;
$this->statistics[4][0]++; $this->statistics[4][5]++;
$this->statistics[4][5]++;
// }
} else if (preg_match('/\\.js/i', $uri)) { } else if (preg_match('/\\.js/i', $uri)) {
// Если это JS файл // Если это JS файл
@ -606,10 +572,8 @@ EOT
} }
// Обновление статистики // Обновление статистики
// if (YII_DEBUG) { $this->statistics[4][0]++;
$this->statistics[4][0]++; $this->statistics[4][6]++;
$this->statistics[4][6]++;
// }
} else if (preg_match('/(\\.png|\\.jpeg|\\.jpg|\\.webp|\\.gif|\\.svg|\\.ico)/i', $uri)) { } else if (preg_match('/(\\.png|\\.jpeg|\\.jpg|\\.webp|\\.gif|\\.svg|\\.ico)/i', $uri)) {
// Если это изображение // Если это изображение
@ -622,10 +586,8 @@ EOT
} }
// Обновление статистики // Обновление статистики
// if (YII_DEBUG) { $this->statistics[4][0]++;
$this->statistics[4][0]++; $this->statistics[4][2]++;
$this->statistics[4][2]++;
// }
} else if (preg_match('/(https?:(\/\/|\\\\).+(\/|\\\).+|^(\/|\\\).+)(\.(?!php|htm)[A-z0-9]+)[^\/\\\s]*$/i', $uri)) { } else if (preg_match('/(https?:(\/\/|\\\\).+(\/|\\\).+|^(\/|\\\).+)(\.(?!php|htm)[A-z0-9]+)[^\/\\\s]*$/i', $uri)) {
// Если это неопознанный документ (очень затратное выражение, но по другому никак) // Если это неопознанный документ (очень затратное выражение, но по другому никак)
@ -638,10 +600,8 @@ EOT
} }
// Обновление статистики // Обновление статистики
// if (YII_DEBUG) { $this->statistics[4][0]++;
$this->statistics[4][0]++; $this->statistics[4][7]++;
$this->statistics[4][7]++;
// }
} else if (preg_match_all('/(\/\/|\\\\)(.*)((\/|\\|$).*$)/U', $uri, $uriMatch)) { } else if (preg_match_all('/(\/\/|\\\\)(.*)((\/|\\|$).*$)/U', $uri, $uriMatch)) {
// Иначе, если это обрабатывается универсально или как HTML документ // Иначе, если это обрабатывается универсально или как HTML документ
@ -668,33 +628,22 @@ EOT
$links[$rawLink][2] = $links[$rawLink][1] . '/index.html'; $links[$rawLink][2] = $links[$rawLink][1] . '/index.html';
} }
// Прибавление количеству найденных страниц // Прибавление к количеству найденных страниц
// if (YII_DEBUG) { $this->statistics[3][0]++;
$this->statistics[3][0]++;
// }
} else {
// Иначе, ссылку не удалось инициализировать, пропуск
// throw new Exception('Не удалось идентифицировать сохранённую ссылку: '.$link)
} }
// Удаление обработанной ссылки и оставшихся переменных // Удаление обработанной ссылки и оставшихся переменных
unset($links[$this->linksNew], $rawLink, $location, $uriSplit, $match, $file, $uri); unset($links[$this->linksNew], $rawLink, $location, $uriSplit, $match, $file, $uri);
// Прибавление количеству обработанных ссылок // Прибавление к количеству обработанных ссылок
// if (YII_DEBUG) { $this->statistics[2][1]++;
$this->statistics[2][1]++;
// }
// Подготовка к следующей итерации цикла // Подготовка к следующей итерации цикла
$this->linksNew--; $this->linksNew--;
} }
// Количество обработанных ссылок без дубликатов // Количество обработанных ссылок без дубликатов
// if (YII_DEBUG) { $this->statistics[2][2] = count($this->links);
// Количество обработанных ссылок без дубликатов
$this->statistics[2][2] = count($this->links);
// }
return $links; return $links;
} }
@ -743,8 +692,6 @@ EOT
// Определяем вложенность страницы // Определяем вложенность страницы
if (preg_match_all('/([^\\\|\/|\\s]+)/', $this->links[$link][1], $urlMatch)) { if (preg_match_all('/([^\\\|\/|\\s]+)/', $this->links[$link][1], $urlMatch)) {
$catalogsDepth = count($urlMatch[1]); $catalogsDepth = count($urlMatch[1]);
} else {
// throw new Exception('Ошибка при инъекции <base>: не удалось посчитать вложенность страницы');
} }
$content = $contentMatch[1][0] . "\n<base href=\"" . str_repeat('../', $catalogsDepth ?? 0) . '">'. $contentMatch[2][0]; $content = $contentMatch[1][0] . "\n<base href=\"" . str_repeat('../', $catalogsDepth ?? 0) . '">'. $contentMatch[2][0];
@ -754,12 +701,8 @@ EOT
if (file_put_contents(Yii::$app->params['basePath'] . $this->links[$link][1] . $this->links[$link][0], $content)) { if (file_put_contents(Yii::$app->params['basePath'] . $this->links[$link][1] . $this->links[$link][0], $content)) {
unset($this->files[$link]); unset($this->files[$link]);
// Прибавление количеству конвертированных страниц // Прибавление к количеству конвертированных страниц
// if (YII_DEBUG) { $this->statistics[3][1]++;
$this->statistics[3][1]++;
// }
} else {
// throw new Exception('Не удалось сохранить файл');
} }
} }
} else if ($file[0] !== 0) { } else if ($file[0] !== 0) {
@ -768,6 +711,7 @@ EOT
unset($this->files[$link]); unset($this->files[$link]);
} else { } else {
// Иначе воспринимается как не HTML документ, который не требует конвертацию // Иначе воспринимается как не HTML документ, который не требует конвертацию
continue; continue;
} }
} }
@ -832,11 +776,13 @@ EOT
} else if ($link === '/' || $link === '\\') { } else if ($link === '/' || $link === '\\') {
// Иначе, если ссылка ведёт на главную страницу сайта // Иначе, если ссылка ведёт на главную страницу сайта
// [!!!] Это надо переработать, так как ссылка '/' можеть быть и на стороннем хосте [!!!] if (!$this->searchExternal) {
$uri = $this->connectionProtocol . ':' . '//' . $this->connectionHost; $uri = $this->connectionProtocol . ':' . '//' . $this->connectionHost;
}
// Иначе всё обрабатывается как ссылка на текущего хоста
} else { } else {
// Иначе всё обрабатывается как ссылка на текущего хоста
if (!preg_match('/^(\/|\\\)/', $link)) { if (!preg_match('/^(\/|\\\)/', $link)) {
$link = '/' . $link; $link = '/' . $link;
} }

View File

@ -4,7 +4,7 @@ return [
'controllerNamespace' => 'app\controllers', 'controllerNamespace' => 'app\controllers',
'basePath' => dirname(__DIR__), 'basePath' => dirname(__DIR__),
'params' => [ 'params' => [
'basePath' => dirname(__DIR__) . '/dumps', 'basePath' => dirname(__DIR__) . '/dump',
'pagesPath' => '/pages', 'pagesPath' => '/pages',
'docsPath' => '/data', 'docsPath' => '/data',
'imgPath' => '/img', 'imgPath' => '/img',

View File

@ -2,14 +2,14 @@
namespace app\controllers; namespace app\controllers;
use \Yii; use Yii;
use \app\models\Dump; use app\Dumper;
class DumpController extends \yii\console\Controller class DumpController extends \yii\console\Controller
{ {
public function actionIndex($link, $depth = 0, $buffer = 0, $force = false, $searchExternal = false, $path = '') public function actionIndex($link, $depth = 0, $buffer = 0, $force = false, $searchExternal = false, $path = '')
{ {
(new Dump)->download($link, $depth, $buffer, $force, $searchExternal, $path); (new Dumper)->download($link, $depth, $buffer, $force, $searchExternal, $path);
return 0; return 0;
} }

2
runtime/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore