Сокращаем ссылки без жира (F3)

от автора

Сокращать ссылки в 13 лет не стыдно, верно?
Новичку, да и не только новичку, стоит попробовать написать свой Укротитель Ссылок, походу изучая какой-нибудь новый фреймворк. Чем я и занялся. Что сказать — пятый бутстрап, обезжиренный фреймворк и частичка души.

Вот демо, а вот код. Для таких читателей, как я 😉

Фреймворк, не так ли?

Конечно не Laravel и тому подобные — сегодня обойдёмся 65-ю килобайтами FatFreeFramework. Если Вы знакомы с Python Flask, то возникнет ощущение, что где-то это уже было:

#роутинг во Фласке @app.route('/') def hello_world():     return 'Hello, World!' 


//роутинг в Обезжиренном $f3->route('GET /',     function() {         echo 'Hello, world!';     } );

Ладно, забудьте. Скачиваем .zip с офф.сайта, распаковываем в папку, которая в этот же миг открывается в вашем Любимом Редакторе Кода. Очистите index.php и удалите все из /ui.

Здесь все предельно просто — в папке ui у нас все Вьюшки, а если по простому — прокачанные ХТМЛ шаблоны, которые мы будем показывать пользователю при заходе на определенный URL.

Вот каркас нашего "приложения":

<?php //Файл: index.php  // Kickstart the framework $f3=require('lib/base.php'); $f3->set('DEBUG', 1); if ((float)PCRE_VERSION<8.0)     trigger_error('PCRE version is out of date'); $f3->config('config.ini');  //ВЕСЬ ОСТАЛЬНОЙ КОД БУДЕМ ПИСАТЬ ЗДЕСЬ  $f3->run();

Вот и все, что нужно знать для начала. Приступаем к кодингу!

[для разработки я использовал локальный XAMPP на Windows и VS Code, статья написана в Ноушене]

Homepage

Начнем с главной страницы. Логично, правда?

//Файл: index.php  $f3->route('GET /',     function($f3) { //чтобы использовать функции F3 передаем его в роут                 $view = new View; // создаем вьюшку         echo $view->render('home.htm'); //рендерим шаблон     } );

Теперь нужно этот самый шаблон написать. Для простоты я использовал бутстрап v5 alpfa.

Не забудьте создавать все шаблоны в папке ui, иначе они не будут видны фреймворку

<!-- Файл: ui/home.htm -->  <!DOCTYPE html> <html lang="en">     <head>         <meta charset="<?php echo $ENCODING; ?>" />         <meta name="viewport" content="width=device-width, initial-scale=1">         <title>Пишем (код), сокращаем (ссылки)!</title>         <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/css/bootstrap.min.css" integrity="sha384-r4NyP46KrjDleawBgD5tp8Y7UzmLA05oM1iAEQ17CSuDqnUK2+k9luXQOfXJCJ4I" crossorigin="anonymous">     </head>     <body class="text-center bg-dark text-light"> <!-- темная тема ;) -->          <!-- менюшка -->         <nav class="m-2">             <ul class="nav nav-pills justify-content-center">                 <li class="nav-item">                     <a class="nav-link active" aria-current="page" href="#">Главная</a>                 </li>                 <li class="nav-item">                     <a class="nav-link" href="#">Статья на Хабре</a>                 </li>                 <li class="nav-item">                     <a class="nav-link" href="https://nikonovs.ru">Создатель</a>                 </li>             </ul>         </nav>          <div class="container">         <h1>Короткие ссылки уже здесь.</h1>          <!-- Будем отправлять данные POST-запросом на /newLink -->         <form class="mt-5 mb-3" action="/newLink/" method="POST">             <div class="row justify-content-center">                 <div class="col-auto">                 <label for="inputLink" class="col-form-label">Введи ссылку:</label>                 </div>                 <div class="col-auto">                 <input required placeholder="https://" type="url" name="link" id="inputLink" class="form-control mb-1" aria-describedby="inputLink">                 </div>                 <div class="col-auto">                 <button type="submit" class="btn btn-outline-primary">Сократить!</button>                 </div>             </div>         </form>          <!-- немного текста с Кликера -->         <p class="text-left m-auto mb-5" style="max-width: 30rem;">Довольно часто при общении в интернете люди пересылают друг другу ссылки. Иногда эти ссылки бывают длинными. Совсем иногда — очень длинными. Но почти всегда — слишком длинными. Для того чтобы избавиться от этой проблемы, был создан этот сайт. Да, я знаю, что таких тысячи, но этот же лучше!             А дальше все просто: вставляете ссылку в поле для ввода, нажимаете "Сократить!" и получаете короткий, совсем короткий URL. &copy; <a href="https://clck.ru">Кликер</a></p>          <footer class="m-2">Сделано с <img width="20" height="20" src="https://image.flaticon.com/icons/svg/833/833472.svg" alt="любовью">, <a href="https://v5.getbootstrap.com/">пятым Bootstrap'ом</a>    и <a href="https://fatfreeframework.com/">без жира</a></footer>         </div>     </body> </html>

Вот и все, у нас уже работает главная страница. Форма отправляет POST-запросом ссылку, которую нужно сократить.
Теперь самое интересное (нет).

Работа с БД

Создадим БД — MySQL. Если у Вас установлен PhpMyAdmin, то создайте новую БД "linker", а потом выполните этот SQL:

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET time_zone = "+00:00";  CREATE TABLE IF NOT EXISTS `links` (   `code` varchar(4) NOT NULL,   `link` varchar(1000) NOT NULL,   `hits` int(255) NOT NULL DEFAULT '0' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;  ALTER TABLE `links`   ADD UNIQUE KEY `code` (`code`);

У нас будет 3 поля у каждой ссылки:

  1. Code — это рандомные 4 символа после домена, по которым будет происходить перенаправление, вида example.com/ABC1
  2. Link — Не сокращенная ссылка.
  3. Hits — количество переходов по сокращенной ссылке.

Кратко расскажу принцип работы с БД, без жира.

<?php //сначала нужно подключиться к БД $db = new DB\SQL(     'mysql:host=localhost;port=3306;dbname=linker',     'root',     '' );  //Дальше есть два варианда работы с данными:  //Можно установить переменную в Фреймворк c помощью обычного SQL-запроса: $f3->set('result', $db->exec('SELECT * FROM wherever'));  //они будут доступны в шаблонах, как <?= $resul ? >  //А можно использовать встроенный SQL Mapper: $row = new DB\SQL\Mapper($db, 'links');  $row->load(array('link="https://habrahabr.ru"')); //теперь из этого объекта доступны все колонки строки, где ссылка на Хабр: $row_value = $row->somerow; //Вот так  // Естесственно можно изменять значения: $row->link = 'https://habr.com'; $row->save(); //изменения нужно сохранить, а что вы думали  // больше информации по работе с БД доступно здесь: https://a.nikonovs.ru/MPHR Настоятельно рекомендую прочитать, хотябы с помощью переводчика, встроенного в браузер. ?>

Приступаем к Укорачиванию.

Обработка новой ссылки

Создаем новую Вьюшку в index’e, которая будет обрабатывать запрос из формы на главной странице.

Сначала создадим новый, но очень похожий на первый (home.htm) шаблон — "newLink.htm".
Там мы будем выводить уже сокращенную ссылку и количество переходов по ней (чтобы снова увидеть эту "статистику" нужно снова сократить эту же ссылку — адрес останется тот же).
Для вывода воспользуемся трюком с "переходом переменных":

<?php //Файл: нет (пример)  //устанавливаем переменную в index'е и рендерим шаблон $f3->set('link', $shorted_link); $view = new View; echo $view->render('newLink.htm'); //теперь в шаблоне можно использовать: <?= $link ?>

А вот и листинг newLink.html:

<!-- Файл: newLink.htm -->  <!DOCTYPE html> <html lang="en">     <head>         <meta charset="<?php echo $ENCODING; ?>" />         <meta name="viewport" content="width=device-width, initial-scale=1">         <title>Пишем (код), сокращаем (ссылки)!</title>         <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/css/bootstrap.min.css" integrity="sha384-r4NyP46KrjDleawBgD5tp8Y7UzmLA05oM1iAEQ17CSuDqnUK2+k9luXQOfXJCJ4I" crossorigin="anonymous">     </head>     <body class="text-center bg-dark text-light">         <nav class="m-2">             <ul class="nav nav-pills justify-content-center">                 <li class="nav-item">                     <a class="nav-link" aria-current="page" href="/">Главная</a>                 </li>                 <li class="nav-item">                     <a class="nav-link" href="#">Статья на Хабре</a>                 </li>                 <li class="nav-item">                     <a class="nav-link" href="https://nikonovs.ru">Создатель</a>                 </li>             </ul>         </nav>          <div class="container">         <h1>Короткие ссылки уже здесь.</h1>          <!-- Убираем из формы функционал формы и выводим переменные -->         <form class="mt-5 mb-3">             <div class="row justify-content-center">                 <div class="col-auto">                     <label for="inputLink" class="col-form-label">Сократили:</label>                 </div>                 <div class="col-auto">                     <input disabled required type="url" name="link" id="inputLink" class="form-control disabled" aria-describedby="inputLink" value="<?= $link ?>">                 </div>             </div>             <p class="m-2 text-secondary">По этой ссылке перешли: `<?= $hits ?>`</p>         </form>          <a href="/" class="mt-3 mb-5 btn btn-primary btn-lg">ВЕРНУТЬСЯ НА ГЛАВНУЮ</a>          <footer class="m-2">Сделано с <img width="20" height="20" src="https://image.flaticon.com/icons/svg/833/833472.svg" alt="любовью">, <a href="https://v5.getbootstrap.com/">пятым Bootstrap'ом</a>    и <a href="https://fatfreeframework.com/">без жира</a></footer>         </div>     </body> </html>

Пишем сам роут.

$f3->route('GET|POST /newLink', //мы будем обрабатывать и POST и GET     function($f3) {              $db = new DB\SQL( //Подключение к БД новое в каждом Роуте                 'mysql:host=localhost;port=3306;dbname=linker',                 'root',                 ''             );              //прекрасная функция генерации радомных символов:             $permitted_chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';             function generate_string($input, $strength = 4) {                 $input_length = strlen($input);                 $random_string = '';                 for($i = 0; $i < $strength; $i++) {                     $random_character = $input[mt_rand(0, $input_length - 1)];                     $random_string .= $random_character;                 }                  return $random_string;             }              //проверка на повторение link - нам же не нужно чтобы каждый раз генерировались новые ссылки. link - уникальный.             $check = new DB\SQL\Mapper($db,'links');             $check->load(array('link="'. $link .'"'));             if ($check->dry()) {                 $g_code = generate_string($permitted_chars);                 $row = new DB\SQL\Mapper($db,'links');                 $row->reset();                 $row->code = $g_code;                 $row->link = $link;                 $row->save();             } else {                 $g_code = $check->code; //если link повторяется, то показываем старый код             }              $short_link = 'https://'. $_SERVER['HTTP_HOST'] . '/' . $g_code; //собираем конечную ссылку              //параметры из $_POST можно получить с помощью $f3->get('POST'), поддерживается точечная нотация (поправьте, если неправильно называю): параметр "link" можно получить так:              $link = $f3->get('POST.link');              if ( !empty($f3->get('POST')) ) { //Выдаем HTML, только если POST не пустой.              $f3->set('link', $short_link);             $f3->set('hits', $check->hits);             $view = new View;             echo $view->render('newLink.htm');              } else { //иначе - редирект на главную                 $f3->$f3->reroute('/');             }          } );

Готово! На самом деле, это было просто.

Перенаправление

Дело осталось за малым:

  1. Получить параметр из URL
  2. Проверить его наличие в БД
  3. Получить из БД соответствующую ссылку
  4. Перенаправить пользователя
  5. Profit!

Продолжаем писать код после прошлого Роута.

$f3->route('GET /@code', //указываем параметр после "@", он попадет в PARAMS     function($f3) {          //снова определяем $db         $db = new DB\SQL(             'mysql:host=localhost;port=3306;dbname=linker',             'root',             ''         );          $code = $f3->get('PARAMS.code'); //получаем параметр          $link = new DB\SQL\Mapper($db,'links');           //если получается получить ссылку из БД - получаем, увеличиваем количество переходов и перенаправляем         if ($link->load(array('code="'.$code.'"', 'link=?'))) {             $link->hits++;             $link->save();              $f3->reroute($link->link);         } else {             $f3->reroute('/'); //а если такой ссылки нет - милости просим на главную         }     } );

Вы могли заметить, что в и в роуте newLink, и в роуте выше определятся одно и тоже — ведь code может совпасть с "newLink" (не может, в генераторе только буквы верхнего регистра), но так как сначала определен он, то он и выполнится первым.

$f3→run()!

Спасибо за прочтение!
Я буду рад, если Вы напишете комментарий, и поправите если что не так.

А в качестве домашнего задания или доказательства лени автора (меня), оставляю списочек, что можно сделать. Ведь лучше учиться на практике!

  • Это конечно маловероятно, но при генерации $g_code может повториться, так что предлагаю вам написать функцию, которая будет это проверять.
  • Еще можно сделать нормальную статистику и выводить ее по переходу на /@code/stats
  • Запретить создавать ссылки на сам сервис сокращения ссылок, создать список "защищенных" от укорачивания ресурсов
  • Настоятельно рекомендую даже в таком маленьком деле делать валидацию ввода и на стороне сервера, с выводом соответствующих ошибок, не стоит полагаться на добавление аттрибута required и типа type=«url» к полю ввода
    RedComrade

  • Предлагайте в комментарии…

    На связи)

ссылка на оригинал статьи https://habr.com/ru/post/515636/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *