Съкращаваме връзки без излишъци (F3)

Съкращаваме връзки без излишъци (F3)

Не е срамно да съкращаваш линкове на 13 години, нали? На начинаещите, а и не само на тях, си струва да опитат да напишат свой Линк Укротител, учейки се на някой нов фреймуорк. Именно това направих. Какво да кажа — пети Bootstrap, обезмаслен фреймуорк и малко душа.

Ето демо, а ето код. За читатели като мен 😉

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

Разбира се, не е 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 имаме всички наши View-ове, а на прост език — обновени HTML шаблони, които ще покажем на потребителя при посещение на определен URL.

Ето и основата на нашето "приложение":

set('DEBUG', 1);
if ((float)PCRE_VERSIONconfig('config.ini');

//ЦЕЛИЯТ ОСТАНАЛ КОД ЩЕ НАПИШЕМ ТУК

$f3->run();

Ето и всичко, което трябва да знаете, за да започнете. Да започваме с кодирането!

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

Началната страница

Да започнем с главната страница. Логично, нали?

//Файл: index.php

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

Сега трябва да напишем същия шаблон. За простота използвах Bootstrap v5 alpha.

Не забравяйте да създавате всички шаблони в папка 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="/bg/newLink/" method="POST" data-trp-original-action="/newLink/">
            <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>
        <input type="hidden" name="trp-form-language" value="bg"/></form>

        <!-- немного -->
        <p class="text-left m-auto mb-5" style="max-width: 30rem;">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Omnis illum molestiae hic fugiat molestias nemo, architecto beatae repellat ullam exercitationem non ab, necessitatibus maxime quod iure ipsa quam quos! Reprehenderit. Lorem ipsum dolor, sit amet consectetur adipisicing elit. Necessitatibus eos sapiente voluptates veniam sequi delectus totam tenetur praesentium obcaecati. Repudiandae quisquam, ipsa ullam corrupti molestiae minima optio nihil est modi?</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 — брой посещения по съкратената връзка.

Накратко ще обясня принципа на работа с БД, без излишно.

set('result', $db->exec('SELECT * FROM wherever')); 
// те ще бъдат достъпни в шаблоните, като 

// Или можете да използвате вградения SQL Mapper:
$row = new DBSQLMapper($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 Настоятельно препоръчвам да прочетете, макар и с помощта на преводач, вграден в браузъра.
?>

Започваме с Укорачаването.

Обработка на нов линк

Създаваме нова View в index’e, която ще обработва запитването от формата на главната страница.

Първо ще създадем нов, но много подобен на първия (home.htm) шаблон — "newLink.htm".
Там ще извеждаме вече съкратената връзка и броя на преминаванията по нея (за да видим отново тази "статистика", трябва отново да съкратим същата връзка — адресът остава същият).
За извеждането ще използваме трик с "предаване на променливи":

set('link', $shorted_link);
$view = new View;
echo $view->render('newLink.htm');
// сега в шаблона можете да използвате:

А ето и листингът 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="/bg/">Начало</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" action="">
            <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">Преминали по тази връзка: ``</p>
        <input type="hidden" name="trp-form-language" value="bg"/></form>

        <a href="/bg/" 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 DBSQL( //Свързване с БД ново за всеки Рут
                '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 load(array('link="'. $link .'"'));
            if ($check->dry()) {
                $g_code = generate_string($permitted_chars);
                $row = new DBSQLMapper($db,'links');
                $row->reset();
                $row->code = $g_code;
                $row->link = $link;
                $row->save();
            } else {
                $g_code = $check->code; //ако линкът се дублира, показваме стария код
            }

            $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 DBSQL(
            'mysql:host=localhost;port=3306;dbname=linker',
            'root',
            ''
        );

        $code = $f3->get('PARAMS.code'); //получаваме параметъра

        $link = new DBSQLMapper($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

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

    На връзка)

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster