MD5-hash in Base32
Voor een ETag wil ik een hexadecimale MD5-hash converteren naar Base32. Dat heb ik op de volgende twee manieren geprobeerd, maar ik krijg door afrondingsverschillen onnauwkeurige resultaten:
Hoe kan ik de conversie uitvoeren met behoud van de volledige precisie?
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
<?php
$file = '/pad/naar/een/cachebestand.tmp';
$etag = md5_file($file);
$etag = base_convert($etag, 16, 32);
// $etag == string(26) "4sfh0pbocb8000000000000000"
$etag = md5_file($file);
$etag = hexdec($etag);
$etag = base_convert($etag, 10, 32);
// $etag == string(11) "1r3pb3t0r0a"
?>
$file = '/pad/naar/een/cachebestand.tmp';
$etag = md5_file($file);
$etag = base_convert($etag, 16, 32);
// $etag == string(26) "4sfh0pbocb8000000000000000"
$etag = md5_file($file);
$etag = hexdec($etag);
$etag = base_convert($etag, 10, 32);
// $etag == string(11) "1r3pb3t0r0a"
?>
Hoe kan ik de conversie uitvoeren met behoud van de volledige precisie?
Als ik in de handleiding kijk:
string base_convert ( string $number , int $frombase , int $tobase )
In jou voorbeeld ga je van 16 naar 32 en daarna van 32 naar 10. Dat levert een verschil op
string base_convert ( string $number , int $frombase , int $tobase )
In jou voorbeeld ga je van 16 naar 32 en daarna van 32 naar 10. Dat levert een verschil op
Hm, zowel base_convert alsmede hexdec lijken beide te kampen met afrondingen en conversies.
Laten hier op php.net nu op beide plekken in de user comments twee functies voor staan (respectievelijk str_baseconvert en bchexdec):
Ik heb hier verder geen wiskundige of technische onderbouwing voor, maar met de volgende hash als invoer van een arbitrair bestand leidt dit via beide wegen tot hetzelfde antwoord:
Ook weet ik niet of je hier iets aan hebt :p.
Laten hier op php.net nu op beide plekken in de user comments twee functies voor staan (respectievelijk str_baseconvert en bchexdec):
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
function str_baseconvert($str, $frombase=10, $tobase=36) {
$str = trim($str);
if (intval($frombase) != 10) {
$len = strlen($str);
$q = 0;
for ($i=0; $i<$len; $i++) {
$r = base_convert($str[$i], $frombase, 10);
$q = bcadd(bcmul($q, $frombase), $r);
}
}
else $q = $str;
if (intval($tobase) != 10) {
$s = '';
while (bccomp($q, '0', 0) > 0) {
$r = intval(bcmod($q, $tobase));
$s = base_convert($r, 10, $tobase) . $s;
$q = bcdiv($q, $tobase, 0);
}
}
else $s = $q;
return $s;
}
function bchexdec($hex)
{
$len = strlen($hex);
$dec = 0; // initialisatie ontbrak nog :p
for ($i = 1; $i <= $len; $i++)
$dec = bcadd($dec, bcmul(strval(hexdec($hex[$i - 1])), bcpow('16', strval($len - $i))));
return $dec;
}
?>
function str_baseconvert($str, $frombase=10, $tobase=36) {
$str = trim($str);
if (intval($frombase) != 10) {
$len = strlen($str);
$q = 0;
for ($i=0; $i<$len; $i++) {
$r = base_convert($str[$i], $frombase, 10);
$q = bcadd(bcmul($q, $frombase), $r);
}
}
else $q = $str;
if (intval($tobase) != 10) {
$s = '';
while (bccomp($q, '0', 0) > 0) {
$r = intval(bcmod($q, $tobase));
$s = base_convert($r, 10, $tobase) . $s;
$q = bcdiv($q, $tobase, 0);
}
}
else $s = $q;
return $s;
}
function bchexdec($hex)
{
$len = strlen($hex);
$dec = 0; // initialisatie ontbrak nog :p
for ($i = 1; $i <= $len; $i++)
$dec = bcadd($dec, bcmul(strval(hexdec($hex[$i - 1])), bcpow('16', strval($len - $i))));
return $dec;
}
?>
Ik heb hier verder geen wiskundige of technische onderbouwing voor, maar met de volgende hash als invoer van een arbitrair bestand leidt dit via beide wegen tot hetzelfde antwoord:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
<?php
$hash = 'dc3a240b57f9c6f87694b28c3c512b42';
// manier #1
echo str_baseconvert($hash, 16, 32).'<hr />'; // 6s78i0mlvpors7d55ihgu52aq2
// manier #2
$test = bchexdec($hash);
echo $test.'<br />'; // 292732043355959189153777150500485016386
echo str_baseconvert($test, 10, 32); // 6s78i0mlvpors7d55ihgu52aq2
?>
$hash = 'dc3a240b57f9c6f87694b28c3c512b42';
// manier #1
echo str_baseconvert($hash, 16, 32).'<hr />'; // 6s78i0mlvpors7d55ihgu52aq2
// manier #2
$test = bchexdec($hash);
echo $test.'<br />'; // 292732043355959189153777150500485016386
echo str_baseconvert($test, 10, 32); // 6s78i0mlvpors7d55ihgu52aq2
?>
Ook weet ik niet of je hier iets aan hebt :p.
Dank jullie wel!
Ik zag met jullie input dat ik het even moest omdenken. Base16 (hex) en Base32 zijn slechts stringnotaties van binaire data. Voor het zusje Base64 geldt hetzelfde. Ik kan dus ook md5_file() met binaire output gebruiken en daarna base64_encode() gebruiken voor de conversie naar een string. En dat werkt:
Ik zag met jullie input dat ik het even moest omdenken. Base16 (hex) en Base32 zijn slechts stringnotaties van binaire data. Voor het zusje Base64 geldt hetzelfde. Ik kan dus ook md5_file() met binaire output gebruiken en daarna base64_encode() gebruiken voor de conversie naar een string. En dat werkt:




