Base64URL in PHP
PHP doesn’t support the Base64URL standard, but you can use built-in functions to normalize values. The only thing you have to change is to replace 62-63 index characters. More exactly, you should use “-” instead of “+” and “_” instead of “/”.
Implementations of Base64URL decode and encode in PHP:
<?php
/**
* Encode data to Base64URL
* @param string $data
* @return boolean|string
*/
function base64url_encode($data)
{
// First of all you should encode $data to Base64 string
$b64 = base64_encode($data);
// Make sure you get a valid result, otherwise, return FALSE, as the base64_encode() function do
if ($b64 === false) {
return false;
}
// Convert Base64 to Base64URL by replacing “+” with “-” and “/” with “_”
$url = strtr($b64, '+/', '-_');
// Remove padding character from the end of line and return the Base64URL result
return rtrim($url, '=');
}
/**
* Decode data from Base64URL
* @param string $data
* @param boolean $strict
* @return boolean|string
*/
function base64url_decode($data, $strict = false)
{
// Convert Base64URL to Base64 by replacing “-” with “+” and “_” with “/”
$b64 = strtr($data, '-_', '+/');
// Decode Base64 string and return the original data
return base64_decode($b64, $strict);
}
Using the above functions, let’s do some tests:
<?php
// Encode text to Base64 standard
echo base64_encode('<<???>>'); //-> "PDw/Pz8+Pg=="
// Encode same text to Base64URL (note that letters and digits remain intact)
echo base64url_encode('<<???>>'); //-> "PDw_Pz8-Pg"
// Try to decode obtained value using Base64 standard (the result appears damaged)
// In fact, since strict mode is disabled, it attempts to decode “PDwPz8Pg”
echo base64_decode('PDw_Pz8-Pg'); //-> "<<���"
// Well, now try to decode it by enabling strict mode, but the result again is wrong
echo base64_decode('PDw_Pz8-Pg', true); //-> FALSE
// Finally, get the original data using the proper function
echo base64url_decode('PDw_Pz8-Pg'); //-> "<<???>>"
Comments (8)
I hope you enjoy this discussion. In any case, I ask you to join it.
I also hadn't seen you could have
base64_decode
decode in strict-mode, so that's a nice find!Here's what I had in a little terminal script, before reading this:
php
<?php
function urlsafe_base64_encode(mixed $value): string
{
$result = base64_encode($value);
$result = strtr($result, '+/', '-_');
return rtrim($result, '=');
}
function urlsafe_base64_decode(string $value): mixed
{
$result = strtr($value, '-_', '+/');
return base64_decode($result);
}
$value = $argv[1] ?? random_bytes(random_int(4, 32));
$b64 = urlsafe_base64_encode($value);
echo $b64, PHP_EOL;
echo urlsafe_base64_decode($b64), PHP_EOL;
But yours is a bit better, so I'll use that, instead!
{
$result = base64_encode($value);
$result = strtr($result, '+/', '-_');
return rtrim($result, '=');
}
function urlsafe_base64_decode(string $value): mixed
{
$result = strtr($value, '-_', '+/');
return base64_decode($result);
}
$value = $argv[1] ?? random_bytes(random_int(4, 32));
$b64 = urlsafe_base64_encode($value);
echo $b64, PHP_EOL;
echo urlsafe_base64_decode($b64), PHP_EOL;