<?php
# x_base.php
# coded by uwe stein
#
# Copyright (C) 2010 Uwe Stein
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# x_base provides the possibility to convert numbers to/from each base
# by default the base-range is limited from 2 up to 36
# this limit may change if there is used a different set of alnum-digits
# the max-value for base is the len of the string alnum_digit.
# using x_base may show funny results
# try the following decimal nummbers converted into base 36
# 992128766
# 1952720019
# 676
# 10
# 765164
class x_base
{
// class-members
private $num; // the (n_base) value
private $base; // the base
private $dec_num; // the (decimal) value
private $alnum_digit; // the used set of digits
private $max_base; // the max possible base to convert
// class functions
public function __construct($num,$base=10)
{
$this->alnum_digit = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // default use upper case letters
$this->num = $num; // the mumber encoded with base
$this->base= $base; // the used base
$this->max_base = strlen( $this->alnum_digit );
$this->dec_num = $this->calc_dec($num); // dec_num always keeps the decimal-value of num
}
public function getNum() { return $this->num;} // returns the encoded value
public function getDec() { return $this->dec_num;} // returns the decimal value
public function getBase() { return $this->base;} // returns the used base
public function getMaxBase() { return $this->max_base;} // returns the maximum-base
public function toUpper() {$this->changeAlnumDigits("upper");} // use upper digits
public function toLower() {$this->changeAlnumDigits("lower");} // use lower digits
public function mixedDigits() {$this->changeAlnumDigits("mixed");} // use upper and lower digits
// take Care! -> a and A represent
// different values while using mixed Digits
// returns the stored number converted to base $base
// does the same as getNum but doesnt change (restores)base or number
public function getConvNum($base)
{
$tmp_num = $this->num;
$tmp_base = $this->base;
// dbg var_dump($this);
$this->setBase($base);
// dbg var_dump($this);
$ret = $this->num;
$this->num = $tmp_num;
$this->base = $tmp_base;
return $ret;
}
// change the base encoded number
// param: $value ; the used base
// return: none
public function setNum($value,$base=10)
{
$this->num = $value;
$this->base = $base;
$this->dec_num = $this->calc_dec($value);
}
// changes the base and builds the new encoded number using the new base
public function setBase($base)
{
if ($base > strlen($this->alnum_digit) OR $base < 2 )
die("<br><b>Invalid Base ".$value." Allowed Range = 2 - ".strlen($this->alnum_digit)."</b>");
if ($base != $this->base)
{
$this->base = $base;
$this->build_nBase_number();
}
}
private function calc_dec($number)
{
// nothing to do if base == 10
if ( $this->base == 10 )
return $number;
$dec = 0;
// walk through the num-string (from right side)
$t_num = strrev($number);
for ($i = 0; $i < strlen($t_num); $i++)
{
// no check for allowed digits
// the user has to keep an eye on valid digits
// the position of the digit in $this->alnum_digit represents the decimal value first=1, scnd=1 ...
$val = strpos($this->alnum_digit,$t_num[$i]);
$dec += $val * ( pow($this->base,$i));
}
//$this->dec_num = $dec;
return $dec;
}
private function build_nBase_number()
{
$num = $this->get_highest_numPart($this->dec_num,$this->base);
//dbg("erster Aufruf von get_highest...",$num);
$rest = $this->dec_num - $this->calc_dec($num);
while ($rest)
{
// get the next numPart
$n_num = $this->get_highest_numPart($rest,$this->base);
//dbg("schleifenaufruf von get_highest...",$n_num);
// get the remaining rest
$rest -= $this->calc_dec($n_num);
// "add the $n_num-string to the $num-string
// check the length of $n_num to find the position
// and add the first digit of $n_num
$a = strlen($n_num);
$b = strlen($num);
$num[$b-$a]= $n_num[0];
}
// arrived here, all should be done
// store the value
$this->num = $num;
}
// find the highest valid left digit ( filled with "0" )
private function get_highest_numPart ($dec_num,$base)
{
if ($dec_num == 0)
return "0";
$dec = 0;
$pos = 0;
$last_num = "";
do
{
$num = "";
// walk through the digits ( start with 1 because "0" would be returned )
for ($i =1; $i < $base; $i++)
{
// check the next digit
$num = $this->alnum_digit[$i];
// add digits if $num has 2 ore more ( add "0" on right side )
for ( $n=0; $n < $pos; $n++)
$num .= "0";
// first get the decimal-value
$dec = $this->calc_dec($num);
// then check wether $num is smaller or equal to dec_num
// equal? then return
if ($dec == $dec_num)
return $num;
// smaller? then save the current num and continue
if ($dec < $dec_num )
{
$last_num = $num;
}
// hihger ? then return the last valid num
if ($dec > $dec_num )
{
return $last_num;
}
}
// arrived here, add 1 more digit ( add a "0" at right position )
$pos++;
} while ($dec < $dec_num);
}
private function changeAlnumDigits($uc)
{
switch ($uc)
{
case "upper" : $this->alnum_digit = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
break;
case "lower" : $this->alnum_digit = "0123456789abcdefghijklmnopqrstuvwxyz";
break;
case "mixed" : $this->alnum_digit = "01234567890123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
break;
default : die ("Invalid Param ".$uc." in Function changeAlnumDigits");
}
$this->max_base = strlen($this->alnum_digit);
// rebuild the nBase_numer
$this->build_nBase_number();
}
} // End of class
?>