12e464181SGreg Roach<?php 22e464181SGreg Roach 32e464181SGreg Roach/** 42e464181SGreg Roach * webtrees: online genealogy 5d11be702SGreg Roach * Copyright (C) 2023 webtrees development team 62e464181SGreg Roach * This program is free software: you can redistribute it and/or modify 72e464181SGreg Roach * it under the terms of the GNU General Public License as published by 82e464181SGreg Roach * the Free Software Foundation, either version 3 of the License, or 92e464181SGreg Roach * (at your option) any later version. 102e464181SGreg Roach * This program is distributed in the hope that it will be useful, 112e464181SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 122e464181SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 132e464181SGreg Roach * GNU General Public License for more details. 142e464181SGreg Roach * You should have received a copy of the GNU General Public License 152e464181SGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>. 162e464181SGreg Roach */ 172e464181SGreg Roach 182e464181SGreg Roachdeclare(strict_types=1); 192e464181SGreg Roach 202e464181SGreg Roachnamespace Fisharebest\Webtrees\Factories; 212e464181SGreg Roach 222e464181SGreg Roachuse Fisharebest\Webtrees\Contracts\IdFactoryInterface; 232e464181SGreg Roachuse Ramsey\Uuid\Exception\RandomSourceException; 242e464181SGreg Roachuse Ramsey\Uuid\Uuid; 252e464181SGreg Roach 262e464181SGreg Roachuse function dechex; 272e464181SGreg Roachuse function hexdec; 282e464181SGreg Roachuse function str_pad; 292e464181SGreg Roachuse function strtoupper; 302e464181SGreg Roachuse function substr; 312e464181SGreg Roach 322e464181SGreg Roachuse const STR_PAD_LEFT; 332e464181SGreg Roach 342e464181SGreg Roach/** 352e464181SGreg Roach * Create a unique identifier. 362e464181SGreg Roach */ 372e464181SGreg Roachclass IdFactory implements IdFactoryInterface 382e464181SGreg Roach{ 392e464181SGreg Roach /** 402e464181SGreg Roach * @return string 412e464181SGreg Roach */ 422e464181SGreg Roach public function uuid(): string 432e464181SGreg Roach { 442e464181SGreg Roach try { 452e464181SGreg Roach return strtolower(strtr(Uuid::uuid4()->toString(), ['-' => ''])); 4628d026adSGreg Roach } catch (RandomSourceException) { 472e464181SGreg Roach // uuid4() can fail if there is insufficient entropy in the system. 482e464181SGreg Roach return ''; 492e464181SGreg Roach } 502e464181SGreg Roach } 512e464181SGreg Roach 522e464181SGreg Roach /** 532e464181SGreg Roach * An identifier for use in CSS/HTML 542e464181SGreg Roach * 5561351a03SGreg Roach * @param string $prefix 5661351a03SGreg Roach * 572e464181SGreg Roach * @return string 582e464181SGreg Roach */ 592e464181SGreg Roach public function id(string $prefix = 'id-'): string 602e464181SGreg Roach { 612e464181SGreg Roach return $prefix . $this->uuid(); 622e464181SGreg Roach } 632e464181SGreg Roach 642e464181SGreg Roach /** 652e464181SGreg Roach * A value for _UID fields, as created by PAF 662e464181SGreg Roach * 672e464181SGreg Roach * @return string 682e464181SGreg Roach */ 692e464181SGreg Roach public function pafUid(): string 702e464181SGreg Roach { 712e464181SGreg Roach $uid = strtoupper(strtr($this->uuid(), ['-' => ''])); 722e464181SGreg Roach 732e464181SGreg Roach if ($uid === '') { 742e464181SGreg Roach return ''; 752e464181SGreg Roach } 762e464181SGreg Roach 772e464181SGreg Roach return $uid . $this->pafUidChecksum($uid); 782e464181SGreg Roach } 792e464181SGreg Roach 802e464181SGreg Roach /** 81*e5766395SGreg Roach * @param string $uid exactly 32 hex characters 822e464181SGreg Roach * 832e464181SGreg Roach * @return string 842e464181SGreg Roach */ 852e464181SGreg Roach public function pafUidChecksum(string $uid): string 862e464181SGreg Roach { 872e464181SGreg Roach $checksum_a = 0; // a sum of the bytes 882e464181SGreg Roach $checksum_b = 0; // a sum of the incremental values of $checksum_a 892e464181SGreg Roach 902e464181SGreg Roach for ($i = 0; $i < 32; $i += 2) { 912e464181SGreg Roach $checksum_a += hexdec(substr($uid, $i, 2)); 922e464181SGreg Roach $checksum_b += $checksum_a & 0xff; 932e464181SGreg Roach } 942e464181SGreg Roach 952e464181SGreg Roach $digit1 = str_pad(dechex($checksum_a), 2, '0', STR_PAD_LEFT); 962e464181SGreg Roach $digit2 = str_pad(dechex($checksum_b), 2, '0', STR_PAD_LEFT); 972e464181SGreg Roach 982e464181SGreg Roach return strtoupper($digit1 . $digit2); 992e464181SGreg Roach } 1002e464181SGreg Roach} 101