If anyone needs to do this with PHP, I ported Adrian's answer. Requires PHP 8.0 or newer:
<?php
declare(strict_types=1);
namespace Shadowhand\Salesforce;
use function assert;
use function strlen;
use function strpos;
use function strtolower;
use function strtoupper;
use function substr;
/**
* @link https://salesforce.stackexchange.com/questions/123217/converting-uppercased-18-digit-id-to-valid-id
*/
final class SalesforceId
{
private const CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ012345';
public static function correct(string $input): string
{
assert(assertion: strlen($input) === 18);
$id = '';
$capitalize = [
...self::shouldCapitalize(letter: substr($input, offset: 15, length: 1)),
...self::shouldCapitalize(letter: substr($input, offset: 16, length: 1)),
...self::shouldCapitalize(letter: substr($input, offset: 17, length: 1)),
];
for ($i = 0; $i < 15; $i++) {
$letter = substr($input, offset: $i, length: 1);
$id .= $capitalize[$i] ? strtoupper($letter) : strtolower($letter);
}
$id .= strtoupper(substr($input, offset: 15, length: 3));
return $id;
}
private static function shouldCapitalize(string $letter): array
{
$index = strpos(haystack: self::CHARS, needle: strtoupper($letter));
$result = [];
for ($bit = 0; $bit < 5; $bit++) {
$result[] = ($index & (1 << $bit)) !== 0;
}
return $result;
}
private function __construct()
{
}
}
And here is the PHPUnit test:
<?php
declare(strict_types=1);
namespace Shadowhand\Salesforce;
use PHPUnit\Framework\TestCase;
use function strtolower;
use function strtoupper;
class SalesforceIdTest extends TestCase
{
public function testShouldCorrectCapitalization(): void
{
$id = '00129000007Kbn7AAC';
self::assertSame(expected: $id, actual: SalesforceId::correct(strtoupper($id)));
self::assertSame(expected: $id, actual: SalesforceId::correct(strtolower($id)));
}
}
Map<String, sObjectt>
having String as 18-digit Id in uppercase.