Omdat (o.a.) Marktplaats de onhebbelijkheid heeft om URL's standaard naar lower case ("kleine letters") te drukken kun je daar niet met
base-64 encoding werken (die gebruikt zowel hoofd- als kleine letters - wat daardoor dus onbruikbaar wordt). Maar om nou meteen terug te schakelen naar
hexadecimaal is ook zo wat. PHP biedt zelf geen ondersteuning voor andere encodings, dus dan moet je het zelf maar doen (online is van alles te vinden, maar niet zo geheugen/processor-efficiƫnt als deze!):
<?php
/**
* Base encode parameters.
* @param string $base Base characters.
* @param int $length Number of characters in base.
* @param int $bits Number of bits possible in character range (rounded up).
* @param int $max Maximum value in base without data loss.
* @param bool $oversize True when the bit size is too large for the base.
*/
protected static function baseParams(&$base,&$length,&$bits,&$max,&$oversize){
if(($length = strlen($base)) < 2) throw new \ValueError('Not enough characters in base');
if(count(array_unique($base = str_split($base))) < $length) throw new \ValueError('Duplicate characters in base');
$bits = 0;
while(($max = (1 << ++$bits)) < $length);
if($oversize = $max > $length) $max >>= 1;
}
/**
* Encode a string with a base set of characters.
* @param string $base Base characters.
* @param string $str String to encode.
* @return string String encoded with characters from base.
*/
public static function baseEncode($base,$str){
$result = null;
if($count = strlen($str)){
self::baseParams($base,$length,$bits,$max,$oversize);
$buffer = $size = $fill = $position = 0; //bit buffer, buffer size, fillers in buffer, position in string
while(($position < $count) || ($size > $fill)){ //still bytes or bits to process
if($size < $bits){ //add next byte (or filler) to buffer
$buffer <<= 8;
$size += 8;
if($position < $count) $buffer += ord($str[$position++]);
else $fill += 8;
}
$index = $buffer >> ($size - ($gone = $bits)); //get bits from buffer
if($oversize && (($index < $max) || ($index >= $length))){ //not in extra chars - take 1 bit less.
$index >>= 1;
$gone--;
}
$result .= $base[$index];
$buffer &= (1 << ($size -= $gone)) - 1;
}
}
return $result;
}
/**
* Decode a string encoded with a base set of characters.
* @param string $base Base characters.
* @param string $str String to decode.
* @return string Decoded (original) string.
*/
public static function baseDecode($base,$str){
$result = null;
if($count = strlen($str)){
self::baseParams($base,$length,$bits,$max,$oversize);
$map = array_flip($base);
$buffer = $size = 0; //bit buffer, buffer size
for($position = 0; $position < $count; $position++){
if (!array_key_exists($char = $str[$position],$map)) throw new \ValueError("Char '$char' is not in base");
$index = $map[$char];
$add = $bits;
if($oversize){ //bit size larger then char range
if($index < $max) $add--; //lower range = 1 bit less
elseif($index >= $length){ //out of range = 1 bit less
$index >>= 1;
$add--;
} //else: in extra range = maximum bits used
}
$buffer = ($buffer << $add) | $index;
$size += $add;
while($size >= 8){ //write bytes from buffer
$result .= chr($buffer >> ($size -= 8));
$buffer &= (1 << $size) - 1;
}
}
}
return $result;
}
De "base" kan dus van alles zijn. Als het maar meer dan 2 (en minder dan 256) unieke karakters zijn - het precieze aantal maakt niet uit (hoeft geen macht van 2 te zijn).
Rob, zaterdag 30 september 2023, 13:22