Sunday 13 September 2015

Membangun Pemendek URL Sendiri dengan PHP

Membangun Pemendek URL Sendiri dengan PHP

Sebagian besar dari kita akrab dengan melihat URL seperti bit.ly , sh.st atau t.co pada feed Twitter atau Facebook kami. Ini adalah contoh dari URL singkat, yang merupakan alias atau pointer singkat ke linkhalaman lain yang lebih panjang. Sebagai contoh, saya bisa mengirimkan kamu URL yang diperpendek http://sh.st/xJsU4 yang akan mengarahkan kamu ke URL google yang sangat panjang dengan hasil pencarian bagaimana menyetrika kaus. Akan jauh lebih mudah menggunakan teks20karakter URL bit.ly bagi anak anda yang ada di perguruan tinggi dan mempersiapkan diri untuk wawancara pekerjaan besar pertamanya.

Dalam artikel ini Anda akan belajar cara membuat pemendek URL yang berfungsi penuh untuk website Anda yang akan bekerja apakah Anda menggunakan front controller / framework atau tidak.Jika Anda menggunakan front controller, saya akan membahas cara mudah untuk mengintegrasikan URL shortener ini tanpa harus menggali ke dalam program controller.


Menjawab Beberapa Pertanyaan Umum

Jadi dengan bit.ly dan banyak penyingkat URL lainnya  seperti itu di luar sana dan tersedia secara bebas, mengapa kita harus repot-repot membangun sendiri? Sebagian besar darilayanan memperpendek ini bahkan memiliki API yang mudah digunakan sehingga kita dapatmenghasilkan URL singkat yang telah diprogram, dan menggunakannya dalam skrip PHP kita.
Alasan yang terbaik adalah untuk kenyamanan, estetika dan pengenalan merek. Jika misalnya website Anda memiliki aplikasi yang menciptakan sejumlah besar laporan, sebuah blog yang sangat aktif ataualbum foto besar, akan ada banyak link. Sebuah URL shortener akan memungkinkan Anda untukmembuat pemrograman yang bersih, link sederhana yang bisa diemail ke pembaca ataudipublikasikan di website Anda. Keuntungan yang jelas untuk memilikinya sendiri adalah bahwapembaca Anda memiliki pengenalan merek instan dengan situs web Anda.

Anda mungkin bertanya-tanya mengapa Anda selalu melihat huruf dicampur dengan angka di URLyang dipersingkat. Dengan memiliki lebih dari sepuluh pilihan (0-9) per digit, kita dapat memilikikombinasi yang lebih dramatis sambil menjaga kodenya sesingkat mungkin.



Karakter kita akan menggunakan adalah angka 1-9 bersama dengan berbagai huruf besar / huruf kecil.Saya telah menghapus semua vokal untuk mencegah memiliki link yang dibuat menggunakan kata-kata buruk yang tidak diinginkan, dan saya telah menghapus karakter yang bisa membingungkan satu sama lain. Ini memberi kita daftar sekitar 50 karakter yang tersedia untuk setiap digit, yang berarti bahwa dengan dua karakter, kami memiliki 2.500 kemungkinan kombinasi, 125.000 kemungkinan dengan tiga karakter, dan 6,5 juta kombinasi dengan hanya empat karakter !

Mempersiapkan Database

Mari membuat tabel short_urls. Ini adalah tabel yang sederhana dan pernyataan untuk membuatnya adalah seperti dibawah ini :




CREATE TABLE IF NOT EXISTS short_urls (
  id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  long_url VARCHAR(255) NOT NULL,
  short_code VARBINARY(6) NOT NULL,
  date_created INTEGER UNSIGNED NOT NULL,
  counter INTEGER UNSIGNED NOT NULL DEFAULT '0',
  PRIMARY KEY (id),
  KEY short_code (short_code)
)
ENGINE=InnoDB;



Kita memiliki autoincrementing primary key standar dan kolom untuk URL lengkap, kode singkat untuk URL (diindeks untuk pencarian lebih cepat), penanda waktu ketika baris diciptakan, dan jumlahberapa kali URL pendek telah diakses.

Perhatikan bahwa field long_url memiliki panjang maksimum 255 karakter, yang harus cukup untuk sebagian besar aplikasi. Jika Anda perlu untuk menyimpan URL yang lebih panjang maka Anda harus mengubah definisi menjadi TEXT.



Sekarang dengan PHP!

Membuat Kode Pemendek URL

Kode untuk membuat dan mengurai URL pendek akan berada dalam kelas bernama ShortUrl. Pertama, mari kita lihat kode yang bertanggung jawab untuk menciptakan kode yang diperpendek :





<!--?php
class ShortUrl
{
    protected static $chars = "123456789bcdfghjkmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ";
    protected static $table = "short_urls";
    protected static $checkUrlExists = true;
    protected $pdo;
    protected $timestamp;
    public function __construct(PDO $pdo) {
        $this->pdo = $pdo;
        $this->timestamp = $_SERVER["REQUEST_TIME"];
    }
    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) {
        $id = $this->insertUrlInDb($url);
        $shortCode = $this->convertIntToShortCode($id);
        $this->insertShortCodeInDb($id, $shortCode);
        return $shortCode;
    }
    protected function insertUrlInDb($url) {
        $query = "INSERT INTO " . self::$table .
            " (long_url, date_created) " .
            " VALUES (:long_url, :timestamp)";
        $stmnt = $this->pdo->prepare($query);
        $params = array(
            "long_url" => $url,
            "timestamp" => $this->timestamp
        );
        $stmnt->execute($params);
        return $this->pdo->lastInsertId();
    }
    protected function convertIntToShortCode($id) {
        $id = intval($id);
        if ($id < 1) {
            throw new Exception(
                "The ID is not a valid integer");
        }
        $length = strlen(self::$chars);
        // make sure length of available characters is at
        // least a reasonable minimum - there should be at
        // least 10 characters
        if ($length < 10) {
            throw new Exception("Length of chars is too small");
        }
        $code = "";
        while ($id > $length - 1) {
            // determine the value of the next higher character
            // in the short code should be and prepend
            $code = self::$chars[fmod($id, $length)] .
                $code;
            // reset $id to remaining value to be converted
            $id = floor($id / $length);
        }
        // remaining value of $id is less than the length of
        // self::$chars
        $code = self::$chars[$id] . $code;
        return $code;
    }
    protected function insertShortCodeInDb($id, $code) {
        if ($id == null || $code == null) {
            throw new Exception("Input parameter(s) invalid.");
        }
        $query = "UPDATE " . self::$table .
            " SET short_code = :short_code WHERE id = :id";
        $stmnt = $this->pdo->prepare($query);
        $params = array(
            "short_code" => $code,
            "id" => $id
        );
        $stmnt->execute($params);
        if ($stmnt->rowCount() < 1) {
            throw new Exception(
                "Row was not updated with short code.");
        }
        return true;
    }
...

Ketika kita menginstansiasi class ShortUrl, kita akan melewatkan objek PDO kita. Konstruktor menyimpan referensi ini dan menetapkan nilai $timestamp.

Kita memanggil metode urlToShortCode () melewatkan URL panjang yang kita ingin dipersingkat.Metode ini membungkus segala sesuatu yang diperlukan untuk membuat kode URL pendek, yangakan ditambahkan ke nama domain kita.
urlToShortCode() memanggil validateUrlFormat() yang hanya menggunakan filter PHPuntuk memastikan bahwa URL diformat dengan benar. Lalu, apakah variabel statis$checkUrlExists bernilai benar, verifyUrlExists() akan dipanggil menggunakan cURLuntuk menghubungi URL dan memastikan bahwa hal itu tidak mengembalikan error 404 (Not Found).Sebagai alternatif anda dapat memeriksa status 200 (OK), tapi ini bisa menyebabkan masalah jika halaman tiba-tiba mengembalikan kode respon 301 (Dipindah) atau 401 (sah).
Adalah tidak masuk akal untuk memiliki entri ganda, sehingga kode memeriksanya denganurlExistsInDb() yang meng-query database untuk URL yang panjang. Jika menemukan URL itu, ia akan mengembalikan kode pendek yang sesuai, jika tidak maka mengembalikan false jadi kita tahu bahwa kita perlu untuk menciptakannya. Perhatikan bahwa http://www.example.com danhttp://example.com adalah URL yang berbeda, jadi jika Anda ingin mencegah duplikasi semacam inimaka Anda harus menambahkan beberapa kalimat biasa.

createShortCode() menujuk tugas-tugas dibawah ini kepada method khusus:
1. insertUrlInDb() untuk memasukkan URL yang panjang ke dalam database danmengembalikan ID baris yang baru.
2.    convertIntToShortCode() untuk mengubah ID baris baru ke skema nomor basis50 kita.
3.    insertShortCodeInDb()untuk memperbarui baris dengan kode pendek yang baru dibuat.


Ketika kita ingin membuat URL pendek, yang harus kita lakukan adalah menginstansiasi kelas,melewati PDO ke konstruktor, memanggil method urlToShortCode() tersebut dengan URL panjang yang ingin kita persingkat, dan menambahkan kode pendek kembali ke domain danmenyebarkannya kembali ke controller yang memintanya.






<!--?php
include "../include/config.php";
include "../include/ShortUrl.php";
try {
    $pdo = new PDO(DB_PDODRIVER . ":host=" . DB_HOST .
        ";dbname=" . DB_DATABASE,
        DB_USERNAME, DB_PASSWORD);
}
catch (PDOException $e) {
    trigger_error("Error: Failed to establish connection to database.");
    exit;
}
$shortUrl = new ShortUrl($pdo);
try {
    $code = $shortUrl->urlToShortCode($_POST["url"]);
    printf('Short URL: %1$s
',
        SHORTURL_PREFIX . $code);
    exit;
}
catch (Exception $e) {
    // log exception and then redirect to error page.
    header("Location: /error");
    exit;
}

Menguraikan Kode Pendek

Kode untuk memecahkan kode pendek dan mendapatkan URL panjang adalah bagian dari kelas ShortUrl juga. Kami menyebutnya metode shortCodeToUrl() dan melewatkan kodesingkat kami yang telah diekstrak dari URIshortCodeToUrl()juga menerima parameter opsional,$increment, yang defaultnya adalah TRUE. Kemudian menugaskan berikut:
1.    validateShortCodeFormat() memastikan bahwa kode singkat yang disediakan hanya berisi huruf dan angka.
2.    getUrlFromDb() query ke database dengan kode pendek yang diberikan dan mengembalikan id, long_url, dan counter.
3.    Jika parameter $increment bernilai true, incrementCounter() dipanggil untuk menambahkan nilai kolom counter.


Ini adalah sisa kode untuk class tersebut :





...
    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) {
        return preg_match("|[" . self::$chars . "]+|", $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 counter = counter + 1 WHERE id = :id";
        $stmt = $this->pdo->prepare($query);
        $params = array(
            "id" => $id
        );
        $stmt->execute($params);
    }
}

Membawa Semuanya

Membangun/mengubah front controller atau menyesuaikan paket ini ke framework yang ada di luarlingkup artikel ini, dan jadi aku memilih untuk memasukkan logika decoding kami dalam sebuah file bernama r.php (r singkatan untuk redirect). Kita bisa menulis URL disingkat kita sebagai http://example.com/r/X4c mana r.php (atau r / index.php tergantung pada desain Anda) akan menjadicontroller. Format ini akan mudah untuk mengintegrasikannya ke dalam hampir kerangka apapuntanpa menyentuh front controller yang ada.
Pada catatan terkait, jika Anda ingin belajar bagaimana membangun front controller Anda sendiri, periksa seri yang sangat baik An Introduction to the Front Controller Pattern.
Salah satu keuntungan dari desain ini adalah bahwa, jika Anda ingin, Anda dapat memiliki kontrolerterpisah untuk bagian yang berbeda dari situs Anda menggunakan tabel yang berbeda untuk menjagakode pendek terorganisir dan sesingkat mungkin. http://example.com/b/ bisa untuk posting blog, dan http://example.com/i/ bisa untuk gambar.
Tapi bagaimana kalau saya tidak menggunakan front controller atau framework?” Anda bertanya,Apakah aku hanya membaca artikel ini secara keseluruhan untuk hal yang sia-sia?” Meskipun itu tidak cukup, Anda dapat menggunakan format http://example.com/ r? c = X4c mana r / index.php berisi script decoding.


Ini adalah isi dari file r.php :




<?php
include "../include/config.php";
include "../include/ShortUrl.php";
// How are you getting your short code?
// from framework or front controller using a URL format like
// http://.example.com/r/X4c
// $code = $uri_data[1];
// from the query string using a URL format like
// http://example.com/r?c=X4c where this file is index.php in the
// directory http_root/r/index.php
$code = $_GET["c"];
try {
    $pdo = new PDO(DB_PDODRIVER . ":host=" . DB_HOST .
        ";dbname=" . DB_DATABASE,
        DB_USERNAME, DB_PASSWORD);
}
catch (PDOException $e) {
    trigger_error("Error: Failed to establish connection to database.");
    exit;
}
$shortUrl = new ShortUrl($pdo);
try {
    $url = $shortUrl->shortCodeToUrl($code);
    header("Location: " . $url);
    exit;
}
catch (Exception $e) {
    // log exception and then redirect to error page.
    header("Location: /error");
    exit;
}





  • Tambahkan cara untuk mengcache permintaan URL singkat.
  •  Abstrak interaksi database Anda untuk menghapus kode berlebihan.
  • Tambahkan beberapa analisis ke URL pendek yang diminta di luar field counter.
  • Tambahkan cara untuk menyaring halaman berbahaya.
Aku ingin mengambil kesempatan ini untuk mengucapkan terima kasih Timothy Boronczyk atassarannya selama proses penulisan saya. Itu adalah suatu kehormatan untuk menulis artikel ini untukSitePoint dan bekerja sama dengannya.
Silahkan fork  contoh kode artikel ini di GitHub dan bagikan kontribusi dan peningkatan kamu.
Terima kasih telah membaca dan selamat ber-PHP ria!


Artikel Terkait

Membangun Pemendek URL Sendiri dengan PHP
4/ 5
Oleh

Berlangganan

Suka dengan artikel di atas? Silakan berlangganan gratis via email

Coretan Disqus

close
close