123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- <?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); //Aborted
- /* --------------------------New Algorithm Start----------------------------- */
- $shortCode = $this->createCode($id, $url); //Accepted
- $number = rand(0, 3);
- $shortCode = $shortCode[$number];
- /* --------------------------New Algorithm End----------------------------- */
-
- $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();
- }
-
- /**
- * @param unknown $id
- * @throws Exception
- * @return string
- * Aborted
- */
- 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;
- }
-
- /**
- * @param unknown $id
- * @param unknown $url
- * @return multitype:string
- * Accepted
- */
- protected function createCode($id, $url){
- $base32 = array (
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
- 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
- 'y', 'z', '0', '1', '2', '3', '4', '5'
- );
-
- $hex = md5($url);
- $hexLen = strlen($hex);
- $subHexLen = $hexLen / 8;
- $output = array();
-
- for ($i = 0; $i < $subHexLen; $i++) {
- $subHex = substr ($hex, $i * 8, 8);
- $int = 0x3FFFFFFF & (1 * ('0x'.$subHex));
- $out = '';
-
- for ($j = 0; $j < 6; $j++) {
- $val = 0x0000001F & $int;
- $out .= $base32[$val];
- $int = $int >> 5;
- }
-
- $output[] = $out;
- }
-
- return $output;
- }
-
- 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, 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;
- }
-
- 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);
- }
- }
|