[PHP, Анализ и проектирование систем, Apache, DIY или Сделай сам, Flask] Сокращаем ссылки без жира (F3)

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
18-Авг-2020 17:38


Сокращать ссылки в 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. © <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(10) NOT NULL,
  `link` varchar(255) NOT NULL,
  `hits` int(255) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ALTER TABLE `links`
  ADD UNIQUE KEY `code` (`code`);

У нас будет 3 поля у каждой ссылки:
  • Code — это рандомные 4 символа после домена, по которым будет происходить перенаправление, вида example.com/ABC1
  • Link — Не сокращенная ссылка.
  • 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('/');
            }
        }
);

Готово! На самом деле, это было просто.
Перенаправление
Дело осталось за малым:
  • Получить параметр из URL
  • Проверить его наличие в БД
  • Получить из БД соответствующую ссылку
  • Перенаправить пользователя
  • 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->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
  • Предлагайте в комментарии...
    На связи)

===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_php, #_analiz_i_proektirovanie_sistem (Анализ и проектирование систем), #_apache, #_diy_ili_sdelaj_sam (DIY или Сделай сам), #_flask, #_sokraschenie_ssylok (сокращение ссылок), #_fatfree_framework, #_php, #_phpframework, #_php, #_analiz_i_proektirovanie_sistem (
Анализ и проектирование систем
)
, #_apache, #_diy_ili_sdelaj_sam (
DIY или Сделай сам
)
, #_flask
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 21:11
Часовой пояс: UTC + 5