کوتاه کننده لینک با 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; }
ارسال نظر