Encurtando links sem gordura (F3)

Encurtando links sem gordura (F3)

Não é vergonhoso encurtar links aos 13 anos, certo? Um novato, e não apenas ele, deve tentar criar seu próprio Encurtador de Links, enquanto aprende algum novo framework. Foi isso que eu fiz. O que posso dizer — o quinto Bootstrap, um framework enxuto e um pedaço da alma.

Aqui demonstração, e aqui está código. Para leitores como eu 😉

Framework, não é?

Claro que não é o Laravel e semelhantes — hoje vamos nos contentar com 65 kilobytes FatFreeFramework. Se você está familiarizado com o Python Flask, terá a sensação de que isso já foi visto em algum lugar:

#роутинг во Фласке
@app.route('/')
def hello_world():
    return 'Hello, World!'
//роутинг в Обезжиренном
$f3->route('GET /',
    function() {
        echo 'Hello, world!';
    }
);

Certo, vamos esquecer. Baixamos .zip do site oficial, descompactamos na pasta que se abre imediatamente no seu Editor de Código Favorito. Limpe o index.php e remova tudo de /ui.

Aqui tudo é bem simples — na pasta ui temos todas as Views, ou em termos simples — templates HTML aprimorados, que mostraremos ao usuário ao acessar uma URL específica.

Aqui está a estrutura do nosso "aplicativo":

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

// TODO: TODO O CÓDIGO AQUI

$f3->run();

E é isso que você precisa saber para começar. Vamos ao código!

[para o desenvolvimento, usei o local XAMPP no Windows e o VS Code, o artigo foi escrito no Notion]

Homepage

Vamos começar pela página principal. Faz sentido, não é?

//Файл: index.php

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

Agora precisamos escrever esse template. Para simplicidade, usei Bootstrap v5 alpha.

Não se esqueça de criar todos os templates na pasta ui, caso contrário, eles não serão visíveis para o framework

<!-- Файл: 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>Escrevemos (código), encurtamos (links)!</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="#">Início</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#">Artigo no Habr</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="https://nikonovs.ru">Criador</a>
                </li>
            </ul>
        </nav>

        <div class="container">
        <h1>Links curtos já estão aqui.</h1>

        <!-- Будем отправлять данные POST-запросом на /newLink -->
        <form class="mt-5 mb-3" action="/pt/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">Insira o link:</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">Encurtar!</button>
                </div>
            </div>
        <input type="hidden" name="trp-form-language" value="pt"/></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">Feito com <img width="20" height="20" src="https://image.flaticon.com/icons/svg/833/833472.svg" alt="com amor">, <a href="https://v5.getbootstrap.com/">o quinto Bootstrap</a>    e <a href="https://fatfreeframework.com/">sem gordura</a></footer>
        </div>
    </body>
</html>

E é isso, já temos a página principal funcionando. O formulário envia a URL que precisa ser encurtada via POST.
Agora vem a parte interessante (não).

Trabalho com BD

Vamos criar um BD — MySQL. Se você tiver o PhpMyAdmin instalado, crie um novo BD "linker", e depois execute este 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`);

Teremos 3 campos para cada link:

  1. Code — são 4 caracteres aleatórios após o domínio, onde ocorrerá o redirecionamento, no formato example.com/ABC1
  2. Link — O link não encurtado. Hits — o número de acessos ao link encurtado.
  3. Vou explicar brevemente o funcionamento com BD, sem gordura.

Vou explicar brevemente o princípio de trabalho com bancos de dados, sem rodeios.

set('result', $db->exec('SELECT * FROM wherever')); 
// Elas estarão disponíveis nos templates, como 

// Ou podemos usar o SQL Mapper integrado:
$row = new DBSQLMapper($db, 'links');

$row->load(array('link="https://habrahabr.ru"')); // Agora, a partir deste objeto todas as colunas da linha onde o link está disponível:
$row_value = $row->somerow; // Assim

// Naturalmente, é possível alterar os valores:
$row->link = 'https://habr.com';
$row->save(); // As alterações precisam ser salvas, o que você achou que ia acontecer?

// Mais informações sobre como trabalhar com o banco de dados estão disponíveis aqui: https://a.nikonovs.ru/MPHR Recomendo fortemente a leitura, mesmo que com a ajuda de um tradutor embutido no navegador.
?>

Vamos começar a encurtir.

Processando um novo link

Criando uma nova visão em index., que irá processar a solicitação do formulário na página principal.

Primeiro, vamos criar um novo template, muito semelhante ao primeiro (home.htm) — "newLink.htm".
". Lá, exibiremos o link encurtado e a quantidade de acessos a ele (para ver novamente essas "estatísticas", é necessário encurtir o mesmo link novamente — o endereço continuará o mesmo).
Para exibir, utilizaremos um truque com "passagem de variáveis":

set('link', $shorted_link);
$view = new View;
echo $view->render('newLink.htm');
// agora, no template, podemos usar:

Aqui está o código 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>Escrevemos (código), encurtamos (links)!</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="/pt/">Início</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#">Artigo no Habr</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="https://nikonovs.ru">Criador</a>
                </li>
            </ul>
        </nav>

        <div class="container">
        <h1>Links curtos já estão aqui.</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">Reduzido:</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">Acesse este link: ``</p>
        <input type="hidden" name="trp-form-language" value="pt"/></form>

        <a href="/pt/" class="mt-3 mb-5 btn btn-primary btn-lg">VOLTE PARA A PÁGINA PRINCIPAL</a>

        <footer class="m-2">Feito com <img width="20" height="20" src="https://image.flaticon.com/icons/svg/833/833472.svg" alt="com amor">, <a href="https://v5.getbootstrap.com/">o quinto Bootstrap</a>    e <a href="https://fatfreeframework.com/">sem gordura</a></footer>
        </div>
    </body>
</html>

Escrevendo a própria rota.

$f3->route('GET|POST /newLink', //Vamos a processar tanto POST quanto GET
    function($f3) {

            $db = new DBSQL( //Conexão ao banco de dados nova em cada Roteamento
                'mysql:host=localhost;port=3306;dbname=linker',
                'root',
                ''
            );

            //Ótima função para gerar caracteres aleatórios:
            $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; //Se o link se repetir, mostramos o código antigo
            }

            $short_link = 'https://'. $_SERVER['HTTP_HOST'] . '/' . $g_code; //Montando o link final

            //Os parâmetros de $_POST podem ser obtidos com $f3->get('POST'), notação pontual é suportada (corrija-me se estiver errado): o parâmetro "link" pode ser obtido assim: 
            $link = $f3->get('POST.link');

            if ( !empty($f3->get('POST')) ) { //Retornamos HTML, apenas se POST não está vazio.

            $f3->set('link', $short_link);
            $f3->set('hits', $check->hits);
            $view = new View;
            echo $view->render('newLink.htm');

            } else { //Caso contrário - redirecionar para a página inicial
                $f3->$f3->reroute('/');
            }

        }
);

Pronto! Na verdade, isso foi fácil.

Redirecionamento

Agora só falta um detalhe:

  1. Obter parâmetro da URL
  2. Verificar sua presença no banco de dados
  3. Obter o link correspondente do banco de dados
  4. Redirecionar o usuário
  5. Lucro!

Vamos continuar escrevendo código após o último Roteamento.

$f3->route('GET /@code', // Especificamos o parâmetro após "@", ele irá para PARAMS
    function($f3) {

        // Novamente definimos $db
        $db = new DBSQL(
            'mysql:host=localhost;port=3306;dbname=linker',
            'root',
            ''
        );

        $code = $f3->get('PARAMS.code'); // Obtendo o parâmetro

        $link = new DBSQLMapper($db,'links'); 

        // Se for possível obter o link do BD - obtemos, aumentamos o número de acessos e redirecionamos
        if ($link->load(array('code="'.$code.'"', 'link=?'))) {
            $link->hits++;
            $link->save();

            $f3->reroute($link->link);
        } else {
            $f3->reroute('/'); // Se esse link não existe - sejam bem-vindos à página inicial
        }
    }
);

Você pode ter notado que em e no route newLink, e no rote acima será definido a mesma coisa — afinal code pode coincidir com "newLink" (não pode, no gerador só letras maiúsculas), mas como ele é definido primeiro, será o que será executado primeiro.

$f3→run()!

Obrigado pela leitura!
Ficarei feliz se você escrever um comentário e corrigir se algo estiver errado.

Como tarefa de casa ou prova da preguiça do autor (eu), deixo uma lista do que pode ser feito. Afinal, é melhor aprender na prática!

  • É claro que é muito improvável, mas durante a geração $g_code pode se repetir, então sugiro que você escreva uma função para verificar isso.
  • Além disso, pode-se criar estatísticas adequadas e exibi-las com base nos acessos a /@code/stats
  • Proibir a criação de links para o próprio serviço de encurtamento, criar uma lista de recursos "protegidos" contra encurtamento
  • Recomendo fortemente que, mesmo em um projeto pequeno, você faça a validação de entrada também no lado do servidor, exibindo os erros correspondentes; não confie apenas na adição do atributo required e tipo type=«url» ao campo de entrada
    RedComrade

  • Ofereça nos comentários…

    Até mais)

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster