I\'m looking for a method that encodes an string to shortest possible length and lets it be decodable (pure PHP, no SQL). I have working sc
EDIT
Reading from the above and below comments, you need a solution to hide the real path of your image parser, giving it a fixed image width.
http://www.example.com/tn/full/animals/images/lion.jpg
You can achieve a basic "thumbnailer" by taking profit of .htaccess
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule tn/(full|small)/(.*) index.php?size=$1&img=$2 [QSA,L]
Your PHP file:
$basedir="/public/content/";
$filename=realpath($basedir.$_GET["img"]);
## check that file is in $basedir
if ((!strncmp($filename, $basedir, strlen($basedir))
||(!file_exists($filename)) die("Bad file path");
switch ($_GET["size"]) {
case "full":
$width=700;
$height=500;
## you can also use getimagesize() to test if the image is landscape or portrait
break;
default:
$width=350;
$height=250;
break;
}
## here is your old code for resizing images
## Note that the "tn" directory can exist and store the actual reduced images
This lets you using the url www.example.com/tn/full/animals/images/lion.jpg
to view your reduced in size image.
This has the advantage for SEO to preserve the original file name.
http://www.example.com/tn/full/lion.jpg
If you want a shorter url, if the number of images you have is not too much, you can use the basename of the file (eg. "lion.jpg") and recursively search. When collision use an index to identify which one you want (eg. "1--lion.jpg")
function matching_files($filename, $base) {
$directory_iterator = new RecursiveDirectoryIterator($base);
$iterator = new RecursiveIteratorIterator($directory_iterator);
$regex_iterator = new RegexIterator($iterator, "#$filename\$#");
$regex_iterator->setFlags(RegexIterator::USE_KEY);
return array_map(create_function('$a', 'return $a->getpathName();'), iterator_to_array($regex_iterator, false));
}
function encode_name($filename) {
$files=matching_files(basename($filename), realpath('public/content'));
$tot=count($files);
if (!$tot) return NULL;
if ($tot==1) return $filename;
return "/tn/full/".array_search(realpath($filename), $files)."--".basename($filename);
}
function decode_name($filename) {
$i=0;
if (preg_match("#^([0-9]+)--(.*)#", $filename, $out)) {
$i=$out[1];
$filename=$out[2];
}
$files=matching_files($filename, realpath('public/content'));
return $files ? $files[$i] : NULL;
}
echo $name=encode_name("gallery/animals/images/lion.jpg").PHP_EOL;
## --> returns lion.jpg
## You can use with the above solution the url http://www.example.com/tn/lion.jpg
echo decode_name(basename($name)).PHP_EOL;
## -> returns the full path opn disk to the image "lion.jpg"
Original post:
Basically, if you add some formatting in your example your shorten url is in fact longer:
img=/dir/dir/hi-res-img.jpg&w=700&h=500 // 39 chars
y8xNt9VPySwC44xM3aLUYt3M3HS9rIJ0tXJbcwMDtQxbUwMDAA // 50 chars
Using base64_encode
will always result in longer strings. And gzcompress
will require at less to store one occurence of the different chars; this is not a good solution for small strings.
So doing nothing (or a simple str_rot13
) is clearly the first option to consider if you want to shorten the result you had previously.
You can also use a simple character replacement method of your choice:
$raw_query_string = 'img=/dir/dir/hi-res-img.jpg&w=700&h=500';
$from="0123456789abcdefghijklmnopqrstuvwxyz&=/ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// the following line if the result of str_shuffle($from)
$to="0IQFwAKU1JT8BM5npNEdi/DvZmXuflPVYChyrL4R7xc&SoG3Hq6ks=e9jW2abtOzg";
echo strtr($raw_query_string, $from, $to)."\n";
// Result: EDpL4MEu4MEu4NE-u5f-EDp.dmprYLU00rNLA00 // 39 chars
Reading from your comment, what you really want is "to prevent anyone to gets a hi-res image".
The best way to achieve that is to generate a checksum with a private key.
Encode:
$secret="ujoo4Dae";
$raw_query_string = 'img=/dir/dir/hi-res-img.jpg&w=700&h=500';
$encoded_query_string = $raw_query_string."&k=".hash("crc32", $raw_query_string.$secret);
Result: img=/dir/dir/hi-res-img.jpg&w=700&h=500&k=2ae31804
Decode:
if (preg_match("#(.*)&k=([^=]*)$#", $encoded_query_string, $out)
&& (hash("crc32", $out[1].$secret) == $out[2])) {
$decoded_query_string=$out[1];
}
This does not hide the original path but this path has no reason to be public, your "index.php" can output your image from the local directory once the key has been checked.
If you really want to shorten your original URL, you have to consider the acceptable characters in the original url to be restricted. Many compression methods are based on the fact that you can use a full byte to store more than a character.