Я максимально постараюсь писать без «воды». Минимум лишней отвлекающей информации и разглагольствований. Максимум полезной информации и рабочего кода. Я не буду поднимать вопрос зачем кому-то собственный торрент-поисковик на базе RuTracker. И я не считаю себя гуру программирования. Мы просто сделаем этот сайт вместе. Будем использовать Apache+PHP, MySQL и Sphinx. Сразу предупрежу, что на минимальном виртуальном хостинге сайт будет работать совсем не быстро.

Для начала нам надо взять саму базу. RuTracker каждый месяц выкладывает дамп своих торрентов здесь. Скачиваем, распаковываем и видим два десятка файлов CSV.

Нам нужны только те, в которых есть информация о торрентах – остальные удаляем. В файле «category_info.csv» — подсказка для тех, кому не хочется открывать каждый файл (удалить: «category_1.csv», «category_4.csv», «category_36.csv»). Открываем любой из оставшихся файлов и видим такую структуру (я сразу заменил символ «;» на новую строку, что бы было визуально удобнее):
Теперь мы добавим всю информацию в базу данных. Используем MySQL, как самую распространённую БД. У меня получилась вот такая таблица (обратите внимание: столбец «hash» — уникальный, все текстовые данные в кодировке utf8):
Затем закачиваем все файлы CSV в одну папку (например, назовем её «db») на сервере. Добавление информации о торрентах в БД осуществим с помощью не сложного скрипта, представленного ниже. Его тоже необходимо закачать в ту же папку где находятся исходные CSV-файлы.
Открываем браузер, открываем url «http://site.ru/db/insert_to_db.php?f=category_10.csv». Проделываем тоже самое с каждым файлом CSV. Да, все это можно было автоматизировать, но я специально написал так, что бы было максимально всё понятно. После этих действий в нашей таблице оказалось чуть больше 1,6 миллиона записей. Не маленькая такая база. Поиск MySQL с таким объемом данных не справится, так что поручим эту задачу Sphinx.

Установка Sphinx на различные системы производится разными способами. Все зависит от операционной системы и железа. Это тема заслуживает отдельной статьи. Но есть очень много отличных мануалов в Интернете. На русском языке тоже. Сейчас же мы займемся настройкой конфигурационного файла для Sphinx. Создаем в корневом каталоге сайта директорию, допустим, cache. Здесь будут хранится все файлы индекса Sphinx для нашего сайта. Загружаем в эту папку файл конфигурации (листинг приведен ниже).
Подключаемся к серверу через ssh. Для того что бы Sphinx смог искать по нашей базе, надо подготовить индекс. Выполняем команду:
Sphinx некоторое время будет проводить индекс базы данных. Длительность зависит от мощности сервера. В моем случае индексирование заняло около 10 минут.

После окончания индексирования, проверим все ли нормально прошло. Для этого выполним поиск через консоль с помощью команды (поисковая фраза пишется после указания файла конфига):

Если вы увидели что-то похожее на верхний скриншот, значит индексирование прошло успешно. Если ничего не найдено, то не нужно запускать следующую команду. Для запуска демона поиска Sphinx выполняем команду:

Обратите внимание, что демон нужно запускать после каждой перезагрузки системы. Для выключения демона (если нужно) добавляем «--stop» в конце вышеуказанной команды.
Я не долго думал какой фреймворк использовать для web-интерфейса. Требования простые: простота в использовании, адаптивный дизайн и поддержка всех современных браузеров. Под это отлично подходит, пусть и немного надоевший, Bootstrap. Дистрибутив качать не обязательно, можно подключить файл стилей онлайн. Главная страница на чистом HTML, без использования PHP. Комментарии к коду, думаю, будут излишни.
Дизайн главной страницы получился очень минималистичным и максимально функциональным.

Скрипт поиска будет уже интереснее. Для начала нам нужен API Sphinx на PHP. Последнюю версию можно взять здесь. Кратко расскажу, как работает скрипт поиска, а подробнее уже в листинге. ��одключаем файл для работы с API, настраиваем поиск, ищем, выкладываем результаты поиска в удобном виде. Скачать торрент можно будет прямо из поиска, без дополнительных кликов.
Для удобства пользователей, сделаем отдельную страницу для каждого торрента. Вдруг кому-то понадобится отправить ссылку.
Вот и всё. Мы получили полностью рабочий сайт с базой данных от RuTracker, с быстрым поиском и удобным интерфейсом. Я специально не стал добавлять фильтрацию поиска по категориям, сортировку, пагинацию и т.д, что бы был максимально чистый код с самым необходимым. Если будет интерес, я расскажу об этом всем в комментариях или в отдельной статье.
Всем большое спасибо за внимание. Пишите вопросы, всем отвечу.

База данных
Для начала нам надо взять саму базу. 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):
Таблица SQL
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-файлы.
Файл insert_to_db.php
<? //Ограничиваем время выполнения скрипта 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 для нашего сайта. Загружаем в эту папку файл конфигурации (листинг приведен ниже).
Файл torrents.conf
# Настройка источника откуда берутся данные 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. Комментарии к коду, думаю, будут излишни.
Файл index.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, настраиваем поиск, ищем, выкладываем результаты поиска в удобном виде. Скачать торрент можно будет прямо из поиска, без дополнительных кликов.
Файл search.php
<? //Фильтруем и форматируем запрос $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>
Для удобства пользователей, сделаем отдельную страницу для каждого торрента. Вдруг кому-то понадобится отправить ссылку.
Файл torrent.php
<? //Фильтруем и форматируем 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, с быстрым поиском и удобным интерфейсом. Я специально не стал добавлять фильтрацию поиска по категориям, сортировку, пагинацию и т.д, что бы был максимально чистый код с самым необходимым. Если будет интерес, я расскажу об этом всем в комментариях или в отдельной статье.
Всем большое спасибо за внимание. Пишите вопросы, всем отвечу.
