База данных
Для начала нам надо взять саму базу. RuTracker каждый месяц выкладывает дамп своих торрентов здесь. Скачиваем, распаковываем и видим два десятка файлов CSV.
Нам нужны только те, в которых есть информация о торрентах – остальные удаляем. В файле «category_info.csv» — подсказка для тех, кому не хочется открывать каждый файл (удалить: «category_1.csv», «category_4.csv», «category_36.csv»). Открываем любой из оставшихся файлов и видим такую структуру (я сразу заменил символ «;» на новую строку, что бы было визуально удобнее):
«1568» | ID раздела на RuTracker |
«Кулинария» | Название раздела |
«63629» | ID темы на RuTracker |
«F7D7BE97A818CCDFA072C42348EB669F7883888D» | Hash торрента |
"(Кулинария) Вкусные истории 1" | Название торрента |
«729927066» | Размер раздачи в байтах |
«2006-08-21 10:00:22» | Дата публикации раздачи |
Теперь мы добавим всю информацию в базу данных. Используем MySQL, как самую распространённую БД. У меня получилась вот такая таблица (обратите внимание: столбец «hash» — уникальный, все текстовые данные в кодировке utf8):
CREATE TABLE IF NOT EXISTS `torrents` (
`id` int(11) NOT NULL,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`hash` varchar(40) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`date` date NOT NULL,
`size` int(11) NOT NULL,
`topic_id` int(11) NOT NULL,
`cat_id` int(11) NOT NULL,
`cat_name` varchar(120) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf32 COLLATE=utf32_bin;
ALTER TABLE `torrents`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `hash` (`hash`);
ALTER TABLE `torrents`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
Затем закачиваем все файлы CSV в одну папку (например, назовем её «db») на сервере. Добавление информации о торрентах в БД осуществим с помощью не сложного скрипта, представленного ниже. Его тоже необходимо закачать в ту же папку где находятся исходные CSV-файлы.
<?
//Ограничиваем время выполнения скрипта 3-мя минутами
set_time_limit(180);
//Подключаемся к MySQL, при неудаче выводим ошибку
mysql_connect("localhost", "torrent", "password") or die("Could not connect to MySQL");
//Выбираем БД, при неудаче выводим ошибку
mysql_select_db("torrent") or die("Could not select database");
//Переводим все общение с БД в кодировку utf8
mysql_query("SET NAMES utf8");
//Открываем файл указанный в url переменной "f"
$fp = fopen($_GET[f], "r");
//Запускаем цикл до конца строк в файле
while (!feof($fp)) {
//Считываем строку (да, функцию trim() выполнять не обязательно, но у каждого программиста свои "тараканы")
$tmp = trim(fgets($fp));
//Преобразуем строку в массив. За разделитель используем ";"
$torrent = explode('";"', $tmp);
//В первом и последнем элементе удаляем лишние символы "
$torrent[0] = substr($torrent[0], 1);
$torrent[6] = substr($torrent[6], 0, (strlen($torrent[6]) - 1));
//Если раскомментировать следующую строку, то можно увидеть как распарсился первый торрент в файле
//print '<pre>'; print_r($torrent); exit();
//Вставляем данные текущего торрента в таблицу
mysql_query("INSERT INTO `torrents`
(`name`,
`hash`,
`date`,
`size`,
`topic_id`,
`cat_id`,
`cat_name`)
VALUES
('" . mysql_real_escape_string($torrent[4]) . "',
'" . $torrent[3] . "',
'" . $torrent[6] . "',
'" . $torrent[5] . "',
'" . $torrent[2] . "',
'" . $torrent[0] . "',
'" . mysql_real_escape_string($torrent[1]) . "')
");
}
//Закрываем файл
fclose($fp);
//Выводим сообщение о завершении работы
print 'complete: ' . $_GET[f];
?>
Открываем браузер, открываем url «http://site.ru/db/insert_to_db.php?f=category_10.csv». Проделываем тоже самое с каждым файлом CSV. Да, все это можно было автоматизировать, но я специально написал так, что бы было максимально всё понятно. После этих действий в нашей таблице оказалось чуть больше 1,6 миллиона записей. Не маленькая такая база. Поиск MySQL с таким объемом данных не справится, так что поручим эту задачу Sphinx.
Sphinx
Установка Sphinx на различные системы производится разными способами. Все зависит от операционной системы и железа. Это тема заслуживает отдельной статьи. Но есть очень много отличных мануалов в Интернете. На русском языке тоже. Сейчас же мы займемся настройкой конфигурационного файла для Sphinx. Создаем в корневом каталоге сайта директорию, допустим, cache. Здесь будут хранится все файлы индекса Sphinx для нашего сайта. Загружаем в эту папку файл конфигурации (листинг приведен ниже).
# Настройка источника откуда берутся данные
source torrentz
{
# Подключаемся к БД
type = mysql
sql_host = localhost
sql_user = torrent
sql_pass = password
sql_db = torrent
sql_port = 3306
# Переводим все общение с БД в кодировку utf8
sql_query_pre = SET NAMES utf8
sql_query_pre = SET CHARACTER SET utf8
# Запрос данных для индексации
sql_query = SELECT id, name FROM torrents
# Время (в миллисекундах) паузы перед посылкой запроса БД. Используется для медленных и загруженных серверов
sql_ranged_throttle = 0
}
# Настройка индекса. Более подробно все описано в документации Sphinx
index torrentz
{
# Выбор источника
source = torrentz
# Путь до файлов индекса
path = /home/rutr/rutracker.online/www/cache/
# Способ хранения индекса
docinfo = extern
# Использование английской и русской морфологии
morphology = stem_enru
# Минимальная длина индексируемого слова
min_word_len = 2
# Установка кодировки
charset_type = utf-8
# Символы
charset_table = 0..9, A..Z->a..z, _, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F
# Минимальная длина инфикса
min_infix_len = 2
# Использовать оператор усечения "*"
enable_star = 1
}
# Настройка индексатора
indexer
{
# Лимит используемой оперативной памяти
mem_limit = 32M
}
# Настройка поискового демона
searchd
{
# Указываем порт на который сайт будет отдавать запросы на поиск
listen = 127.0.0.1:3312
# Лог
log = /home/rutr/rutracker.online/www/cache/searchd.log
# Лог запросов
query_log = /home/rutr/rutracker.online/www/cache/query.log
# Таймаут на соединение с сервером
read_timeout = 5
# Максимальное кол-во потомков от процесса
max_children = 30
# Путь до pid-файла
pid_file = /home/rutr/rutracker.online/www/cache/searchd.pid
# Максимальное кол-во результатов выдачи
max_matches = 1000
}
Подключаемся к серверу через ssh. Для того что бы Sphinx смог искать по нашей базе, надо подготовить индекс. Выполняем команду:
indexer --config /home/rutr/rutracker.online/www/cache/torrents.conf –all
Sphinx некоторое время будет проводить индекс базы данных. Длительность зависит от мощности сервера. В моем случае индексирование заняло около 10 минут.
После окончания индексирования, проверим все ли нормально прошло. Для этого выполним поиск через консоль с помощью команды (поисковая фраза пишется после указания файла конфига):
search --config /home/rutr/rutracker.online/www/cache/torrents.conf morrowind mod
Если вы увидели что-то похожее на верхний скриншот, значит индексирование прошло успешно. Если ничего не найдено, то не нужно запускать следующую команду. Для запуска демона поиска Sphinx выполняем команду:
searchd --config /home/rutr/rutracker.online/www/cache/torrents.conf
Обратите внимание, что демон нужно запускать после каждой перезагрузки системы. Для выключения демона (если нужно) добавляем «--stop» в конце вышеуказанной команды.
Web
Я не долго думал какой фреймворк использовать для web-интерфейса. Требования простые: простота в использовании, адаптивный дизайн и поддержка всех современных браузеров. Под это отлично подходит, пусть и немного надоевший, Bootstrap. Дистрибутив качать не обязательно, можно подключить файл стилей онлайн. Главная страница на чистом HTML, без использования PHP. Комментарии к коду, думаю, будут излишни.
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="/favicon.ico">
<title>Зеркало раздач RuTracker</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<style type="text/css">
.inCenter {
margin: auto;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
.inCenter.isResp {
width: 50%;
height: 50%;
min-width: 400px;
max-width: 800px;
padding: 40px;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="inCenter isResp">
<div class="col-sm-12 col-md-10 col-md-offset-1">
<form action="search.php" method="GET">
<div class="form-group text-center">
<h1>Зеркало раздач RuTracker</h1>
</div>
<div class="form-group input-group">
<input class="form-control input-lg" type="text" name="q" placeholder=""/>
<span class="input-group-btn">
<button class="btn btn-primary input-lg" type="submit"><i class="glyphicon glyphicon-search"></i></button>
</span>
</div>
</form>
</div>
</div>
</div>
</div>
</body>
</html>
Дизайн главной страницы получился очень минималистичным и максимально функциональным.
Скрипт поиска будет уже интереснее. Для начала нам нужен API Sphinx на PHP. Последнюю версию можно взять здесь. Кратко расскажу, как работает скрипт поиска, а подробнее уже в листинге. Подключаем файл для работы с API, настраиваем поиск, ищем, выкладываем результаты поиска в удобном виде. Скачать торрент можно будет прямо из поиска, без дополнительных кликов.
<?
//Фильтруем и форматируем запрос
$q=trim(urldecode($_GET[q]));
//Если нет запроса на поиск, то делаем редирект на главную страницу
if (empty($q)) {header("Location: /"); exit();}
//Если запрос есть, то...
//Подключаемся к MySQL, при неудаче выводим ошибку
mysql_connect("localhost", "torrent", "password") or die("Could not connect to MySQL");
//Выбираем БД, при неудаче выводим ошибку
mysql_select_db("torrent") or die("Could not select database");
//Переводим все общение с БД в кодировку utf8
mysql_query("SET NAMES utf8");
//Подключаем API Sphinx
include("sphinxapi.php");
//Создаем объект Sphinx
$sphinx=new SphinxClient();
//Подключаемся к Sphinx-серверу. Порт мы указываем в файле "torrents.conf"
$sphinx->SetServer('localhost', 3312);
//Ищем совадение по любомым словом
$sphinx->SetMatchMode(SPH_MATCH_ANY);
//Сортируем результаты по релевантности
$sphinx->SetSortMode(SPH_SORT_RELEVANCE);
//Выводим 50 результатов начиная с первого.
$sphinx->SetLimits(0, 50);
//Запускаем поиск (* - использование всех индексов в файле "torrents.conf", но он у нас один: torrentz)
$torrents=$sphinx->Query($q, '*');
//Если раскомментировать следующие две строки, то можно увидеть ошибки и как отработал поиск
//print $sphinx->getLastError();
//print '<br><pre>'; print_r($torrents); exit();
//Функция перевода байтов в килобайты, мегабайты и тд. Пригодится нам ниже. Описывать её прицип не имеем смысла - чистая арифметика.
function bytesToSize($bytes, $precision = 0)
{
$kilobyte = 1024;
$megabyte = $kilobyte * 1024;
$gigabyte = $megabyte * 1024;
$terabyte = $gigabyte * 1024;
if (($bytes >= 0) && ($bytes < $kilobyte)) {return $bytes . ' B';}
elseif (($bytes >= $kilobyte) && ($bytes < $megabyte)) {return round($bytes / $kilobyte, $precision) . ' Kb';}
elseif (($bytes >= $megabyte) && ($bytes < $gigabyte)) {return round($bytes / $megabyte, $precision) . ' Mb';}
elseif (($bytes >= $gigabyte) && ($bytes < $terabyte)) {return round($bytes / $gigabyte, $precision) . ' Gb';}
elseif ($bytes >= $terabyte) {return round($bytes / $terabyte, $precision) . ' Tb';}
else {return $bytes . ' B';}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="/favicon.ico">
<title><?=htmlspecialchars($q)?></title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<style type="text/css">
body
{
padding-top: 80px;
padding-bottom: 20px;
}
</style>
</head>
<body>
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Навигация</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">Зеркало раздач RuTracker</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<form action="/search.php" method="GET" class="navbar-form navbar-left">
<div class="form-group input-group">
<input type="text" placeholder="" value="<?=htmlspecialchars($q)?>" class="form-control" name="q">
<span class="input-group-btn">
<button class="btn btn-primary" type="submit"><i class="glyphicon glyphicon-search"></i></button>
</span>
</div>
</form>
</div>
<!--/.navbar-collapse -->
</div>
</nav>
<div class="container">
<h1><?=htmlspecialchars($q)?></h1>
<table class="table table-striped">
<caption>Всего найдено: <?=$torrents[total_found]?></caption>
<tbody>
<?
//Преобразовывем ключи в полученном массиве результатов поиска в массив
$ids = array_keys($torrents[matches]);
//Собираем массив с id-ми записей в понятный для SQL формат
$ids = implode(',', $ids);
//Пишем SQL запрос для выборки данных по результатам поиска
$sql="SELECT
`id`,
`name`,
`hash`,
`date`,
`size`
FROM `torrents`
WHERE `id` IN (".$ids.") ORDER BY FIELD(`id`, ".$ids.")";
//Выполняем SQL запрос
$r=mysql_query($sql);
//Выводим найденные раздачи
for ($i=0; $i < mysql_num_rows($r); $i++)
{
//Переводим ряд результата запроса в массив
$f=mysql_fetch_array($r);
//Переводим дату в русский формат
$torrent_date=explode('-', $f[date]);
//Можно просто развернуть массив, но для наглядности сделаем так
$torrent_date=$torrent_date[2].'.'.$torrent_date[1].'.'.$torrent_date[0];
?>
<tr>
<td width="75%"><a href="/torrent.php?id=<?=$f[id]?>"><?=$f[name]?></a></td>
<td width="5%"><a href="magnet:?xt=urn:btih:<?=$f[hash]?>"><i class="glyphicon glyphicon-magnet"></i></a></td>
<td width="10%"><?=bytesToSize($f[size])?></td>
<td width="10%"><?=$torrent_date?></td>
</tr>
<?
}
?>
</tbody>
</table>
</div>
<!-- /.container -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="http://getbootstrap.com/dist/js/bootstrap.min.js"></script>
</body>
</html>
Для удобства пользователей, сделаем отдельную страницу для каждого торрента. Вдруг кому-то понадобится отправить ссылку.
<?
//Фильтруем и форматируем id торрента
$id=trim(urldecode($_GET[id]));
//Если нет id, то делаем редирект на главную страницу
if (empty($id)) {header("Location: /"); exit();}
//Если id есть, то...
//Подключаемся к MySQL, при неудаче выводим ошибку
mysql_connect("localhost", "torrent", "password") or die("Could not connect to MySQL");
//Выбираем БД, при неудаче выводим ошибку
mysql_select_db("torrent") or die("Could not select database");
//Переводим все общение с БД в кодировку utf8
mysql_query("SET NAMES utf8");
//Пишем SQL запрос для выборки торрента по id
$sql="SELECT * FROM `torrents` WHERE `id`='".mysql_real_escape_string($id)."'";
//Выполняем SQL запрос
$r=mysql_query($sql);
//Если нет такого id в базе, то делаем редирект на главную страницу
if (mysql_num_rows($r)==0) {header("Location: /"); exit();}
//Переводим ряд результата в массив
$torrent=mysql_fetch_array($r);
//Переводим дату в русский формат
$torrent_date=explode('-', $torrent[date]);
$torrent_date=$torrent_date[2].'.'.$torrent_date[1].'.'.$torrent_date[0];
//Функция перевода байтов в килобайты, мегабайты и тд. Пригодится нам ниже. Описывать её прицип не имеем смысла - чистая арифметика.
function bytesToSize($bytes, $precision = 0)
{
$kilobyte = 1024;
$megabyte = $kilobyte * 1024;
$gigabyte = $megabyte * 1024;
$terabyte = $gigabyte * 1024;
if (($bytes >= 0) && ($bytes < $kilobyte)) {return $bytes . ' B';}
elseif (($bytes >= $kilobyte) && ($bytes < $megabyte)) {return round($bytes / $kilobyte, $precision) . ' Kb';}
elseif (($bytes >= $megabyte) && ($bytes < $gigabyte)) {return round($bytes / $megabyte, $precision) . ' Mb';}
elseif (($bytes >= $gigabyte) && ($bytes < $terabyte)) {return round($bytes / $gigabyte, $precision) . ' Gb';}
elseif ($bytes >= $terabyte) {return round($bytes / $terabyte, $precision) . ' Tb';}
else {return $bytes . ' B';}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="/favicon.ico">
<title><?=htmlspecialchars($torrent[name])?></title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<style type="text/css">
body
{
padding-top: 80px;
padding-bottom: 20px;
}
</style>
</head>
<body>
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Навигация</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">Зеркало раздач RuTracker</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<form action="/search.php" method="GET" class="navbar-form navbar-left">
<div class="form-group input-group">
<input type="text" placeholder="" value="" class="form-control" name="q">
<span class="input-group-btn">
<button class="btn btn-primary" type="submit"><i class="glyphicon glyphicon-search"></i></button>
</span>
</div>
</form>
</div>
<!--/.navbar-collapse -->
</div>
</nav>
<div class="container">
<h1><?=htmlspecialchars($torrent[name])?></h1>
<table class="table table-striped">
<tbody>
<tr>
<th width="20%">Скачать:</th>
<td><a href="magnet:?xt=urn:btih:<?=$torrent[hash]?>"><i class="glyphicon glyphicon-magnet"></i> Magnet</a></td>
</tr>
<tr>
<th width="20%">Размер:</th>
<td><?=bytesToSize($torrent[size])?></td>
</tr>
<tr>
<th width="20%">Дата раздачи:</th>
<td><?=$torrent_date?></td>
</tr>
<tr>
<th width="20%">Раздел:</th>
<td><a target=_blank href="http://rutracker.org/forum/viewforum.php?f=<?=$torrent[cat_id]?>"><?=htmlspecialchars($torrent[cat_name])?></a></td>
</tr>
<tr>
<th width="20%">Обсуждение:</th>
<td><a target=_blank href="http://rutracker.org/forum/viewtopic.php?t=<?=$torrent[topic_id]?>">Топик #<?=$torrent[topic_id]?></a></td>
</tr>
</tbody>
</table>
</div>
<!-- /.container -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="http://getbootstrap.com/dist/js/bootstrap.min.js"></script>
</body>
</html>
Вот и всё. Мы получили полностью рабочий сайт с базой данных от RuTracker, с быстрым поиском и удобным интерфейсом. Я специально не стал добавлять фильтрацию поиска по категориям, сортировку, пагинацию и т.д, что бы был максимально чистый код с самым необходимым. Если будет интерес, я расскажу об этом всем в комментариях или в отдельной статье.
Всем большое спасибо за внимание. Пишите вопросы, всем отвечу.
Комментарии (37)
ragimovich
23.12.2015 11:22+23mysql_connect("localhost", "torrent", "password") or die("Could not connect to MySQL");
Время остановилось. Шел 2015 год. В репозиториях лежал PHP7. А на самом посещаемом IT ресурсе рунета продолжали писать mysql_connect и делать из кода лапшу.lapopator
24.12.2015 10:32Я запускаю много сайтов на различных серверах и нигде не встречал PHP7. Конечно, может быть мои сервера старые.
ragimovich
24.12.2015 20:59+1mysql_connect в статусе deprecated начиная с версии PHP 5.5, если мне память не изменяет. Актуальная версия пятой ветки PHP 5.6. Не заметить предупреждения можно только если везде ставить error_reporting(0), что при разработке/тестах очень странно. Или вы из принципа используете устаревшие функции в надежде на то, что ни один из ваших серверов никогда не обновится до актуальной версии?
aik
24.12.2015 11:54-2# apt-cache search php5 | wc -l
100
# apt-cache search php6 | wc -l
0
# apt-cache search php7 | wc -l
0
Debian Stable.MetaDone
24.12.2015 12:12+1www.digitalocean.com/community/tutorials/how-to-upgrade-to-php-7-on-ubuntu-14-04
askubuntu.com/questions/705880/how-to-install-php-7
наверно и на дебиане заведетсяaik
24.12.2015 12:18-2Это комментарий к «В репозиториях лежал PHP7».
наверно и на дебиане заведется
Может быть, зачем только? Чтобы весь старый софт переписывать?
ragimovich
24.12.2015 20:53+1Для дебиана есть отличный репозиторий обновлений связанных с web пакетов — http://dotdeb.org/
kovalevsky
23.12.2015 11:38+4Автор, а Вы в курсе, что расширение mysql и функции mysql_* deprecated c версии 5.5 и будут удалены в 7?
ragimovich
23.12.2015 11:49+2Ну, можно еще добавить, что Sphinx давно не требует специальных библиотек, а позволяет запрашивать данные по MySQL интерфейсу. Да, некоторый функционал через него пару лет назад не работал (сложная агрегация), но то, что у автора в коде, работало уже тогда.
Но вообще, больше всего меня порадовал вот этот момент
Открываем браузер, открываем url «http://site.ru/db/insert_to_db.php?f=category_10.csv». Проделываем тоже самое с каждым файлом CSV. Да, все это можно было автоматизировать, но я специально написал так, что бы было максимально всё понятно.
36 файлов. Таймаут в скрипте установлен на 3 минуты/файл. Итого, больше 1.5 часов перед монитором, вручную перебирая цифры. У меня ощущение, что автор не дошел до главы, где объясняют, как в PHP можно получить список файлов в директории, поэтому списал этот момент на «усложнение кода».Reuniko
23.12.2015 13:44-1В некоторых случаях оптимальней идти напролом, нежели придумывать элегантные решения. Я к таким случаям отношу однократную установку или настройку. Безусловно автор мог создать академический вылизанный код, однократно выполняемый при установке, но посчитал это лишней тратой времени.
ragimovich
23.12.2015 14:06+4Причём здесь «академичность»? Мне кажется, тут есть смысл говорить не об академичности, а о банальном знакомстве автора с возможностями выбранных инструментов. Или вы считаете, что тратить 1.5 часа собственного времени на заполнение базы в полуавтоматическом режиме это нормально? При том, что можно это автоматизировать буквально тремя строчками кода. Не двумястами, не пятьюстами, а тремя. Единственный вариант, когда такое может быть оправдано, это если 1.5 часа твоего времени стоят меньше, чем набор трёх строк кода.
ivvi
23.12.2015 14:19-2О том, что можно запустить несколько параллельных потоков
в разных окнах/табах, не подумал?http://site.ru/db/insert_to_db.php?f=category_*.csv
Xu4
24.12.2015 16:53+1А зачем эти сложности? За 10 минут можно такой скрипт накатать:
<?php function println($message) { echo $message, PHP_EOL; } mb_internal_encoding('UTF-8'); $db = new PDO('mysql:host=localhost;port=3306;dbname=torrent;charset=utf8', 'torrent', 'password', [ PDO::ATTR_PERSISTENT => 1, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => 0, ]); foreach (glob('csv_data/*.csv') as $file) { $fp = fopen($file, 'r'); if (!is_resource($fp)) { println("Can't open $file"); continue; } $counter = 0; while (($data = fgetcsv($fp, 0, ';')) !== false) { if (count($data) == 0 && is_null($data[0])) { continue; } $db->prepare('INSERT INTO `torrents` (`name`,`hash`,`date`,`size`,`topic_id`,`cat_id`,`cat_name`) VALUES (?,?,?,?,?,?,?)')->execute([$data[4], $data[3], $data[6], $data[5], $data[2], $data[0], $data[1]]); $counter++; } println("Processed $counter entries from $file"); fclose($fp); } println('Done');
Его можно дополнительно адаптировать к запуску из web (добавив set_time_limit и заменив PHP_EOL на <br>) — секунд за 20 это можно сделать. А так, он уже готов из консоли работать.
Xu4
24.12.2015 17:10Опять же, в MySQL можно напрямую загружать CSV-файлы — вообще тогда никаких скриптов не нужно писать.
Reuniko
23.12.2015 15:08К сожалению не понимаю математики про 1.5 часа, таймаут не равен времени исполнения, плюс можно запустить несколько параллельных потоков.
А в реальной жизни бывает так что три строчки кода стоят дороже полного рабочего дня.
ivvi
23.12.2015 14:15+1Автоматизировать и обвешивать плюшками можно до бесконечности.
В этом случае статья заняла бы много экранов, а читатели начали бы зевать уже на файле insert_to_db.php.
Гораздо важнее изложить базовые принципы, пожертовав лишними и отвлекающими внимание плюшками — с чем автор вполне нормально справился (держи пять!).
Кому не хватает автоматического обхода листинга директории — тот сам себе напишет; и ни к чему это тащить сюда, где выжимки самого главного.
з.ы. set_time_limit() лишь ограничивает время исполнения, а не устанавливает его в. Так что, скрипт может выполниться и за 10 секунд, если файл небольшой.
storoj
24.12.2015 01:14+1можно сообразить про
curl http://site.ru/db/insert_to_db.php?f=category_{1..36}.csv
lapopator
24.12.2015 10:30Я же написал «все это можно было автоматизировать, но я специально написал так, что бы было максимально всё понятно». Или Вы решили проигнорировать это предложение?
huksley
23.12.2015 18:19А как сделать чтобы обновлялось каждый час с RuTracker? Раз в месяц обновления — это очень редко.
ragimovich
23.12.2015 19:02+4Подождите пока автор дойдёт до соответствующей главы и выложит наполненный болью и безысходностью код парсера rutracker на регулярных выражениях. Ведь про DOM в его книжке еще не знают. Да и вообще DOM усложняет код — регулярки привычнее.
Mixim333
24.12.2015 03:14Пол-года назад писал на C# для своего проекта поисковик по RuTracker, ссылка на ветку: https://bitbucket.org/Mixim/watcheroffilminfo/branch/RuTrackerSearchEngine — вроде неплохо работал, все руки не доходят закончить весь проект, может поможет?
Kanedias
23.12.2015 23:00+1Просьба. Автор, залейте код на гитхаб и дайте людям оформить баги/предложения/пуллреквесты.
ragimovich
24.12.2015 00:17+2VCS усложняют разработку. ZIP — выбор настоящих программистов! Просите архив, потом выложите ссылку на архив со своими правками, там, глядишь, еще кто подтянется.
rhamdeew
24.12.2015 14:55Один мой знакомый примерно так и принимал пул-реквесты к своей CMS =) Он почему то считал что освоить VCS сложнее чем вручную мержить изменения из кучи файликов =)
lapopator
24.12.2015 10:38Модератор зачем-то удалил ссылку на сайт-пример, не понятно для чего это было сделано. Нарушений правил нету. Попробую оставить её снова. Ведь на рабочем примере будет более понятно, как все работает: rutracker.online
Igogo2012
24.12.2015 14:47+2Вот из-за такого кода и насмеиваються над PHP
Подключение в БД копипастом в 3-х разных файлах…
В трех Карл!!!
Зачем использовать mysql_connect, когда все давно используют PDO, он и не диприкейтед и безопасней в использовании?!
Ну а про выборку из базы прямо среди HTML кода, я пожалуй просто промолчу.
brdsoft
25.12.2015 23:49+1Главная страница на чистом HTML, без использования PHP
Тогда зачем файлу расширение php?
Глянул пример реализации. По запросу «terminator» 951 результат, по «terminator 1991» — 18642. Гениально.
Lolka
Поиск работает шустро и все действительно просто я понятно. Не могу сказать, что «зеркало раздач» это до конца верное название, ведь это просто поиск. Если трекер перестанет работать то и многие раздачи просто растеряют сидов через какое-то время.
Эх, проходят года, а на PHP можно написать все так-же, как когда-то.