چطور با PHP کوتاه کننده لینک بسازیم؟
چطور با PHP کوتاه کننده لینک بسازیم؟

اگر تا به حال پیوندی را در رسانه های اجتماعی خود به اشتراک گذاشته باشید حتما متوجه آن شده اید که چقدر طولانی و ناخوانا است. استفاده از یک کوتاه کننده لینک به اشتراک گذاشتن پیوند ها را نه تنها ساده می کند بلکه خواندن آنها را نیز راحت تر میکند. جالب است بدانید طول یک پیوند و یا کاراکتر های استفاده شده در آن بر روی اعتبار آن URL تاثیر گذار است؛ شما ممکن است یک پیوند ایمن و بدون مشکل را به اشتراک بگذارید ولی طولانی بودن و ناخوانا بودن آن موجب شک افراد بشود و آنها با خود فکر کنند که آیا میتوانند از ن دیدن کنند یا آیا میتوانند آن را به اشتراک بگذارند یا خیر. از طرف دیگر یک پیوندی که کوتاه  و قابل خواندن باشد خود به خود اعتبار پیدا خواهد کرد.

در این مقاله نحوه ساخت یک کوتاه کنند لینک با زبان PHP را آموزش خواهیم داد.

نیازمندی ها :

شما برای درک این آموزش لازم است که با فرآیند توسعه وب آشنایی داشته باشید و بر روی PHP و MySQL تسلط کافی داشته باشید.

  • ایجاد جدول در پایگاه داده:

ما از پایگاه داده برای کنترلر و رسیدگی به تغییر مسیر بر اساس پیوند های کوتاه شده استفاده خواهیم نمود. دستور SQL زیر جدول short_urls  را در پایگاه داده MySQL ایجاد می کند. ما از این جدول برای ذخیره اطلاعات URL استفاده خواهیم نمود؛ این اطلاعات عبارت خواهند بود از پیوند طولانی (lLONG URL), پیوند کوتاه (SHORT CODE), بازدید ها (HITS) و زمان ایجاد رکورد (create time)

CREATE TABLE `short_urls` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `long_url` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `short_code` varchar(25) COLLATE utf8_unicode_ci NOT NULL,
 `hits` int(11) NOT NULL,
 `created` datetime NOT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
  • کتابخانه کوتاه کننده پیوند (Shortener.class.php):

کلاس کوتاه کننده پیوند این امکان را به شما میدهد که تا با روش برنامه نویسی و استفاده از PHP و MySQL لینک های کوتاه ایجاد کنید. این کلاس از PDO Extension برای کار با پایگاه داده MySQL استفاده می کند ، بنابراین ، نمونه شیء PDO برای راه اندازی کلاس Shortener مورد نیاز است.

متغییر ها استاتیک ما عبارت خواهند بود از :

  • chars: کاراکتر های مجاز برای پیوند کوتاه ( گروه کاراکتر ها با | از هم جدا میشوند)
  • table: جدول پایگاه داده برای ذخیره سازی اطلاعات URL و پیوند کوتاه.
  • checkUrlExists: روی TRUE تنظیم کنید تا بررسی کنید آیا URL طولانی وجود دارد یا خیر.
  • codeLength: طول کاراکترهای لینک کوتاه.

لیست توابع ما به صورت زیر خواهد بود:

  • construct: مرجع و زمان بندی شیء PDO را تنظیم میکند.
  • urlToShortCode: اعتبار سنجی URL و ایجاد لینک کوتاه.
  • validateUrlFormat: برای ارزیابی فرمت URL
  • verifyUrlExists: با استفاده از cURL در PHP وجود و یا عدم وجود پیوند را بررسی میکند.
  • urlExistsInDB: بررسی میکند آیا پیوند طولانی در پایگاه داده وجود دارد یا خیر. اگر وجود داشته باشد پیوند کوتاه را برمیگرداند اگر نه مقدار FALSE برمیگرداند.
  • createShortCode: ایجاد یک کد کوتاه برای URL طولانی و وارد کردن URL طولانی و لینک کوتاه در پایگاه داده.
  • generateRandomString: ایجاد رشته تصادفی (کد کوتاه) با نویسه های مشخص شده در متغیر chars.
  • insertUrlInDB: اطلاعات URL را با استفاده از PDO Extension و MySQL در پایگاه داده وارد کرده و شناسه ردیف ( row ID) را بازگردانید.
  • shortCodeToUrl: کد کوتاه را به URL طولانی تبدیل کرده و تعداد بازدیدها را در پایگاه داده وارد میکنید.
  • validateShortCode: لینک کوتاه را براساس کاراکتر های مجاز ارزیابی میکند.
  • getUrlFromDB: پیوند را براساس لینک کوتاه از پایگاه داده دریافت میکند.
  • incrementCounter: افزایش شمارنده بازدیدهای URL در پایگاه داده برای یک رکورد خاص.
<?php
/** 
 * Class to create short URLs and decode shortened URLs
 * 
 * @author www.maryam-hajireza.ir 
 * @copyright Copyright (c) 2021, www.maryam-hajireza.ir
 * @url https://www.maryam-hajireza.ir 
 */ 
class Shortener
{
    protected static $chars = "abcdfghjkmnpqrstvwxyz|ABCDFGHJKLMNPQRSTVWXYZ|0123456789";
    protected static $table = "short_urls";
    protected static $checkUrlExists = false;
    protected static $codeLength = 7;

    protected $pdo;
    protected $timestamp;

    public function __construct(PDO $pdo){
        $this->pdo = $pdo;
        $this->timestamp = date("Y-m-d H:i:s");
    }

    public function urlToShortCode($url){
        if(empty($url)){
            throw new Exception("No URL was supplied.");
        }

        if($this->validateUrlFormat($url) == false){
            throw new Exception("URL does not have a valid format.");
        }

        if(self::$checkUrlExists){
            if (!$this->verifyUrlExists($url)){
                throw new Exception("URL does not appear to exist.");
            }
        }

        $shortCode = $this->urlExistsInDB($url);
        if($shortCode == false){
            $shortCode = $this->createShortCode($url);
        }

        return $shortCode;
    }

    protected function validateUrlFormat($url){
        return filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_HOST_REQUIRED);
    }

    protected function verifyUrlExists($url){
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_NOBODY, true);
        curl_setopt($ch,  CURLOPT_RETURNTRANSFER, true);
        curl_exec($ch);
        $response = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        return (!empty($response) && $response != 404);
    }

    protected function urlExistsInDB($url){
        $query = "SELECT short_code FROM ".self::$table." WHERE long_url = :long_url LIMIT 1";
        $stmt = $this->pdo->prepare($query);
        $params = array(
            "long_url" => $url
        );
        $stmt->execute($params);

        $result = $stmt->fetch();
        return (empty($result)) ? false : $result["short_code"];
    }

    protected function createShortCode($url){
        $shortCode = $this->generateRandomString(self::$codeLength);
        $id = $this->insertUrlInDB($url, $shortCode);
        return $shortCode;
    }
    
    protected function generateRandomString($length = 6){
        $sets = explode('|', self::$chars);
        $all = '';
        $randString = '';
        foreach($sets as $set){
            $randString .= $set[array_rand(str_split($set))];
            $all .= $set;
        }
        $all = str_split($all);
        for($i = 0; $i < $length - count($sets); $i++){
            $randString .= $all[array_rand($all)];
        }
        $randString = str_shuffle($randString);
        return $randString;
    }

    protected function insertUrlInDB($url, $code){
        $query = "INSERT INTO ".self::$table." (long_url, short_code, created) VALUES (:long_url, :short_code, :timestamp)";
        $stmnt = $this->pdo->prepare($query);
        $params = array(
            "long_url" => $url,
            "short_code" => $code,
            "timestamp" => $this->timestamp
        );
        $stmnt->execute($params);

        return $this->pdo->lastInsertId();
    }
    
    public function shortCodeToUrl($code, $increment = true){
        if(empty($code)) {
            throw new Exception("No short code was supplied.");
        }

        if($this->validateShortCode($code) == false){
            throw new Exception("Short code does not have a valid format.");
        }

        $urlRow = $this->getUrlFromDB($code);
        if(empty($urlRow)){
            throw new Exception("Short code does not appear to exist.");
        }

        if($increment == true){
            $this->incrementCounter($urlRow["id"]);
        }

        return $urlRow["long_url"];
    }

    protected function validateShortCode($code){
        $rawChars = str_replace('|', '', self::$chars);
        return preg_match("|[".$rawChars."]+|", $code);
    }

    protected function getUrlFromDB($code){
        $query = "SELECT id, long_url FROM ".self::$table." WHERE short_code = :short_code LIMIT 1";
        $stmt = $this->pdo->prepare($query);
        $params=array(
            "short_code" => $code
        );
        $stmt->execute($params);

        $result = $stmt->fetch();
        return (empty($result)) ? false : $result;
    }

    protected function incrementCounter($id){
        $query = "UPDATE ".self::$table." SET hits = hits + 1 WHERE id = :id";
        $stmt = $this->pdo->prepare($query);
        $params = array(
            "id" => $id
        );
        $stmt->execute($params);
    }
}
  • پیکر بندی پایگاه داده (dbConfig.php):

در فایل dbConfig.php از PDO برای انتخاب و انتصال به پایگاه داده استفاده شده است. اطلاعاتی که باید مشخص کنید عبارت هستند از:

  • dbHost: میزبان پایگاه داده
  • dbUsername: نام کاربری پایگاه داده
  • dbPassword: رمز عبور پایگاه داده
  • dbName: نام پایگاه داده
<?php
// Database configuration
$dbHost     = "localhost";
$dbUsername = "root";
$dbPassword = "root";
$dbName     = "codexworld";

// Create database connection
try{
    $db = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUsername, $dbPassword);
}catch(PDOException $e){
    echo "Connection failed: " . $e->getMessage();
}
  • ایجاد پیوند کوتاه با PHP

دستورزیر با استفاده از کلاس Shortener پیوند کوتاه ایجاد خواهد کرد.

// Include database configuration file
require_once 'dbConfig.php';

// Include URL Shortener library file
require_once 'Shortener.class.php';

// Initialize Shortener class and pass PDO object
$shortener = new Shortener($db);

// Long URL
$longURL = 'https://www.maryam-hajireza.ir/tutorials/php/';

// Prefix of the short URL 
$shortURL_Prefix = 'https://xyz.com/'; // with URL rewrite
$shortURL_Prefix = 'https://xyz.com/?c='; // without URL rewrite

try{
    // Get short code of the URL
    $shortCode = $shortener->urlToShortCode($longURL);
    
    // Create short URL
    $shortURL = $shortURL_Prefix.$shortCode;
    
    // Display short URL
    echo 'Short URL: '.$shortURL;
}catch(Exception $e){
    // Display error
    echo $e->getMessage();
}
  • تغییر مسیر به URL طولانی

کد زیر تغییر مسیر از URL کوتاه به آدرس اصلی را مدیریت می کند.

// Include database configuration file
require_once 'dbConfig.php';

// Include URL Shortener library file
require_once 'Shortener.class.php';

// Initialize Shortener class and pass PDO object
$shortener = new Shortener($db);

// Retrieve short code from URL
$shortCode = $_GET["c"];

try{
    // Get URL by short code
    $url = $shortener->shortCodeToUrl($shortCode);
    
    // Redirect to the original URL
    header("Location: ".$url);
    exit;
}catch(Exception $e){
    // Display error
    echo $e->getMessage();
}
  • بازنویسی  URL با HTACCESS بازنویسی 

اگر می خواهید URL را کاربر پسند کنید ، از HTACCESS با RewriteRule استفاده کنید. با mod_rewrite ، می توانید طول URL را کوتاهتر کرده و به اشتراک گذاری آن را آسان کنید.

یک فایل .htaccess ایجاد کرده و کد زیر را اضافه کنید.

<IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteCond %{REQUEST_FILENAME} !-f
   RewriteCond %{REQUEST_FILENAME} !-d
   RewriteRule ^([a-zA-Z0-9]+)/?$ redirect.php?c=$1 [L] 
</IfModule>

نتیجه گیری:

این کلاس Shortener به شما کمک می کند تا با استفاده از PHP به راحتی URL ها خود را کوتاه کنید. می توانید از این کتابخانه برای ایجاد کوتاه کننده لینک استفاده کنید.

نظرات
سعید

سلام و عرض ادب. ضمن تشکر از اشتراک گذاری کدها من کدها رو برسی کردم یه موضوعی رو ندیدم چک کرده باشید و اون این هست که چک نمیشه کد کوتاه جدیدی که ایجاد میشه قبلا ایجاد نشده باشه. البته این احتمال خصوصا در تعداد کم خیلی پایین هست اما برای مصارف بالا (روزانه چندصد هزار کد کوتاه) احتمال ایجاد کد تکراری وجود داره. میخواستم ببینم شما این موضوع رو هم بررسی کردید و من متوجه نشدم یا اینکه این موضوع بررسی نشده. با تشکر از شما