
Nie ma nic wstydliwego w skracaniu linków przez 13 lat, prawda? Nawet początkujący powinien spróbować napisać własny URL Shortener, przy okazji ucząc się nowego frameworka. I tym właśnie się zająłem. Co można powiedzieć – piąta wersja bootstrap, odchudzony framework i odrobina duszy.
Oto , a oto . Dla takich czytelników, jak ja 😉
Framework, prawda?
Oczywiście to nie Laravel i podobne – dzisiaj obejdziemy się 65 kilobajtami . Jeśli znasz Python Flask, poczujesz, że już gdzieś to było:
#роутинг во Фласке
@app.route('/')
def hello_world():
return 'Hello, World!'
//роутинг в Обезжиренном
$f3->route('GET /',
function() {
echo 'Hello, world!';
}
);Dobra, zapomnijcie. Pobieramy , rozpakowujemy do folderu, który właśnie otworzy się w Twoim ulubionym edytorze kodu. Wyczyść index.php i usuń wszystko z /ui.
Tutaj wszystko jest bardzo proste – w folderze ui mamy wszystkie widoki, a mówiąc prościej – rozbudowane szablony HTML, które będziemy pokazywać użytkownikowi po wejściu na określony URL.
Oto szkielet naszej "aplikacji":
set('DEBUG', 1);
if ((float)PCRE_VERSIONconfig('config.ini');
// CAŁY POZOSTAŁY KOD BĘDZIEMY PISAĆ TUTAJ
$f3->run();To wszystko, co musisz wiedzieć, żeby zacząć. Przystąpmy do kodowania!
[do rozwoju używałem lokalnego na Windows i VS Code, ]
Strona domowa
Zacznijmy od strony głównej. To logiczne, prawda?
//Файл: index.php
$f3->route('GET /',
function($f3) { //чтобы использовать функции F3 передаем его в роут
$view = new View; // создаем вьюшку
echo $view->render('home.htm'); //рендерим шаблон
}
);Teraz musimy napisać ten szablon. Dla uproszczenia użyłem
Nie zapomnij tworzyć wszystkich szablonów w folderze ui, w przeciwnym razie nie będą widoczne dla frameworka I to wszystko, już mamy działającą stronę główną. Formularz wysyła link do skrócenia za pomocą żądania POST.
<!-- Файл: 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>Pisanie (kod), skracanie (linki)!</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="#">Strona główna</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Artykuł na Habrze</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://nikonovs.ru">Twórca</a>
</li>
</ul>
</nav>
<div class="container">
<h1>Krótkie linki są już tutaj.</h1>
<!-- Будем отправлять данные POST-запросом на /newLink -->
<form class="mt-5 mb-3" action="/pl/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">Wprowadź 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">Skróć!</button>
</div>
</div>
<input type="hidden" name="trp-form-language" value="pl"/></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">Zrobione z <img width="20" height="20" src="https://image.flaticon.com/icons/svg/833/833472.svg" alt="z miłością">, <a href="https://v5.getbootstrap.com/">piątą wersją Bootstrap'a</a> i <a href="https://fatfreeframework.com/">bez zbędnych dodatków</a></footer>
</div>
</body>
</html>Teraz najciekawsze (nie).
Praca z bazą danych
Utwórzmy bazę danych – MySQL. Jeśli masz zainstalowane PhpMyAdmin, utwórz nową bazę danych "
linker", a następnie wykonaj ten 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`);
Będziemy mieli 3 pola dla każdego linku:Kod – to losowe 4 znaki po domenie, według których będzie realizowane przekierowanie, w formie
- example.com/ABC1 Link –
- nieskrócony link. Liczba kliknięć – liczba przejść przez skrócony link.
- Krótko opowiem o zasadzie działania z bazą danych, bez zbędnego balastu.
Krótko wyjaśnię zasadę pracy z bazą danych, bez zbędnych informacji.
set('result', $db->exec('SELECT * FROM wherever'));
// będą one dostępne w szablonach jako
// Można też użyć wbudowanego mappera SQL:
$row = new DBSQLMapper($db, 'links');
$row->load(array('link="https://habrahabr.ru"')); // teraz z tego obiektu dostępne są wszystkie kolumny wiersza, gdzie link prowadzi do Habr:
$row_value = $row->somerow; // Tak
// Oczywiście można zmieniać wartości:
$row->link = 'https://habr.com';
$row->save(); // zmiany muszą być zapisane, a co myśleliście
// Więcej informacji na temat pracy z bazą danych znajduje się tutaj: https://a.nikonovs.ru/MPHR Zdecydowanie polecam przeczytać, chociażby z pomocą tłumacza wbudowanego w przeglądarkę.
?>Przystępujemy do skracania.
Obsługa nowego linku
Tworzymy nowy widok w indexie, który będzie obsługiwał zapytanie z formularza na stronie głównej.
Najpierw stworzymy nowy, ale bardzo podobny do pierwszego (home.htm) szablon – "newLink.htm".
Tam będziemy wyświetlać już skrócony link i liczbę kliknięć w niego (aby znowu zobaczyć tę "statystykę", należy ponownie skrócić ten sam link – adres pozostanie ten sam).
Do wyświetlania skorzystamy z triku "przekazywania zmiennych":
set('link', $shorted_link);
$view = new View;
echo $view->render('newLink.htm');
// teraz w szablonie można używać:A oto listing 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>Pisanie (kod), skracanie (linki)!</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="/pl/">Strona główna</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Artykuł na Habrze</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://nikonovs.ru">Twórca</a>
</li>
</ul>
</nav>
<div class="container">
<h1>Krótkie linki są już tutaj.</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">Skrócone:</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">Przejścia przez ten link: ``</p>
<input type="hidden" name="trp-form-language" value="pl"/></form>
<a href="/pl/" class="mt-3 mb-5 btn btn-primary btn-lg">WRÓĆ DO STRONY GŁÓWNEJ</a>
<footer class="m-2">Zrobione z <img width="20" height="20" src="https://image.flaticon.com/icons/svg/833/833472.svg" alt="z miłością">, <a href="https://v5.getbootstrap.com/">piątą wersją Bootstrap'a</a> i <a href="https://fatfreeframework.com/">bez zbędnych dodatków</a></footer>
</div>
</body>
</html>Piszę sam router.
$f3->route('GET|POST /newLink', ///// We will handle both POST and GET
function($f3) {
$db = new DBSQL( ///// Connecting to the new DB in each Route
'mysql:host=localhost;port=3306;dbname=linker',
'root',
''
);
///// A wonderful function for generating random characters:
$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; ///// if the link is repeated, we show the old code
}
$short_link = 'https://'. $_SERVER['HTTP_HOST'] . '/' . $g_code; ///// Assembling final link
///// Parameters from $_POST can be obtained using $f3->get('POST'), dotted notation is supported (please correct me if I'm wrong): parameter "link" can be obtained like this:
$link = $f3->get('POST.link');
if ( !empty($f3->get('POST')) ) { ///// Output HTML, only if POST is not empty.
$f3->set('link', $short_link);
$f3->set('hits', $check->hits);
$view = new View;
echo $view->render('newLink.htm');
} else { ///// otherwise - redirect to the main page
$f3->$f3->reroute('/');
}
}
);Got it! In fact, it was simple.
Redirection
The final step remains:
- Get parameter from URL
- Check its presence in the DB
- Retrieve the corresponding link from the DB
- Redirect the user
- Zysk!
Continuing to write code after the last Route.
$f3->route('GET /@code', // wskazujemy parametr po "@", trafi do PARAMS
function($f3) {
// ponownie definiujemy $db
$db = new DBSQL(
'mysql:host=localhost;port=3306;dbname=linker',
'root',
''
);
$code = $f3->get('PARAMS.code'); // pobieramy parametr
$link = new DBSQLMapper($db,'links');
// jeśli udaje się pobrać link z bazy danych - pobieramy, zwiększamy liczbę przejść i przekierowujemy
if ($link->load(array('code="'.$code.'"', 'link=?'))) {
$link->hits++;
$link->save();
$f3->reroute($link->link);
} else {
$f3->reroute('/'); // a jeśli takiego linku nie ma - zapraszamy na stronę główną
}
}
);Mogłeś zauważyć, że w i w trasie newLink, i w powyższej trasie będą definiowane te same rzeczy — bowiem może pokrywać się z "newLink" (nie może, w generatorze tylko litery wielkie), ale ponieważ on jest najpierw zdefiniowany, to on i się wykona jako pierwszy.
$f3->run()!
Dziękujemy za przeczytanie!
Będę wdzięczny, jeśli napiszesz komentarz i poprawisz, jeśli coś jest nie tak.
A w ramach pracy domowej lub dowodu lenistwa autora (mnie) zostawiam listę, co można by zrobić. W końcu lepiej uczyć się w praktyce!
- To oczywiście mało prawdopodobne, ale przy generowaniu $g_code może się powtórzyć, więc proponuję napisać funkcję, która to sprawdzi.
- Można także zrobić normalną statystykę i wyświetlać ją przy przejściu na /@code/stats
- Zabroń tworzenia linków do samego serwisu skracania linków, stwórz listę "chronionych" przed skracaniem zasobów
Zalecam nawet w tak małej sprawie przeprowadzić walidację wejścia również po stronie serwera, z odpowiednim wyświetlaniem błędów, nie polegaj tylko na dodaniu atrybutu required i typu type="url" do pola wejściowego
Propozycje w komentarzach…
Na łączach)
Źródło: habr.com
