summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/Contracts/IdFactoryInterface.php52
-rw-r--r--app/Elements/EventsRecorded.php3
-rw-r--r--app/Elements/NoteStructure.php2
-rw-r--r--app/Elements/PafUid.php34
-rw-r--r--app/Elements/Uid.php17
-rw-r--r--app/Factories/IdFactory.php99
-rw-r--r--app/Registry.php19
-rw-r--r--app/Services/CaptchaService.php8
-rw-r--r--app/Services/UpgradeService.php3
-rw-r--r--app/Webtrees.php2
-rw-r--r--resources/views/chart-box.phtml4
-rw-r--r--resources/views/edit/edit-gedcom-fields.phtml3
-rw-r--r--resources/views/fact-gedcom-fields.phtml3
-rw-r--r--resources/views/lists/families-table.phtml3
-rw-r--r--resources/views/lists/individuals-table.phtml3
15 files changed, 193 insertions, 62 deletions
diff --git a/app/Contracts/IdFactoryInterface.php b/app/Contracts/IdFactoryInterface.php
new file mode 100644
index 0000000000..7551ffe808
--- /dev/null
+++ b/app/Contracts/IdFactoryInterface.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * webtrees: online genealogy
+ * Copyright (C) 2022 webtrees development team
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace Fisharebest\Webtrees\Contracts;
+
+/**
+ * Create a unique identifier.
+ */
+interface IdFactoryInterface
+{
+ /**
+ * @return string
+ */
+ public function uuid(): string;
+
+ /**
+ * An identifier for use in CSS/HTML
+ *
+ * @return string
+ */
+ public function id(string $prefix = 'id-'): string;
+
+ /**
+ * A value for _UID fields, as created by PAF
+ *
+ * @return string
+ */
+ public function pafUid(): string;
+
+ /**
+ * @param string $uid - exactly 32 hex characters
+ *
+ * @return string
+ */
+ public function pafUidChecksum(string $uid): string;
+}
diff --git a/app/Elements/EventsRecorded.php b/app/Elements/EventsRecorded.php
index d897fb3c77..b1bab54d08 100644
--- a/app/Elements/EventsRecorded.php
+++ b/app/Elements/EventsRecorded.php
@@ -23,7 +23,6 @@ use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Registry;
use Fisharebest\Webtrees\Tree;
use Illuminate\Support\Collection;
-use Ramsey\Uuid\Uuid;
use function array_map;
use function explode;
@@ -132,7 +131,7 @@ class EventsRecorded extends AbstractElement
->sort()
->all();
- $id2 = Uuid::uuid4()->toString();
+ $id2 = Registry::idFactory()->id();
// Our form element name contains "[]", and multiple selections would create multiple values.
$hidden = '<input type="hidden" id="' . e($id) . '" name="' . e($name) . '" value="' . e($value) . '" />';
diff --git a/app/Elements/NoteStructure.php b/app/Elements/NoteStructure.php
index 21026105e7..c22342d123 100644
--- a/app/Elements/NoteStructure.php
+++ b/app/Elements/NoteStructure.php
@@ -107,7 +107,7 @@ class NoteStructure extends SubmitterText
*/
public function labelValue(string $value, Tree $tree): string
{
- $id = 'collapse-' . Uuid::uuid4()->toString();
+ $id = Registry::idFactory()->id();
$expanded = $tree->getPreference('EXPAND_NOTES') === '1';
// A note structure can contain an inline note or a linked to a shared note.
diff --git a/app/Elements/PafUid.php b/app/Elements/PafUid.php
index c7330a1046..5dfb2b0946 100644
--- a/app/Elements/PafUid.php
+++ b/app/Elements/PafUid.php
@@ -19,15 +19,8 @@ declare(strict_types=1);
namespace Fisharebest\Webtrees\Elements;
+use Fisharebest\Webtrees\Registry;
use Fisharebest\Webtrees\Tree;
-use Ramsey\Uuid\Exception\RandomSourceException;
-use Ramsey\Uuid\Uuid;
-
-use function dechex;
-use function hexdec;
-use function strtoupper;
-use function strtr;
-use function substr;
/**
* _UID fields, as created by PAF and other applications
@@ -45,29 +38,10 @@ class PafUid extends AbstractElement
*/
public function default(Tree $tree): string
{
- if ($tree->getPreference('GENERATE_UIDS') !== '1') {
- return '';
- }
-
- try {
- $uid = strtr(Uuid::uuid4()->toString(), ['-' => '']);
- } catch (RandomSourceException $ex) {
- // uuid4() can fail if there is insufficient entropy in the system.
- return '';
+ if ($tree->getPreference('GENERATE_UIDS') === '1') {
+ return Registry::idFactory()->pafUid();
}
- $checksum_a = 0; // a sum of the bytes
- $checksum_b = 0; // a sum of the incremental values of $checksum_a
-
- // Compute checksums
- for ($i = 0; $i < 32; $i += 2) {
- $checksum_a += hexdec(substr($uid, $i, 2));
- $checksum_b += $checksum_a & 0xff;
- }
-
- $uid .= substr('0' . dechex($checksum_a), -2);
- $uid .= substr('0' . dechex($checksum_b), -2);
-
- return strtoupper($uid);
+ return '';
}
}
diff --git a/app/Elements/Uid.php b/app/Elements/Uid.php
index 5f5d9329ff..0c7c2ac2ed 100644
--- a/app/Elements/Uid.php
+++ b/app/Elements/Uid.php
@@ -19,16 +19,8 @@ declare(strict_types=1);
namespace Fisharebest\Webtrees\Elements;
+use Fisharebest\Webtrees\Registry;
use Fisharebest\Webtrees\Tree;
-use Ramsey\Uuid\Exception\RandomSourceException;
-use Ramsey\Uuid\Uuid;
-
-use function dechex;
-use function hexdec;
-use function strtolower;
-use function strtoupper;
-use function strtr;
-use function substr;
/**
* UID fields
@@ -46,11 +38,8 @@ class Uid extends AbstractElement
*/
public function default(Tree $tree): string
{
- try {
- if ($tree->getPreference('GENERATE_UIDS') === '1') {
- return strtolower(Uuid::uuid4()->toString());
- }
- } catch (RandomSourceException $ex) {
+ if ($tree->getPreference('GENERATE_UIDS') === '1') {
+ return Registry::idFactory()->uuid();
}
return '';
diff --git a/app/Factories/IdFactory.php b/app/Factories/IdFactory.php
new file mode 100644
index 0000000000..cfba19673c
--- /dev/null
+++ b/app/Factories/IdFactory.php
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * webtrees: online genealogy
+ * Copyright (C) 2022 webtrees development team
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace Fisharebest\Webtrees\Factories;
+
+use Fisharebest\Webtrees\Contracts\IdFactoryInterface;
+
+use Ramsey\Uuid\Exception\RandomSourceException;
+use Ramsey\Uuid\Uuid;
+
+use function dechex;
+use function hexdec;
+use function str_pad;
+use function strtoupper;
+use function substr;
+
+use const STR_PAD_LEFT;
+
+/**
+ * Create a unique identifier.
+ */
+class IdFactory implements IdFactoryInterface
+{
+ /**
+ * @return string
+ */
+ public function uuid(): string
+ {
+ try {
+ return strtolower(strtr(Uuid::uuid4()->toString(), ['-' => '']));
+ } catch (RandomSourceException $ex) {
+ // uuid4() can fail if there is insufficient entropy in the system.
+ return '';
+ }
+ }
+
+ /**
+ * An identifier for use in CSS/HTML
+ *
+ * @return string
+ */
+ public function id(string $prefix = 'id-'): string
+ {
+ return $prefix . $this->uuid();
+ }
+
+ /**
+ * A value for _UID fields, as created by PAF
+ *
+ * @return string
+ */
+ public function pafUid(): string
+ {
+ $uid = strtoupper(strtr($this->uuid(), ['-' => '']));
+
+ if ($uid === '') {
+ return '';
+ }
+
+ return $uid . $this->pafUidChecksum($uid);
+ }
+
+ /**
+ * @param string $uid - exactly 32 hex characters
+ *
+ * @return string
+ */
+ public function pafUidChecksum(string $uid): string
+ {
+ $checksum_a = 0; // a sum of the bytes
+ $checksum_b = 0; // a sum of the incremental values of $checksum_a
+
+ for ($i = 0; $i < 32; $i += 2) {
+ $checksum_a += hexdec(substr($uid, $i, 2));
+ $checksum_b += $checksum_a & 0xff;
+ }
+
+ $digit1 = str_pad(dechex($checksum_a), 2, '0', STR_PAD_LEFT);
+ $digit2 = str_pad(dechex($checksum_b), 2, '0', STR_PAD_LEFT);
+
+ return strtoupper($digit1 . $digit2);
+ }
+}
diff --git a/app/Registry.php b/app/Registry.php
index 3a8ea31bb0..4f24ea9c32 100644
--- a/app/Registry.php
+++ b/app/Registry.php
@@ -43,6 +43,7 @@ use Fisharebest\Webtrees\Contracts\SubmissionFactoryInterface;
use Fisharebest\Webtrees\Contracts\SubmitterFactoryInterface;
use Fisharebest\Webtrees\Contracts\SurnameTraditionFactoryInterface;
use Fisharebest\Webtrees\Contracts\TimestampFactoryInterface;
+use Fisharebest\Webtrees\Contracts\IdFactoryInterface;
use Fisharebest\Webtrees\Contracts\XrefFactoryInterface;
/**
@@ -66,6 +67,8 @@ class Registry
private static HeaderFactoryInterface $header_factory;
+ private static IdFactoryInterface $id_factory;
+
private static ImageFactoryInterface $image_factory;
private static IndividualFactoryInterface $individual_factory;
@@ -231,6 +234,22 @@ class Registry
/**
* Store or retrieve a factory object.
*
+ * @param IdFactoryInterface|null $factory
+ *
+ * @return IdFactoryInterface
+ */
+ public static function idFactory(IdFactoryInterface $factory = null): IdFactoryInterface
+ {
+ if ($factory instanceof IdFactoryInterface) {
+ self::$id_factory = $factory;
+ }
+
+ return self::$id_factory;
+ }
+
+ /**
+ * Store or retrieve a factory object.
+ *
* @param ImageFactoryInterface|null $factory
*
* @return ImageFactoryInterface
diff --git a/app/Services/CaptchaService.php b/app/Services/CaptchaService.php
index ef04ed3ced..ae0d78ea2c 100644
--- a/app/Services/CaptchaService.php
+++ b/app/Services/CaptchaService.php
@@ -19,10 +19,10 @@ declare(strict_types=1);
namespace Fisharebest\Webtrees\Services;
+use Fisharebest\Webtrees\Registry;
use Fisharebest\Webtrees\Session;
use Fisharebest\Webtrees\Validator;
use Psr\Http\Message\ServerRequestInterface;
-use Ramsey\Uuid\Uuid;
use function view;
@@ -41,9 +41,9 @@ class CaptchaService
*/
public function createCaptcha(): string
{
- $x = Uuid::uuid4()->toString();
- $y = Uuid::uuid4()->toString();
- $z = Uuid::uuid4()->toString();
+ $x = Registry::idFactory()->uuid();
+ $y = Registry::idFactory()->uuid();
+ $z = Registry::idFactory()->uuid();
Session::put('captcha-t', microtime(true));
Session::put('captcha-x', $x);
diff --git a/app/Services/UpgradeService.php b/app/Services/UpgradeService.php
index 86168a8abb..fa94782571 100644
--- a/app/Services/UpgradeService.php
+++ b/app/Services/UpgradeService.php
@@ -22,6 +22,7 @@ namespace Fisharebest\Webtrees\Services;
use Fig\Http\Message\StatusCodeInterface;
use Fisharebest\Webtrees\Http\Exceptions\HttpServerErrorException;
use Fisharebest\Webtrees\I18N;
+use Fisharebest\Webtrees\Registry;
use Fisharebest\Webtrees\Site;
use Fisharebest\Webtrees\Webtrees;
use GuzzleHttp\Client;
@@ -350,7 +351,7 @@ class UpgradeService
$site_uuid = Site::getPreference('SITE_UUID');
if ($site_uuid === '') {
- $site_uuid = Uuid::uuid4()->toString();
+ $site_uuid = Registry::idFactory()->uuid();
Site::setPreference('SITE_UUID', $site_uuid);
}
diff --git a/app/Webtrees.php b/app/Webtrees.php
index a812783f0b..e8cf51551a 100644
--- a/app/Webtrees.php
+++ b/app/Webtrees.php
@@ -45,6 +45,7 @@ use Fisharebest\Webtrees\Factories\SubmissionFactory;
use Fisharebest\Webtrees\Factories\SubmitterFactory;
use Fisharebest\Webtrees\Factories\SurnameTraditionFactory;
use Fisharebest\Webtrees\Factories\TimestampFactory;
+use Fisharebest\Webtrees\Factories\IdFactory;
use Fisharebest\Webtrees\Factories\XrefFactory;
use Fisharebest\Webtrees\GedcomFilters\GedcomEncodingFilter;
use Fisharebest\Webtrees\Http\Middleware\BadBotBlocker;
@@ -204,6 +205,7 @@ class Webtrees
Registry::filesystem(new FilesystemFactory());
Registry::gedcomRecordFactory(new GedcomRecordFactory());
Registry::headerFactory(new HeaderFactory());
+ Registry::idFactory(new IdFactory());
Registry::imageFactory(new ImageFactory());
Registry::individualFactory(new IndividualFactory());
Registry::locationFactory(new LocationFactory());
diff --git a/resources/views/chart-box.phtml b/resources/views/chart-box.phtml
index e53cae5a02..b47fbe9e2e 100644
--- a/resources/views/chart-box.phtml
+++ b/resources/views/chart-box.phtml
@@ -9,9 +9,9 @@ use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Individual;
use Fisharebest\Webtrees\Menu;
use Fisharebest\Webtrees\Module\ModuleChartInterface;
+use Fisharebest\Webtrees\Registry;
use Fisharebest\Webtrees\Services\ModuleService;
use Illuminate\Support\Collection;
-use Ramsey\Uuid\Uuid;
/**
* @var Individual|null $individual
@@ -94,7 +94,7 @@ $all_facts = $all_facts->filter(static function (Fact $fact) use ($exclude): boo
$all_facts = Fact::sortFacts($all_facts);
-$id = Uuid::uuid4()->toString();
+$id = Registry::idFactory()->id();
?>
<div class="wt-chart-box wt-chart-box-<?= strtolower($individual->sex()) ?> <?= $individual->isPendingAddition() ? 'wt-new' : '' ?> <?= $individual->isPendingDeletion() ? 'wt-old' : '' ?> overflow-hidden" data-wt-chart-xref="<?= e($individual->xref()) ?>" data-tree="<?= e($individual->tree()->name()) ?>">
diff --git a/resources/views/edit/edit-gedcom-fields.phtml b/resources/views/edit/edit-gedcom-fields.phtml
index b60669f315..cc5507cfd0 100644
--- a/resources/views/edit/edit-gedcom-fields.phtml
+++ b/resources/views/edit/edit-gedcom-fields.phtml
@@ -3,7 +3,6 @@
use Fisharebest\Webtrees\Elements\EmptyElement;
use Fisharebest\Webtrees\Registry;
use Fisharebest\Webtrees\Tree;
-use Ramsey\Uuid\Uuid;
/**
* @var string $gedcom
@@ -25,7 +24,7 @@ foreach ($keys as $num => $key) {
$hierarchy[$levels[$key]] = $tags[$key];
$full_tag = implode(':', array_slice($hierarchy, 0, 1 + $levels[$key]));
$elements[$key] = Registry::elementFactory()->make($full_tag);
- $ids[$key] = Uuid::uuid4()->toString() . '-' . $full_tag;
+ $ids[$key] = Registry::idFactory()->id() . '-' . $full_tag;
// Does this element have any children?
$has_subtags = ($levels[$key + 1] ?? 0) > $levels[$key];
diff --git a/resources/views/fact-gedcom-fields.phtml b/resources/views/fact-gedcom-fields.phtml
index 9e7041dec8..9e3c0e2fd9 100644
--- a/resources/views/fact-gedcom-fields.phtml
+++ b/resources/views/fact-gedcom-fields.phtml
@@ -8,7 +8,6 @@ use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Registry;
use Fisharebest\Webtrees\Source;
use Fisharebest\Webtrees\Tree;
-use Ramsey\Uuid\Uuid;
/**
* @var string $gedcom
@@ -54,7 +53,7 @@ foreach ($keys as $key) {
<?php if ($elements[0] instanceof XrefSource && preg_match('/^@(' . Gedcom::REGEX_XREF . ')@$/', $values[0], $match) === 1) : ?>
<?php $source = Registry::sourceFactory()->make($match[1], $tree) ?>
<?php if ($source instanceof Source) : ?>
- <?php $id = 'collapse-' . Uuid::uuid4()->toString() ?>
+ <?php $id = Registry::idFactory()->id() ?>
<?php $expanded = $tree->getPreference('EXPAND_SOURCES') === '1' ?>
<div class="fact_SOUR">
<a href="#<?= e($id) ?>" role="button" data-bs-toggle="collapse" aria-controls="<?= e($id) ?>" aria-expanded="<?= $expanded ? 'true' : 'false' ?>">
diff --git a/resources/views/lists/families-table.phtml b/resources/views/lists/families-table.phtml
index 23e8732050..2913a1122c 100644
--- a/resources/views/lists/families-table.phtml
+++ b/resources/views/lists/families-table.phtml
@@ -11,9 +11,8 @@ use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Tree;
use Fisharebest\Webtrees\View;
use Illuminate\Support\Collection;
-use Ramsey\Uuid\Uuid;
-$table_id = 'table-fam-' . Uuid::uuid4()->toString(); // lists requires a unique ID in case there are multiple lists per page
+$table_id = Registry::idFactory()->id(); // lists requires a unique ID in case there are multiple lists per page
$today = new Date(strtoupper(date('d M Y')));
$today_jd = Registry::timestampFactory()->now()->julianDay();
diff --git a/resources/views/lists/individuals-table.phtml b/resources/views/lists/individuals-table.phtml
index 2a1a371a04..0da8b51d5d 100644
--- a/resources/views/lists/individuals-table.phtml
+++ b/resources/views/lists/individuals-table.phtml
@@ -15,7 +15,6 @@ use Fisharebest\Webtrees\Services\ModuleService;
use Fisharebest\Webtrees\Tree;
use Fisharebest\Webtrees\View;
use Illuminate\Support\Collection;
-use Ramsey\Uuid\Uuid;
/**
* @var Collection<int,Individual> $individuals
@@ -24,7 +23,7 @@ use Ramsey\Uuid\Uuid;
*/
// lists requires a unique ID in case there are multiple lists per page
-$table_id = 'table-indi-' . Uuid::uuid4()->toString();
+$table_id = Registry::idFactory()->id();
$today_jd = Registry::timestampFactory()->now()->julianDay();
$hundred_years_ago = Registry::timestampFactory()->now()->subtractYears(100)->julianDay();