<?php

/**
 * main shortURl class
 */
define("SHORT_URL_PREFIX", "");  /* prefix on all the shorturl parts */

class shortUrl
{

    public $shortUrlUID  = null;
    public $shortUrlPart = "";
    public $fullUrl      = "";

    function __construct($fullUrl = null)
    {
        if ($fullUrl)
        {
            $this->fullUrl = $this->standardiseUrl($fullUrl);
        }
    }

    function compileShortUrl()
    {
        return WEB_ROOT . "/" . SHORT_URL_PREFIX . $this->shortUrlPart;
    }

    function expire()
    {
        $db = Database::getDatabase(true);
        $this->visits++;
        $db->query('UPDATE shorturl SET status = :status WHERE id = :id', array('status' => 'expired', 'id'     => $this->shortUrlUID));
    }

    static function standardiseUrl($url)
    {
        if (!strstr(strtolower($url), "://"))
        {
            $url = "http://" . $url;
        }
        return $url;
    }

    function getFormattedLongUrl($length = 36)
    {
        $x = substr($this->fullUrl, 7, $length);
        if (strlen($this->fullUrl) > $length + 7)
            $x .= ' ...';
        return $x;
    }

    function createShortUrl($shortUrlOverride = null)
    {
        if (!$this->fullUrl)
        {
            return false;
        }
        $db = Database::getDatabase(true);

        /* check for spamming */
        if (SITE_CONFIG_MAX_URLS_PER_DAY > 0)
        {
            $urlTodayTotal = $db->getValue('SELECT COUNT(id) AS total FROM shorturl WHERE createdIP = \'' . getUsersIPAddress() . '\' AND MID(dateCreated, 1, 10) = \'' . date("Y-m-d") . '\'');
            if ($urlTodayTotal > SITE_CONFIG_MAX_URLS_PER_DAY)
            {
                setError("You have reached the maximum urls permitted for today, please try again tomorrow.");
                return false;
            }
        }

        if ((int) SITE_CONFIG_DELAY_BETWEEN_SUBMISSIONS > 0)
        {
            $urlTodayTotal = $db->getValue('SELECT COUNT(id) AS total FROM shorturl WHERE createdIP = \'' . getUsersIPAddress() . '\' AND dateCreated > \'' . date("Y-m-d H:i:s", strtotime("- " . (int) SITE_CONFIG_DELAY_BETWEEN_SUBMISSIONS . " seconds")) . '\'');
            if ((int) $urlTodayTotal > 0)
            {
                setError("There is a restriction of " . (int) SITE_CONFIG_DELAY_BETWEEN_SUBMISSIONS . " seconds between submissions.");
                return false;
            }
        }

        /* check for banned words */
        $bannedWords = $db->getRows('SELECT bannedTerm FROM banned_words');
        if (COUNT($bannedWords))
        {
            foreach ($bannedWords AS $bannedWord)
            {
                // check url
                if (strpos($this->fullUrl, $bannedWord['bannedTerm']) !== false)
                {
                    setError("The url submitted contains a banned term/domain name.");
                    return false;
                }

                // check short url part
                if ($shortUrlOverride != null)
                {
                    if (strpos($shortUrlOverride, $bannedWord['bannedTerm']) !== false)
                    {
                        setError("The custom short url contains a banned term.");
                        return false;
                    }
                }
            }
        }

        /* create the intial record */
        $dbInsert = new DBObject("shorturl", array("shortUrl", "originalUrl", "dateCreated", "createdIP", "visits", "isPrivate", "password", "expiryDate", "totalUses", "userId"));
        $dbInsert->originalUrl = $this->fullUrl;
        $dbInsert->dateCreated = sqlDateTime();
        $dbInsert->createdIP = getUsersIPAddress();
        $dbInsert->visits = 0;
        $dbInsert->isPrivate = (int) $this->isPrivate;
        $dbInsert->password = $this->password;
        $dbInsert->expiryDate = $this->expiryDate;
        $dbInsert->totalUses = (int) $this->totalUses;
        $dbInsert->status = $this->status ? $this->status : "active";
        $dbInsert->userId = $this->userId;
        if (!$this->shortUrlUID = $dbInsert->insert())
        {
            return false;
        }

        /* create the shorturl */
        if (!$shortUrlOverride)
        {
            $tracker     = 1;
            $shortUrlObj = $this->createShortUrlPart($tracker . $this->shortUrlUID);
            while ($shortUrlObj)
            {
                $shortUrlPart = $this->createShortUrlPart($tracker . $this->shortUrlUID);
                $shortUrlObj  = shortUrl::loadByUrl($shortUrlPart);
                $tracker++;
            }
            $this->shortUrlPart = $shortUrlPart;
        }
        else
        {
            $this->shortUrlPart = $shortUrlOverride;
        }
        $dbInsert->shortUrl = $this->shortUrlPart;
        $dbInsert->save();
        return shortUrl::loadById($this->shortUrlUID);
    }

    /* method to increment visitors */

    public function updateVisitors()
    {
        $db = Database::getDatabase(true);
        $this->visits++;
        $db->query('UPDATE shorturl SET visits = :visits WHERE id = :id', array('visits' => $this->visits, 'id'     => $this->shortUrlUID));
    }

    /* method to update last accessed */

    public function updateLastAccessed()
    {
        $db = Database::getDatabase(true);
        $db->query('UPDATE shorturl SET lastAccessed = NOW() WHERE id = :id', array('id' => $this->shortUrlUID));
    }

    /* loader method */

    static function loadByUrl($shortUrl)
    {
        $db  = Database::getDatabase(true);
        $row = $db->getRow('SELECT * FROM shorturl WHERE shortUrl = ' . $db->quote($shortUrl));
        if (!is_array($row))
        {
            return false;
        }

        $shortUrlObj = new shortUrl();
        $shortUrlObj->id = $row['id'];
        $shortUrlObj->shortUrlUID = $row['id'];
        $shortUrlObj->shortUrlPart = $shortUrl;
        $shortUrlObj->fullUrl = $row['originalUrl'];
        $shortUrlObj->dateCreated = $row['dateCreated'];
        $shortUrlObj->createdIP = $row['createdIP'];
        $shortUrlObj->visits = $row['visits'];
        $shortUrlObj->isPrivate = $row['isPrivate'];
        $shortUrlObj->password = $row['password'];
        $shortUrlObj->expiryDate = $row['expiryDate'];
        $shortUrlObj->totalUses = $row['totalUses'];
        $shortUrlObj->status = $row['status'];
        $shortUrlObj->userId = $row['userId'];
        return $shortUrlObj;
    }

    static function loadAllByAccount($accountId)
    {
        $db = Database::getDatabase(true);
        $rs = $db->getRows('SELECT * FROM shorturl WHERE userId = ' . $db->quote($accountId) . ' ORDER BY shortUrl');
        if (!is_array($rs))
        {
            return false;
        }

        return $rs;
    }

    static function loadAllRecentByAccount($accountId)
    {
        $db = Database::getDatabase(true);
        $rs = $db->getRows('SELECT * FROM shorturl WHERE userId = ' . $db->quote($accountId) . ' ORDER BY dateCreated DESC LIMIT 10');
        if (!is_array($rs))
        {
            return false;
        }

        return $rs;
    }

    static function loadAllRecentByIp($ip)
    {
        $db = Database::getDatabase(true);
        $rs = $db->getRows('SELECT * FROM shorturl WHERE createdIP = ' . $db->quote($ip) . ' ORDER BY dateCreated DESC LIMIT 10');
        if (!is_array($rs))
        {
            return false;
        }

        return $rs;
    }

    static function loadByOriginalUrl($originalUrl)
    {
        $db  = Database::getDatabase(true);
        $row = $db->getRow('SELECT * FROM shorturl WHERE originalUrl = ' . $db->quote($originalUrl));
        if (!is_array($row))
        {
            return false;
        }

        $shortUrlObj = new shortUrl();
        $shortUrlObj->id = $row['id'];
        $shortUrlObj->shortUrlUID = $row['id'];
        $shortUrlObj->shortUrlPart = $row['shortUrl'];
        $shortUrlObj->fullUrl = $row['originalUrl'];
        $shortUrlObj->dateCreated = $row['dateCreated'];
        $shortUrlObj->createdIP = $row['createdIP'];
        $shortUrlObj->visits = $row['visits'];
        $shortUrlObj->isPrivate = $row['isPrivate'];
        $shortUrlObj->password = $row['password'];
        $shortUrlObj->expiryDate = $row['expiryDate'];
        $shortUrlObj->totalUses = $row['totalUses'];
        $shortUrlObj->status = $row['status'];
        $shortUrlObj->userId = $row['userId'];

        return $shortUrlObj;
    }

    static function loadById($recordId)
    {
        $db  = Database::getDatabase(true);
        $row = $db->getRow('SELECT * FROM shorturl WHERE id = ' . $db->quote($recordId));
        if (!is_array($row))
        {
            return false;
        }

        $shortUrlObj = new shortUrl();
        $shortUrlObj->id = $row['id'];
        $shortUrlObj->shortUrlUID = $row['id'];
        $shortUrlObj->shortUrlPart = $row['shortUrl'];
        $shortUrlObj->fullUrl = $row['originalUrl'];
        $shortUrlObj->dateCreated = $row['dateCreated'];
        $shortUrlObj->createdIP = $row['createdIP'];
        $shortUrlObj->visits = $row['visits'];
        $shortUrlObj->isPrivate = $row['isPrivate'];
        $shortUrlObj->password = $row['password'];
        $shortUrlObj->expiryDate = $row['expiryDate'];
        $shortUrlObj->totalUses = $row['totalUses'];
        $shortUrlObj->status = $row['status'];
        $shortUrlObj->userId = $row['userId'];

        return $shortUrlObj;
    }

    /* strip unwanted characters from custom short url */

    static function prepareShortUrlPart($str)
    {
        $str = trim($str);
        $str = strtolower($str);
        $str = str_replace(" ", "_", $str);
        return ereg_replace("[^a-z0-9_-]", "", $str);
    }

    /* returns shorturl part - no bcmath reliance */

    static function createShortUrlPart($in)
    {
        $codeset  = "0123456789abcdefghjkmnpqrstuvwxyz";
        $cbLength = strlen($codeset);
        while ((int) $in > $cbLength - 1)
        {
            $out = $codeset[fmod($in, $cbLength)] . $out;
            $in  = floor($in / $cbLength);
        }
        return $codeset[$in] . $out;
    }

    /* returns shorturl part - depreciated */

    static function DEP_createShortUrlPart($in, $to_num = false, $pad_up = false, $passKey = null)
    {
        $index = "abcdefghijklmnopqrstuvwxyz0123456789";
        if ($passKey !== null)
        {
            // Although this function's purpose is to just make the
            // ID short - and not so much secure,
            // with this patch by Simon Franz (http://blog.snaky.org/)
            // you can optionally supply a password to make it harder
            // to calculate the corresponding numeric ID

            for ($n = 0; $n < strlen($index); $n++)
            {
                $i[] = substr($index, $n, 1);
            }

            $passhash = hash('sha256', $passKey);
            $passhash = (strlen($passhash) < strlen($index)) ? hash('sha512', $passKey) : $passhash;

            for ($n = 0; $n < strlen($index); $n++)
            {
                $p[] = substr($passhash, $n, 1);
            }

            array_multisort($p, SORT_DESC, $i);
            $index = implode($i);
        }

        $base = strlen($index);

        if ($to_num)
        {
            // Digital number  <<--  alphabet letter code
            $in  = strrev($in);
            $out = 0;
            $len = strlen($in) - 1;
            for ($t   = 0; $t <= $len; $t++)
            {
                $bcpow = bcpow($base, $len - $t);
                $out   = $out + strpos($index, substr($in, $t, 1)) * $bcpow;
            }

            if (is_numeric($pad_up))
            {
                $pad_up--;
                if ($pad_up > 0)
                {
                    $out -= pow($base, $pad_up);
                }
            }
        }
        else
        {
            // Digital number  -->>  alphabet letter code
            if (is_numeric($pad_up))
            {
                $pad_up--;
                if ($pad_up > 0)
                {
                    $in += pow($base, $pad_up);
                }
            }

            $out = "";
            for ($t   = floor(log10($in) / log10($base)); $t >= 0; $t--)
            {
                $a   = floor($in / bcpow($base, $t));
                $out = $out . substr($index, $a, 1);
                $in  = $in - ($a * bcpow($base, $t));
            }
            $out = strrev($out); // reverse
        }

        return $out;
    }

    static function formatLongUrlForScreen($url)
    {
        if (strlen($url) > 50)
        {
            $endPart   = substr($url, strlen($url) - 5, 5);
            $startPart = substr($url, 0, 40);
            $url       = $startPart . '&nbsp;...' . $endPart;
        }

        return $url;
    }

    static function getFavIconUrl($url)
    {
        $expUrl  = explode("/", $url);
        $baseUrl = "http://" . $expUrl[2];

        return $baseUrl . "/favicon.ico";
    }

}

?>