Link to home
Start Free TrialLog in
Avatar of Pedro Chagas
Pedro ChagasFlag for Portugal

asked on

URL's dynamic

Hi E's, I'm working on a quiz system (entertainment), and I want to create a system of dynamic URLs and to show the new address each time a certain page is requested.
Example:
In the page mydomain.com/quiz_result.php is where I want to show the result of the quiz, but I want to URL address something appears: mydomain.com/45gde244de5 (mydomain.com/???????????).
The part of "?????????" I can create whit MD5 function, and every new key can be saved in database, and I can check if that URL it has been used or not, and it was previously used back to generate a new key.
How I resolve this problem?

The best regards, JC
Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

You can make an md5() string from a combination of the following data, and it will always be unique.

1. The client IP address from $_SERVER["REMOTE_ADDR"]
2. The current timestamp from time()
3. The client's username or similar - whatever you use to identify an individual user of your system.

You can mark the database column UNIQUE and MySQL will throw error number 1062 if your script tries to insert a duplicate value.  You can test for this and regenerate the md5() string if it happens.
FWIW, PHP also has a function to get a random value: uniqid().  I have not used it much, and the docs seem to suggest it's not a very good tool if there are any security implications around the application.

This is a "thought experiment" I did on a similar topic.  On my server it runs about 10 seconds to give back 100,000 random unique keys.
<?php // demo/random_unique_string.php
/**
 * Generate a short unique random string for use as some kind of key.
 *
 * We deliberately omit look-alike letters like o and 0, I and 1.
 * If lower case letters are included, it's wise to omit lower-case l.
 *
 * In some fonts we might want to omit s,5 and z,2.
 *
 * Note that the data base must have the rand_key field defined as "unique"
 * Note that the length argument must match throughout so we define() it.
 */
error_reporting(E_ALL);
echo "<pre>";


define('ARG_LENGTH', 7);


Class Randu
{
    public $keys, $errs, $cnt;
    protected $mytable  = 'myKeys';
    protected $mycolumn = 'rand_key';

    public function __construct()
    {
        $this->keys = array();
        $this->errs = array();
        $this->cnt  = -1;

        // DATABASE CONNECTION AND SELECTION VARIABLES - GET THESE FROM YOUR HOSTING COMPANY
        $db_host = "localhost"; // PROBABLY THIS IS OK
        $db_name = "??";
        $db_user = "??";
        $db_word = "??";
        require_once('RAY_live_data.php');
        // OPEN A CONNECTION TO THE DATA BASE SERVER AND SELECT THE DB
        $this->mysqli = new mysqli($db_host, $db_user, $db_word, $db_name);

        // DID THE CONNECT/SELECT WORK OR FAIL?
        if ($this->mysqli->connect_errno)
        {
            $err
            = "CONNECT FAIL: "
            . $this->mysqli->connect_errno
            . ' '
            . $this->mysqli->connect_error
            ;
            trigger_error($err, E_USER_ERROR);
        }


        // IN REAL LIFE, THIS WOULD BE A PERMANENT TABLE
        $len = ARG_LENGTH;
        $sql
        =
        "
        CREATE TEMPORARY TABLE $this->mytable
        ( id                 INT                   NOT NULL AUTO_INCREMENT PRIMARY KEY
        , $this->mycolumn    VARCHAR($len)  UNIQUE NOT NULL DEFAULT '?'
        )
        ENGINE=MyISAM DEFAULT CHARSET=ascii
        "
        ;
        // IF mysqli::query() RETURNS FALSE, LOG AND SHOW THE ERROR
        if (!$res = $this->mysqli->query($sql))
        {
            $err
            = 'QUERY FAILURE:'
            . ' ERRNO: '
            . $this->mysqli->errno
            . ' ERROR: '
            . $this->mysqli->error
            . ' QUERY: '
            . $sql
            ;
            trigger_error($err, E_USER_ERROR);
        }
    }

    // FUNCTION TO MAKE A RANDOM STRING
    public function random_string($length)
    {
        // POSSIBLE COMBINATIONS > HUNDREDS OF MILLIONS IF LENGTH > 6
        //           1...5...10...15...20...25...30.
        $alphabet = "ABCDEFGHJKMNPQRSTUVWXYZ23456789";
        $strlen   = strlen($alphabet);
        $string   = NULL;
        while(strlen($string) < $length)
        {
            $random = mt_rand(0,$strlen);
            $string .= substr($alphabet, $random, 1);
        }
        return($string);
    }

    // FUNCTION TO ENSURE THE RANDOM STRING IS UNIQUE
    public function make_random_key()
    {
        $key = NULL;
        $this->cnt++;

        // GENERATE A UNIQUE AND RANDOM TOKEN
        while ($key == NULL)
        {
            $key = $this->random_string(ARG_LENGTH);
            $sql = "INSERT INTO $this->mytable ( $this->mycolumn ) VALUES ( '$key' )";
            $res = $this->mysqli->query($sql);

            // IF THERE IS A QUERY ERROR
            if (!$res)
            {
                // THE EXPECTED QUERY ERROR WOULD BE A DUPLICATE VALUE, NULLIFY THE KEY AND START OVER
                if ($this->mysqli->errno == 1062)
                {
                    // trigger_error("1062 Duplicate Key Event: $key at " . number_format($this->cnt), E_USER_NOTICE);
                    echo PHP_EOL   . "1062 Duplicate Key Event: $key at " . number_format($this->cnt);
                    $this->errs[$this->cnt] = $key;
                    $key = NULL;
                }
                // OTHER UNEXPECTED QUERY ERROR
                else
                {
                    $err
                    = 'QUERY FAILURE:'
                    . ' ERRNO: '
                    . $this->mysqli->errno
                    . ' ERROR: '
                    . $this->mysqli->error
                    . ' QUERY: '
                    . $sql
                    ;
                    trigger_error($err, E_USER_ERROR);
                }
            }
        }
        $this->keys[$this->cnt] = $key;
        return $key;
    }

}


// MAKE LOTS OF UNIQUE AND RANDOM STRINGS
$num = 0;
$max = 100000;
$ran = new Randu;
$aaa = time();
while ($num < $max)
{
    $thing = $ran->make_random_key();
    $num++;
}

// SHOW THE WORK PRODUCT
$zzz = time();
$lap = $zzz - $aaa;
echo PHP_EOL . "CREATED $max UNIQUE KEYS IN $lap SECONDS" . PHP_EOL;
echo PHP_EOL . number_format(count($ran->errs)) . " DUPLICATE KEYS";
echo PHP_EOL;
print_r($ran->errs);
echo PHP_EOL ;
// print_r($ran->keys);

Open in new window

Avatar of Pedro Chagas

ASKER

Hi Ray,
Two good ideas for generate unique keys, also I can insert a new element, the facebook id of the user.
But how I implement that in the system?
You can check my project here http://quiz.wwdablio.com/.
I guess I have to do some changes in htaccess file?

~JC
ASKER CERTIFIED SOLUTION
Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial