کوتاه کننده لینک با PHP/MYSQL/JS

کوتاه کننده لینک با پی اچ پی ، مای اس کیو ال و جاوا اسکریپت – ساخت یک انتقال دهنده لینک نیازمند این است که راه حلی را داشته باشیم که بتوانیم یک رشته طولانی را به یک رشته کوتاه تبدیل کنیم .
در این آموزش یک URL Shortener نیمه حرفه ای را خواهیم ساخت که از کیفیت خوبی برخوردار خواهد بود و از تکنولوژی Ajax پشتیبانی می کند .
از این رو با در این آموزش با تابع های کاربردی مثل :
- crc32 : این تابع رشته را گرفته و یک عدد 10 رقمی به ما برمی گرداند .
- base_convert : می توانیم داده های عددی را به مبناهای مختلفی تبدیل کنیم .
- filter_var : با کمک این تابع می توانیم ورودی های مختلفی مثل ایمیل ، url و … را اعتبارسنجی کنیم .
فایل index.php
خط 18 : از اونجایی که فرم ajax خواهد بود زمانی که آدرس وارد شد و کاربر ENTER زد نمی خواهیم هدایت بشیم بنابراین با onSubmit مقدار false برمی گردانیم کــــه ریدایرکت نشیم .
خط 19 : pattern را برای ورودی http و https تنظیم می کنیم که با یکی از این 2 شروع شود .
<?php
require_once "functions.php";
require_once "func.actions.php";
if(!empty($_GET['u']))require_once "redirect.php";
?>
<!DOCTYPE html>
<html lang="fa">
<head>
<meta charset="UTF-8">
<title>Rapidcode.iR - سورس کد</title>
<link rel="stylesheet" href="static/css/main.css">
</head>
<body>
<div class="container">
<a id="introduce" href="https://rapidcode.ir" target="_blank">رپید کد • کتابخانه مجازی برنامه نویسان</a>
<form onSubmit="return false;">
<input autofocus pattern="https:\/\/.*|http:\/\/.*" type="url" name="url-inp" id="url-inp"
placeholder="لینک مورد نظر برای کوتاه شدن"><br><br>
<input type="button" id="submit" value="کوتاه کن">
</form>
<?php if(isset($GLOBALS['is_url_correct']) && !$GLOBALS['is_url_correct']) echo generate_html_message("آدرس مورد نظر در پایگاه داده یافت نشد ." , "warning") ?>
<?php if(!empty($GLOBALS['info_msg'])) echo $GLOBALS['info_msg'] ?>
<div class="short-link-wrapper">
<button id="copy-short-link" data-clipboard-target="#short-link-copy">
<img src="static/img/clippy.svg" alt="copy text">
</button>
<input id="short-link-copy" type="url" readonly placeholder="short link goes here (;" dir="ltr">
</div>
</div>
<script src=static/js/lib/clipboard.min.js> </script>
<script src="static/js/app.js"></script>
</body>
</html>
فایل contants.php برای ثابت ها
<?php
define("HOST" , "localhost");
define("USERNAME" , "root");
define("PASSWORD" , "");
define("DB" , "link_db");
define("CURRENT_TIME" , date("Y/m/d H:i:s"));
?>
فایل functions.php برای توابع دیتابیس و تابع های کاربردی
<?php
require_once "constants.php";
$table = "link_tbl";
function validate_url(string $url)
{
$url_list = parse_url($url);
$host = $url_list['host'];
$path = $url_list['path'];
$url = str_ireplace($path , urlencode($path) , $url);
$url = str_ireplace($host . "%2f" , $host . "/" , $url);
$url = filter_var($url, FILTER_VALIDATE_URL);
return $url;
}
function show_json_message($array_data)
{
return json_encode($array_data);
}
function generate_url_token($url)
{
$crc32_number = crc32($url);
$encoded_url = base_convert($crc32_number, 10, 36);
$encoded_url_list = str_split($encoded_url, 1);
$encoded_url = "";
for ($i = 0; $i < sizeof($encoded_url_list); $i++) {
$current_index = $encoded_url_list[$i];
$letter = is_numeric($current_index) ? $current_index : strtoupper($current_index);
$encoded_url .= $letter;
}
return $encoded_url;
}
function generate_html_message($message = "", $type = "notice")
{
return "<div class=\"msg {$type}\"><p>{$message}</p></div>";
}
function remove_end_slash($url)
{
$url = strrev($url);
$url = str_split($url, 1);
if ($url[0] == "/") unset($url[0]);
$url = join($url);
$url = strrev($url);
return $url;
}
function update_views($column, $short_url)
{
$mysqli = new mysqli(HOST, USERNAME, PASSWORD, DB);
$current_time = CURRENT_TIME;
$row_updated = 0;
$mysqli->set_charset("utf8");
$stmt = $mysqli->stmt_init();
$query = "UPDATE `{$GLOBALS['table']}` SET `views` = views + 1 , `date_last_view` = ? WHERE {$column} = ?";
$stmt->prepare($query);
$stmt->bind_param('ss', $current_time, $short_url);
if ($stmt->execute()) {
$row_updated = $stmt->affected_rows ? $stmt->insert_id : 0;
}
$stmt->close();
$mysqli->close();
return $row_updated;
}
function row_select($user_query, $column, $select = "*")
{
$mysqli = new mysqli(HOST, USERNAME, PASSWORD, DB);
$row = 0;
$mysqli->set_charset("utf8");
$stmt = $mysqli->stmt_init();
$query = "SELECT {$select} FROM `{$GLOBALS['table']}` WHERE {$column}=?";
$stmt->prepare($query);
$stmt->bind_param("s", $user_query);
if ($stmt->execute() && $res = $stmt->get_result()) {
if ($stmt->affected_rows || $res->num_rows) {
$row = $res->fetch_assoc();
}
}
$stmt->close();
$mysqli->close();
return $row;
}
function row_insert($url)
{
$mysqli = new mysqli(HOST, USERNAME, PASSWORD, DB);
$views = 0;
$token_url = generate_url_token($url);
$inserted_id = 0;
$current_time = CURRENT_TIME;
$mysqli->set_charset("utf8");
$stmt = $mysqli->stmt_init();
$query = "INSERT INTO `{$GLOBALS['table']}` (link_original , link_short , date_submitted , date_last_view , views) VALUES (? , ? , ? , ? , ?)";
$stmt->prepare($query);
$stmt->bind_param('ssssi', $url, $token_url, $current_time, $current_time, $views);
if ($stmt->execute()) {
$inserted_id = $stmt->affected_rows ? $stmt->insert_id : 0;
}
$stmt->close();
$mysqli->close();
return $inserted_id;
}
فایل func.actions.php
این فایل شامل 3 تابع است که 3 عمل اصلی را هم انجام می دهد :
- تابع func_action_submit : برای زمانی که لینکی را ثبت می کنیم .
- تابع func_action_redirect : کاربر را با لینک کوتاه به لینک اصلی هدایت می کند .
- تابع func_action_redirect_info : اطلاعاتی از لینک کوتاه ثبت شده به ما می دهد شامل تاریخ ثبت لینک ، تاریخ آخرین ارجاع یا بازدید از لینک ، تعداد بازدید .
<?php
function func_action_submit($response_list, $user_url)
{
$row = row_select($user_url, "link_original");
if (empty($row)) {
$row = row_insert($user_url);
if (empty($row)) {
$response_list['status'] = 0;
$response_list['msg'] = "خطایی در هنگام ثبت داده در دیتابیس رخ داده .";
die(show_json_message($response_list));
} else {
$response_list['status'] = 1;
$response_list['msg'] = "آدرس مورد نظر با موفقیت ثبت گردید .";
$response_list['data'] = json_encode(row_select($row, "id", "link_short"));
die(show_json_message($response_list));
}
} else {
$response_list['msg'] = "این آدرس از قبل ثبت شده";
$response_list['data'] = json_encode(["link_short" => $row['link_short']]);
die(show_json_message($response_list));
}
}
function func_action_redirect($user_url)
{
$url_data = row_select($user_url, "link_short", "link_original");
$GLOBALS['is_url_correct'] = false;
if (!empty($url_data)) {
update_views("link_short", $user_url);
header("Location: {$url_data['link_original']}");
$GLOBALS['is_url_correct'] = true;
}
}
function func_action_redirect_info($user_url)
{
$url_data = row_select($user_url, "link_short", "*");
$url_data['link_original'] = urldecode($url_data['link_original']);
$GLOBALS['is_url_correct'] = false;
if (!empty($url_data)) {
$GLOBALS['info_msg'] = "<div style=\"direction: ltr;font-size:25px\" class=\"msg success\"><p>{$url_data['link_original']}</p></div><table id=\"statistics\"><tr><td>تاریخ ثبت لینک : </td><td>{$url_data['date_submitted']}</td></tr><tr><td>تاریخ آخرین ارجاع لینک : </td><td>{$url_data['date_last_view']}</td></tr><tr><td>تعداد ارجاع : </td><td>{$url_data['views']}</td></tr></table>";
$GLOBALS['is_url_correct'] = true;
}
}
فایل redirect.php
این تابع مشخص می کند که کاربر با لینک کوتاهی که وارد کرده است می خواهد به لینک اصلی هدایت شود یا آمار لینک را مشاهده کند .
<?php
if($_GET['u'] && !empty($_GET['info'])){
func_action_redirect_info($_GET['u']);
}else if($_GET['u']){
func_action_redirect($_GET['u']);
}
?>
فایل api.php
از اسمی که دارد برای endpoint استفاده می شود که درخواست های ajax به این فایل ختم می شود .
<?php
header("Content-Type: application/json");
require_once "functions.php";
require_once "func.actions.php";
$response_list = [
"status" => 0,
"msg" => "",
"data" => []
];
$action_list = [
"submit",
];
$user_url = @$_POST['inp-url'];
$action = @$_POST['action'];
if(empty($action) || !in_array($action , $action_list)){
$response_list['msg'] = "پارامتر action معتبر نمی باشد .";
die(show_json_message($response_list));
}
$user_url = remove_end_slash($user_url);
if(empty($user_url) || !validate_url($user_url)){
$response_list['msg'] = "لینک معتبری وارد نشده است .";
die(show_json_message($response_list));
}
$user_url = urldecode($user_url);
call_user_func("func_action_" . $action , $response_list , $user_url);
?>
همچنین از clipboard.js برای کپی کردن لینک ها در این پروژه استفاده کردیم که می تونید از اینجا کتابخانه را دانلود کنید .
فایل app.js
const clipboardJS = new ClipboardJS('#copy-short-link');
const submitDOM = document.getElementById("submit");
const urlInput = document.getElementById("url-inp");
const shortLinkWrapper = document.getElementsByClassName("short-link-wrapper")[0];
submitDOM.addEventListener("click", handlerSubmit);
function handlerSubmit() {
if (!urlInput.checkValidity()) {
alert("آدرس داده شده معتبر نمی باشد .");
return false;
}
submitDOM.setAttribute("disabled", "disabled");
submitDOM.value = "در حال دریافت لینک ...";
funcPostRequest(function (xhr) {
const response = xhr.currentTarget.response;
let data = response.data;
if(typeof data == "string") data = JSON.parse(data);
window.alert(response.msg);
if (data['link_short']) {
shortLinkWrapper.classList.add("active");
submitDOM.removeAttribute("disabled");
submitDOM.value = "کوتاه کن";
shortLinkWrapper.querySelector("#short-link-copy").value = location.origin + "?u="+ data['link_short'];
}
}, function () {
alert("خطایی رخ داده برای جزئیات بیشتر تب console را باز کنید")
console.warn("[XHR Error]");
submitDOM.removeAttribute("disabled");
submitDOM.value = "کوتاه کن";
});
}
function funcPostRequest(cbOnload, cbOnerror) {
const xhr = new XMLHttpRequest();
xhr.responseType = "json";
const params = new FormData;
params.append("action", "submit");
params.append("inp-url", urlInput.value);
xhr.open("POST", location.origin + "/api.php");
xhr.onload = cbOnload;
xhr.onerror = cbOnerror;
xhr.send(params);
}
فایل main.css
body{
background-image: url(../img/sea.jpg);
background-size: cover;
}
.active{
display: block !important;
}
#url-inp{
transition: 0.3s all;
width: 40%;
border: none;
outline: none;
padding: 10px;
border-radius: 25px;
text-align: center;
font-weight: bold;
}
#url-inp:focus{
width: 50%;
border: 1px solid #000;
}
#submit{
border: none;
background-color: #2196f3;
color: white;
font-weight: bold;
font-size: 25px;
padding: 10px 50px;
border-radius: 25px;
cursor: pointer;
}
#submit:hover{
background-color: #137dd3;
}
.msg{
background-color: silver;
color: #000;
border-radius: 15px;
display: inline-block;
padding: 5px 35px;
margin: 15px auto;
font-weight: bold;
}
.msg.warning{
background-color: #ffa500;
}
.msg.success{
background-color: #3f51b5;
color: white;
}
#statistics{
font-weight: bold;
background-color: rgb(255 255 255 / 79%);
border-radius: 4px;
width: 50%;
margin: 0 25%;
}
#statistics td{
padding: 12px;
}
.short-link-wrapper{
display: none;
}
#short-link-copy{
margin-top: 50px;
font-size: 24px;
background-color: #4caf50;
border: 3px #fff solid;
outline: none;
color: white;
padding: 3px 10px;
border-radius: 15px;
}
.short-link-wrapper button{
height: 25px;
}
.short-link-wrapper button img{
width: 15px;
}
ارسال نظر