PHP invalid hash tiger192 3 - php

I am using a php code with php 5.4 and i am trying to hash a string with tiger192,3. I am not getting a correct hash after all..
$keyLength = 24;
$keyCharacters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$string = '';
$key = '';
$keyHash = '';
$first8Hash = '';
$uniqueKey = false;
while ($uniqueKey == false)
{
for ($p = 0; $p < $keyLength; $p++)
{
$string .= $keyCharacters[mt_rand(0, strlen($keyCharacters)-1)];
}
$key = $string;
$keyHash = hash('tiger192,3', $key);
$first8Hash = substr($keyHash, 0, 16);
$sql = "SELECT * FROM `penkeys` WHERE first8 = '" . $first8Hash . "'";
$result = $db->sql_query($sql);
while ($keyrow = $db->sql_fetchrow($result))
{
$uniqueKey = false;
}
$db->sql_freeresult($result);
$uniqueKey = true;
}
I am hashing the string nQ5GcLMsOlPIaUYJOMkmjo7f
I should be getting babcb7d489332aee9c554a7a654bb65b4dd892e5b80e0156 but i am getting ee2a3389d4b7bcba5bb64b657a4a559c56010eb8e592d84d.
Can you help me?

This is an interesting case where both answers (both the php answer and the timestampgenerator answer) are correct. In PHP >= 5.4, the tiger hashes use big-endian byte notation and in PHP < 5.4, it presumably used little-endian byte notation (noted in the changelog http://php.net/manual/en/function.hash.php). The function below is in the php docs and oldtiger gives babcb7d489332aee9c554a7a654bb65b4dd892e5b80e0156 as the result.
function old_tiger($data = "", $width=192, $rounds = 3) {
return substr(
implode(
array_map(
function ($h) {
return str_pad(bin2hex(strrev($h)), 16, "0");
},
str_split(hash("tiger192,$rounds", $data, true), 8)
)
),
0, 48-(192-$width)/4
);
}
echo hash('tiger192,3', 'a-string'), PHP_EOL;
echo old_tiger('a-string'), PHP_EOL;
If you notice, both babcb7d489332aee9c554a7a654bb65b4dd892e5b80e0156 and ee2a3389d4b7bcba5bb64b657a4a559c56010eb8e592d84d are anagrams of each other which is more than a coincidence. The endianness is changed between the two strings. Each set of 8 bytes is in byte-reversed order.
ee-2a-33-89-d4-b7-bc-ba becomes ba-bc-b7-d4-89-33-2a-ee. The byte-order endieness is switched for each 64-bit(8 byte) word.

Related

Decrypting string encrypted in C# with RijndaelManaged class using PHP

Here's some C# code (I've modified it slightly to modify some of the hard coded values in it):
public static string Decrypt(string InputFile)
{
string outstr = null;
if ((InputFile != null))
{
if (File.Exists(InputFile))
{
FileStream fsIn = null;
CryptoStream cstream = null;
try
{
byte[] _b = { 94, 120, 102, 204, 199, 246, 243, 104, 185, 115, 76, 48, 220, 182, 112, 101 };
fsIn = File.Open(InputFile, FileMode.Open, System.IO.FileAccess.Read);
SymmetricAlgorithm symm = new RijndaelManaged();
PasswordDeriveBytes Key = new PasswordDeriveBytes(System.Environment.MachineName, System.Text.Encoding.Default.GetBytes("G:MFX62rlABW:IUYAX(i"));
ICryptoTransform transform = symm.CreateDecryptor(Key.GetBytes(24), _b);
cstream = new CryptoStream(fsIn, transform, CryptoStreamMode.Read);
StreamReader sr = new StreamReader(cstream);
char[] buff = new char[1000];
sr.Read(buff, 0, 1000);
outstr = new string(buff);
}
finally
{
if (cstream != null)
{
cstream.Close();
}
if (fsIn != null)
{
fsIn.Close();
}
}
}
}
return outstr;
}
I need to come up with a function to do the same in PHP. Bear in mind, I did not write the C# code and I cannot modify it, so even if it's bad, I'm stuck with it. I've searched all over and have found bits and pieces around, but nothing that works so far. All examples I've found use mcrypt, which seems to be frowned upon these days, but I'm probably stuck using it. Next, I found the following post which has some useful info: Rewrite Rijndael 256 C# Encryption Code in PHP
So looks like the PasswordDeriveBytes class is the key to this. I created the following PHP code to try to decrypt:
function PBKDF1($pass,$salt,$count,$dklen) {
$t = $pass.$salt;
//echo 'S||P: '.bin2hex($t).'<br/>';
$t = sha1($t, true);
//echo 'T1:' . bin2hex($t) . '<br/>';
for($i=2; $i <= $count; $i++) {
$t = sha1($t, true);
//echo 'T'.$i.':' . bin2hex($t) . '<br/>';
}
$t = substr($t,0,$dklen);
return $t;
}
$input = 'Ry5WdjGS8rpA9eA+iQ3aPw==';
$key = "win7x64";
$salt = implode(unpack('C*', "G:MFX62rlABW:IUYAX(i"));
$salt = pack("H*", $salt);
$it = 1000;
$keyLen = 16;
$key = PBKDF1($key, $salt, $it, $keyLen);
$key = bin2hex(substr($key, 0, 8));
$iv = bin2hex(substr($key, 8, 8));
echo trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($input), MCRYPT_MODE_CBC, $iv));
You'll note that for what I believe to be System.Environment.MachineName, I put in a fixed value for now which is the computer name of the machine I'm on, so should be equivalent of what the C# code is doing. Other than that, I've noticed that using MCRYPT_RIJNDAEL_256 doesn't work, it throws the error "The IV parameter must be as long as the blocksize". If I use MCRYPT_RIJNDAEL_128, I don't get that error, but decryption still fails. I assume I'm missing the piece for the byte array _b that's used by the CreateDecryptor function, I have no idea where that's supposed to fit in. Any help is appreciated.
UPDATE
This is the solution, which was made possible by the answer marked correct. Note that the code for the PBKDF1 function is not mine, it was linked to in the answer.
function PBKDF1($pass, $salt, $count, $cb) {
static $base;
static $extra;
static $extracount= 0;
static $hashno;
static $state = 0;
if ($state == 0)
{
$hashno = 0;
$state = 1;
$key = $pass . $salt;
$base = sha1($key, true);
for($i = 2; $i < $count; $i++)
{
$base = sha1($base, true);
}
}
$result = "";
if ($extracount > 0)
{
$rlen = strlen($extra) - $extracount;
if ($rlen >= $cb)
{
$result = substr($extra, $extracount, $cb);
if ($rlen > $cb)
{
$extracount += $cb;
}
else
{
$extra = null;
$extracount = 0;
}
return $result;
}
$result = substr($extra, $rlen, $rlen);
}
$current = "";
$clen = 0;
$remain = $cb - strlen($result);
while ($remain > $clen)
{
if ($hashno == 0)
{
$current = sha1($base, true);
}
else if ($hashno < 1000)
{
$n = sprintf("%d", $hashno);
$tmp = $n . $base;
$current .= sha1($tmp, true);
}
$hashno++;
$clen = strlen($current);
}
// $current now holds at least as many bytes as we need
$result .= substr($current, 0, $remain);
// Save any left over bytes for any future requests
if ($clen > $remain)
{
$extra = $current;
$extracount = $remain;
}
return $result;
}
$input = 'base 64 encoded string to decrypt here';
$key = strtoupper(gethostname());
$salt = 'G:MFX62rlABW:IUYAX(i';
$it = 100;
$keyLen = 24;
$key = PBKDF1($key, $salt, $it, $keyLen);
$iv = implode(array_map('chr', [94, 120, 102, 204, 199, 246, 243, 104, 185, 115, 76, 48, 220, 182, 112, 101]));
_b is a static value that is used as the IV (CreateDecryptor takes a key and IV parameter). Since it is 16 bytes long, this means that you're using Rijndael-128 or more commonly known AES.
Key.GetBytes(24) suggests that a 24 byte key is derived and not a 16 byte key.
Make sure that
System.Text.Encoding.Default is equivalent with implode(unpack('C*', ...,
Default value for iterations of PasswordDeriveBytes is 1000,
Default value for hash of PasswordDeriveBytes is SHA-1
Security problems:
PBKDF1 is obsolete and PBKDF2 isn't that much better. Use up-to-date key derivation algorithms like Argon2 or scrypt.
The IV must be randomly chosen to achieve semantic security. It doesn't have to be secret, so it can be sent along with the ciphertext.
Stretching a key by encoding it to hex doesn't provide any security (don't use bin2hex).
The ciphertext is not authenticated, which means that you cannot detect (malicious) manipulation of encrypted messages. Employ encrypt-then-MAC.

Validate IBAN PHP

As designing a new platform we tried to integrate the IBAN numbers. We have to make sure that the IBAN is validated and the IBAN stored to the database is always correct. So what would be a proper way to validate the number?
As the logic was explained in my other question, I've created a function myself. Based on the logic explained in the Wikipedia article find a proper function below. Country specific validation.
Algorithm and character lengths per country at https://en.wikipedia.org/wiki/International_Bank_Account_Number#Validating_the_IBAN.
function checkIBAN($iban)
{
if(strlen($iban) < 5) return false;
$iban = strtolower(str_replace(' ','',$iban));
$Countries = array('al'=>28,'ad'=>24,'at'=>20,'az'=>28,'bh'=>22,'be'=>16,'ba'=>20,'br'=>29,'bg'=>22,'cr'=>21,'hr'=>21,'cy'=>28,'cz'=>24,'dk'=>18,'do'=>28,'ee'=>20,'fo'=>18,'fi'=>18,'fr'=>27,'ge'=>22,'de'=>22,'gi'=>23,'gr'=>27,'gl'=>18,'gt'=>28,'hu'=>28,'is'=>26,'ie'=>22,'il'=>23,'it'=>27,'jo'=>30,'kz'=>20,'kw'=>30,'lv'=>21,'lb'=>28,'li'=>21,'lt'=>20,'lu'=>20,'mk'=>19,'mt'=>31,'mr'=>27,'mu'=>30,'mc'=>27,'md'=>24,'me'=>22,'nl'=>18,'no'=>15,'pk'=>24,'ps'=>29,'pl'=>28,'pt'=>25,'qa'=>29,'ro'=>24,'sm'=>27,'sa'=>24,'rs'=>22,'sk'=>24,'si'=>19,'es'=>24,'se'=>24,'ch'=>21,'tn'=>24,'tr'=>26,'ae'=>23,'gb'=>22,'vg'=>24);
$Chars = array('a'=>10,'b'=>11,'c'=>12,'d'=>13,'e'=>14,'f'=>15,'g'=>16,'h'=>17,'i'=>18,'j'=>19,'k'=>20,'l'=>21,'m'=>22,'n'=>23,'o'=>24,'p'=>25,'q'=>26,'r'=>27,'s'=>28,'t'=>29,'u'=>30,'v'=>31,'w'=>32,'x'=>33,'y'=>34,'z'=>35);
if(array_key_exists(substr($iban,0,2), $Countries) && strlen($iban) == $Countries[substr($iban,0,2)]){
$MovedChar = substr($iban, 4).substr($iban,0,4);
$MovedCharArray = str_split($MovedChar);
$NewString = "";
foreach($MovedCharArray AS $key => $value){
if(!is_numeric($MovedCharArray[$key])){
if(!isset($Chars[$MovedCharArray[$key]])) return false;
$MovedCharArray[$key] = $Chars[$MovedCharArray[$key]];
}
$NewString .= $MovedCharArray[$key];
}
if(bcmod($NewString, '97') == 1)
{
return true;
}
}
return false;
}
Slight modification of #PeterFox answer including support for bcmod() when bcmath is not available,
<?php
function isValidIBAN ($iban) {
$iban = strtolower($iban);
$Countries = array(
'al'=>28,'ad'=>24,'at'=>20,'az'=>28,'bh'=>22,'be'=>16,'ba'=>20,'br'=>29,'bg'=>22,'cr'=>21,'hr'=>21,'cy'=>28,'cz'=>24,
'dk'=>18,'do'=>28,'ee'=>20,'fo'=>18,'fi'=>18,'fr'=>27,'ge'=>22,'de'=>22,'gi'=>23,'gr'=>27,'gl'=>18,'gt'=>28,'hu'=>28,
'is'=>26,'ie'=>22,'il'=>23,'it'=>27,'jo'=>30,'kz'=>20,'kw'=>30,'lv'=>21,'lb'=>28,'li'=>21,'lt'=>20,'lu'=>20,'mk'=>19,
'mt'=>31,'mr'=>27,'mu'=>30,'mc'=>27,'md'=>24,'me'=>22,'nl'=>18,'no'=>15,'pk'=>24,'ps'=>29,'pl'=>28,'pt'=>25,'qa'=>29,
'ro'=>24,'sm'=>27,'sa'=>24,'rs'=>22,'sk'=>24,'si'=>19,'es'=>24,'se'=>24,'ch'=>21,'tn'=>24,'tr'=>26,'ae'=>23,'gb'=>22,'vg'=>24
);
$Chars = array(
'a'=>10,'b'=>11,'c'=>12,'d'=>13,'e'=>14,'f'=>15,'g'=>16,'h'=>17,'i'=>18,'j'=>19,'k'=>20,'l'=>21,'m'=>22,
'n'=>23,'o'=>24,'p'=>25,'q'=>26,'r'=>27,'s'=>28,'t'=>29,'u'=>30,'v'=>31,'w'=>32,'x'=>33,'y'=>34,'z'=>35
);
if (strlen($iban) != $Countries[ substr($iban,0,2) ]) { return false; }
$MovedChar = substr($iban, 4) . substr($iban,0,4);
$MovedCharArray = str_split($MovedChar);
$NewString = "";
foreach ($MovedCharArray as $k => $v) {
if ( !is_numeric($MovedCharArray[$k]) ) {
$MovedCharArray[$k] = $Chars[$MovedCharArray[$k]];
}
$NewString .= $MovedCharArray[$k];
}
if (function_exists("bcmod")) { return bcmod($NewString, '97') == 1; }
// http://au2.php.net/manual/en/function.bcmod.php#38474
$x = $NewString; $y = "97";
$take = 5; $mod = "";
do {
$a = (int)$mod . substr($x, 0, $take);
$x = substr($x, $take);
$mod = $a % $y;
}
while (strlen($x));
return (int)$mod == 1;
}
The accepted answer is not the preferred way of validation. The specification dictates the following:
Check that the total IBAN length is correct as per the country. If not, the IBAN is invalid
Replace the two check digits by 00 (e.g. GB00 for the UK)
Move the four initial characters to the end of the string
Replace the letters in the string with digits, expanding the string as necessary, such that A or a = 10, B or b = 11, and Z or z = 35. Each alphabetic character is therefore replaced by 2 digits
Convert the string to an integer (i.e. ignore leading zeroes)
Calculate mod-97 of the new number, which results in the remainder
Subtract the remainder from 98, and use the result for the two check digits. If the result is a single digit number, pad it with a leading 0 to make a two-digit number
I've written a class that validates, formats and parses strings according to the spec. Hope this helps some save the time required to roll their own.
The code can be found on GitHub here.
top rated function does NOT work.
Just try a string with '%' in it...
I'm using this one :
function checkIBAN($iban) {
// Normalize input (remove spaces and make upcase)
$iban = strtoupper(str_replace(' ', '', $iban));
if (preg_match('/^[A-Z]{2}[0-9]{2}[A-Z0-9]{1,30}$/', $iban)) {
$country = substr($iban, 0, 2);
$check = intval(substr($iban, 2, 2));
$account = substr($iban, 4);
// To numeric representation
$search = range('A','Z');
foreach (range(10,35) as $tmp)
$replace[]=strval($tmp);
$numstr=str_replace($search, $replace, $account.$country.'00');
// Calculate checksum
$checksum = intval(substr($numstr, 0, 1));
for ($pos = 1; $pos < strlen($numstr); $pos++) {
$checksum *= 10;
$checksum += intval(substr($numstr, $pos,1));
$checksum %= 97;
}
return ((98-$checksum) == $check);
} else
return false;
}
I found this solution in cakephp 3.7 validation class. Plain beautiful php realization.
/**
* Check that the input value has a valid International Bank Account Number IBAN syntax
* Requirements are uppercase, no whitespaces, max length 34, country code and checksum exist at right spots,
* body matches against checksum via Mod97-10 algorithm
*
* #param string $check The value to check
*
* #return bool Success
*/
public static function iban($check)
{
if (!preg_match('/^[A-Z]{2}[0-9]{2}[A-Z0-9]{1,30}$/', $check)) {
return false;
}
$country = substr($check, 0, 2);
$checkInt = intval(substr($check, 2, 2));
$account = substr($check, 4);
$search = range('A', 'Z');
$replace = [];
foreach (range(10, 35) as $tmp) {
$replace[] = strval($tmp);
}
$numStr = str_replace($search, $replace, $account . $country . '00');
$checksum = intval(substr($numStr, 0, 1));
$numStrLength = strlen($numStr);
for ($pos = 1; $pos < $numStrLength; $pos++) {
$checksum *= 10;
$checksum += intval(substr($numStr, $pos, 1));
$checksum %= 97;
}
return ((98 - $checksum) === $checkInt);
}
This function check the IBAN and need GMP activate http://php.net/manual/en/book.gmp.php.
function checkIban($string){
$to_check = substr($string, 4).substr($string, 0,4);
$converted = '';
for ($i = 0; $i < strlen($to_check); $i++){
$char = strtoupper($to_check[$i]);
if(preg_match('/[0-9A-Z]/',$char)){
if(!preg_match('/\d/',$char)){
$char = ord($char)-55;
}
$converted .= $char;
}
}
// prevent: "gmp_mod() $num1 is not an integer string" error
$converted = ltrim($converted, '0');
return strlen($converted) && gmp_strval(gmp_mod($converted, '97')) == 1;
}
enjoy !

Vigenere in PHP

could anyone help me fix this Vigenere cypher in PHP?
Sorry for the ripped up code, that's from where I have been dissecting it for hours - trying to fix!
Anyhow, the code outputs 'Ace' when it should output 'Abc'.
There is some weird double offset which I don't have the maths brain to fix! Thanks for reading.
The code originates from here in AutoHotkey script - I have attempted to transcribe it. There are PHP Vigenere examples on the web (although not on Rosetta Code, weirdly!).. but anyhow, this one is modified to accept lower case as well as the standard capitals. Thanks.
$key = "AAA";
$keyLength = 3;
$keyIndex = 0;
$messageAsArray[0] = "A";
$messageAsArray[1] = "b";
$messageAsArray[2] = "c";
foreach ($messageAsArray as $value) //Loop through input string array
{
$thisValueASCII = ord($value);
if ($thisValueASCII >= 65 && $thisValueASCII <= 90) //if is uppercase
{
$thisValueASCIIOffset = 65;
}
else //if is lowercase
{
$thisValueASCIIOffset = 97;
}
$thisA = $thisValueASCII - $thisValueASCIIOffset;
$thisB = fmod($keyIndex,$keyLength);
$thisC = substr($key, $thisB, 1);
$thisD = ord($thisC) - 65;
$thisE = $thisA + $thisD;
$thisF = fmod($thisE,26);
$thisG = $thisF + $thisValueASCII ;
$thisOutput = chr($thisG);
$output = $output . $thisOutput ;
$keyIndex++;
}
echo $output
Ok, I read your code.
You're encoding, and your error is quite simple :
$thisG = $thisF + $thisValueASCII ;
In this step, $thisF is your encrypted letter, which value is between 0 and 25. You want to print it as an ascii char and, instead of adding the offset, you're adding the uncrypted ascii value, which makes no sense.
You should have :
$thisG = $thisF + $thisValueASCIIOffset;
A few tips.
You don't need to have your text or key as an array, you can use it as if it was one.
You can use the % operator instead of fmod. Makes the code easier to read, but it is just a personnal preference.
For instance :
$key = "AAA";
$keyLength = strlen($key);
$keyIndex = 0;
$message = str_split("Abc");
$output = '';
foreach($message as $value) // Loop through input string array
{
$thisValueASCII = ord($value);
if($thisValueASCII >= 65 && $thisValueASCII <= 90) // if is uppercase
{
$thisValueASCIIOffset = 65;
} else // if is lowercase
{
$thisValueASCIIOffset = 97;
}
$letter_value_corrected = $thisValueASCII - $thisValueASCIIOffset;
$key_index_corrected = $keyIndex % $keyLength; // This is the same as fmod but I prefer this notation.
$key_ascii_value = ord($key[$key_index_corrected]);
if($key_ascii_value >= 65 && $key_ascii_value <= 90) // if is uppercase
{
$key_offset = 65;
} else // if is lowercase
{
$key_offset = 97;
}
$final_key = $key_ascii_value - $key_offset;
$letter_value_encrypted = ($letter_value_corrected + $final_key)%26;
$output = $output . chr($letter_value_encrypted + $thisValueASCIIOffset);
$keyIndex++;
}
echo $output;
Have fun and good luck for your implementation !

drop 0 from md5() PHP if byte representation is less than 0x10

Using md5() function in PHP directly gives me the String. What I want to do before saving the string in the database is remove zeroes 0 if any in the byte representation of that hex and that byte representation is < 0x10 and then save the string in the database.
How can I do this in PHP?
MD5 - PHP - Raw Value - catch12 - 214423105677f2375487b4c6880c12ae - This is what I get now. Below is the value that I want the PHP to save in the database.
MD5 - Raw Value - catch12 - 214423105677f2375487b4c688c12ae
Wondering why? The MD5 code I have in my Android App for Login and Signup I did not append zeroes for the condition if ((b & 0xFF) < 0x10) hex.append("0"); Works fine. But the Forgot Password functionality in the site is PHP which is when the mismatch happens if the user resets password. JAVA code below.
byte raw[] = md.digest();
StringBuffer hexString = new StringBuffer();
for (int i=0; i<raw.length; i++)
hexString.append(Integer.toHexString(0xFF & raw[i]));
v_password = hexString.toString();
Any help on the PHP side so that the mismatch does not happen would be very very helpful. I can't change the App code because that would create problems for existing users.
Thank you.
Pass the "normal" MD5 hash to this function. It will parse it into the individual byte pairs and strip leading zeros.
EDIT: Fixed a typo
function convertMD5($md5)
{
$bytearr = str_split($md5, 2);
$ret = '';
foreach ($bytearr as $byte)
$ret .= ($byte[0] == '0') ? str_replace('0', '', $byte) : $byte;
return $ret;
}
Alternatively, if you don't want zero-bytes completely stripped (if you want 0x00 to be '0'), use this version:
function convertMD5($md5)
{
$bytearr = str_split($md5, 2);
$ret = '';
foreach ($bytearr as $byte)
$ret .= ($byte[0] == '0') ? $byte[1] : $byte;
return $ret;
}
$md5 = md5('catch12');
$new_md5 = '';
for ($i = 0; $i < 32; $i += 2)
{
if ($md5[$i] != '0') $new_md5 .= $md5[$i];
$new_md5 .= $md5[$i+1];
}
echo $new_md5;
To strip leading zeros (00->0, 0a->a, 10->10)
function stripZeros($md5hex) {
$res =''; $t = str_split($md5hex, 2);
foreach($t as $pair) $res .= dechex(hexdec($pair));
return $res;
}
To strip leading zeros & zero bytes (00->nothing, 0a->a, 10->10)
function stripZeros($md5hex) {
$res =''; $t = str_split($md5hex, 2);
foreach($t as $pair) {
$b = dechex(hexdec($pair));
if ($b!=0) $res .= $b;
}
return $res;
}

Encoding like base36 including uppercase

I am using base36 to shorten URLs. I have an id of a blog entry and convert that id to base36 to make it smaller. Base36 only includes lowercase letters. How can I include uppercase letters? If I use base64_encode it actually makes the string longer.
you can find examples of source-code to create short-urls containing letters (both lower and upper case) and number on those two articles, for instance :
Create short IDs with PHP - Like Youtube or TinyURL
Building a URL Shortener
Here is the portion of code used in that second article (quoting) :
$codeset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
$base = strlen($codeset);
$n = 300;
$converted = "";
while ($n > 0) {
$converted = substr($codeset, ($n % $base), 1) . $converted;
$n = floor($n/$base);
}
echo $converted; // 4Q
And you can pretty easily encapsulate this in a function -- only thing to consider is that $n is to be received as a parameter :
function shorten($n) {
$codeset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
$base = strlen($codeset);
$converted = "";
while ($n > 0) {
$converted = substr($codeset, ($n % $base), 1) . $converted;
$n = floor($n/$base);
}
return $converted;
}
And calling it this way :
$id = 123456;
$url = shorten($id);
var_dump($url);
You get :
string 'w7e' (length=3)
(You can also add some other characters, if needed -- depending on what you want to get in your URLs)
Edit after the comment :
Reading through the second article (from which I got the shortening code), you'll find the code that does the un-shortening.
Encapsulating that code in a function shouldn't be that hard, and might get you something like this :
function unshorten($converted) {
$codeset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
$base = strlen($codeset);
$c = 0;
for ($i = strlen($converted); $i; $i--) {
$c += strpos($codeset, substr($converted, (-1 * ( $i - strlen($converted) )),1))
* pow($base,$i-1);
}
return $c;
}
And calling it with a shortened-url :
$back_to_id = unshorten('w7e');
var_dump($back_to_id);
Will get you :
int 123456
function dec2any( $num, $base=62, $index=false ) {
// Parameters:
// $num - your decimal integer
// $base - base to which you wish to convert $num (leave it 0 if you are providing $index or omit if you're using default (62))
// $index - if you wish to use the default list of digits (0-1a-zA-Z), omit this option, otherwise provide a string (ex.: "zyxwvu")
if (! $base ) {
$base = strlen( $index );
} else if (! $index ) {
$index = substr( "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ,0 ,$base );
}
$out = "";
for ( $t = floor( log10( $num ) / log10( $base ) ); $t >= 0; $t-- ) {
$a = floor( $num / pow( $base, $t ) );
$out = $out . substr( $index, $a, 1 );
$num = $num - ( $a * pow( $base, $t ) );
}
return $out;
}
Shamelessly borrowed from a commenter on PHP's base_convert() page (base_convert() only works up to base 32).

Categories