Forum Moderators: coopster
<?php
//>NumberEncoder.php
class NumberEncoder {
const keyString = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
private $_key;
function __construct($ks = self::keyString) {
$this->_key = $ks;
}
//encodes a number to a four character code.
//maximum size of $num accepted will be dependant upon the fact that we are only
//encoding to four characters, and upon the number of characters given to use for
//encoding. With the default NumberEncoder::keyString (62 characters) the largest
//encodable number is 14776335
//Formula for determining maximum number size is: number of encoding characters to the fourth power - 1
public function encode($num) {
$ca = str_split($this->_key); //62 items in $ca, if using NumberEncoder::keyString
$c = count($ca); //number of chars we have to work with for encoding
$c2 = pow($c, 2);
$c3 = pow($c, 3);
$c4 = pow($c, 4);
if (!is_int($num) || $num >= $c4) {
return null;
}
//fourth char will be the remainder of the number divided by $c, if number is greater than $c
//third char will be the number of multiples of $c
//second char will be the number of multiples of $c*$c
//first char will be the number of multiples of $c*$c*$c
//maximum number of multiples is of course limited to $c
$d1 = $d2 = $d3 = 0;
$d4 = $num % $c;
if ($num < $c) {
$d4 = $num;
} else if ($num < $c2) {
$d3 = floor($num / $c); //number of multiples of $c
} else if ($num < $c3) {
$d2 = floor($num / $c2); //number of multiples of $c2
$d3 = floor(($num - ($c2 * $d2)) / $c); //number of multiples of $c
} else { //$num is >= $c3 && < $c4
$d1 = floor($num / $c3); //number of multiples of $c3
$d2 = floor(($num - ($c3 * $d1)) / $c2); //number of multiples of $c2
$d3 = floor(($num - (($c2 * $d2) + ($c3 * $d1))) / $c); //number of multiples of $c
}
return $ca[$d1].$ca[$d2].$ca[$d3].$ca[$d4];
}
//decodes a number which was encoded with this class's encode method
public function decode($str) {
$key = $this->_key;
$matchkey = preg_replace("/(\(|\))/", '\$1', $key);
//check $str is of proper type and length, and does not contain characters other than our key contains
if (!((is_string($str) || is_int($str)) && strlen($str) == 4) || preg_match("/[^$matchkey]/", $str)) {
return null;
}
$caf = array_flip(str_split($key));
$sa = str_split($str);
$c = count($caf); //62 items in $caf, number of chars we have to work with for encoding/decoding
$c2 = $c * $c; //3844 (with 62 characters given for encoding use)
$c3 = $c * $c * $c; //238328 (with 62 characters given for encoding use)
$d1 = $caf[$sa[0]] * $c3;
$d2 = $caf[$sa[1]] * $c2;
$d3 = $caf[$sa[2]] * $c;
$d4 = $caf[$sa[3]];
return $d1 + $d2 + $d3 + $d4;
}
}
?>
<?php
//>number_encoder_test.php
function erp($s, $color = 0) {
$colors = array('black', 'red', 'green', 'blue');
echo '<p style="color:'.$colors[$color].'; margin:4px;">'.$s."</p>\n";
}
function pre($o) {
echo '<pre style="margin:4px; padding:0 4px;">'."\n";
print_r($o);
echo "</pre>\n";
}
include('NumberEncoder.php'); //import the NumberEncoder class
$NE = new NumberEncoder(); //not passing a string to NumberEncoder uses the default key which is NumberEncoder::keyString
erp('NumberEncoder::keyString = '.NumberEncoder::keyString);
//some test numbers to run through:
$nArr = array(1, 12, 50, 61, 62, 104, 233, 675, 3400, 3844, 3845, 16788, 123000, 238328, 1333666, 9888777, 14776335, 14776336);
foreach ($nArr as $i => $n) {
$encoded = $NE->encode($n);
if ($encoded !== null) {
$decoded = $NE->decode($encoded);
pre('$n = '.$n.', $encoded = '.$encoded.', $decoded = '.$decoded);
} else {
erp('$n = '.$n.', NUMBER TOO LARGE, CAN NOT ENCODE TO 4 CHARACTERS WITH THE ENCODE CHARACTERS GIVEN!');
}
}
erp('Example of using NumberEncoder with a different, longer key:', 1);
$key = str_split(NumberEncoder::keyString.'[]{}()*%$#@!?,.;:"\'^&');
$c = count($key);
$max = pow($c, 4) - 1;
erp('Number of chars for encoding: '.$c.', maximum size of acceptable number (see notes in NumberEncoder->encode): '.$max, 1);
shuffle($key); //randomize the order of the characters
$NE2 = new NumberEncoder(implode('', $key));
foreach ($nArr as $i => $n) {
$encoded = $NE2->encode($n);
if ($encoded !== null) {
$decoded = $NE2->decode($encoded);
pre('$n = '.$n.', $encoded = '.$encoded.', $decoded = '.$decoded);
} else {
erp('$n = '.$n.', NUMBER TOO LARGE, CAN NOT ENCODE TO 4 CHARACTERS WITH THE ENCODE CHARACTERS GIVEN!');
}
}
?>
//decodes a number which was encoded with this class's encode method
public function decode($str) {
$key = $this->_key;
//check $str is of proper type and length
if (!((is_string($str) || is_int($str)) && strlen($str) == 4)) {
return null;
}
$caf = array_flip(str_split($key));
$sa = str_split($str);
foreach ($sa as $s) { //verify the $str did not contain characters which are not in our $key
if (!array_key_exists($s, $caf)) {
return null;
}
}
$c = count($caf); //62 items in $caf, number of chars we have to work with for encoding/decoding
$c2 = $c * $c; //3844 (with 62 characters given for encoding use)
$c3 = $c * $c * $c; //238328 (with 62 characters given for encoding use)
$d1 = $caf[$sa[0]] * $c3;
$d2 = $caf[$sa[1]] * $c2;
$d3 = $caf[$sa[2]] * $c;
$d4 = $caf[$sa[3]];
return $d1 + $d2 + $d3 + $d4;
}