From 9f24ab972331db1806232dc3968d3c7301861a7b Mon Sep 17 00:00:00 2001 From: David Cook Date: Wed, 28 Aug 2024 03:49:17 +0000 Subject: [PATCH] Bug 37675: Ensure unique random number server-side This change ensures that a unique number is used for the random numbers used in the MARC basic editor. Note that there is a chance for a near infinite loop for records with a large number of records. This could be improved by dynamically increasing the random number max and throwing a fatal error if too much time is spent generating numbers. Or we could calculate how many numbers we need ahead of time, and use those. Note that the Javascript used for creating random numbers does not have knowledge of the already used set of numbers currently. This should be improved as well. --- Koha/UI/Form/Builder/Biblio.pm | 12 +++++++++++- cataloguing/addbiblio.pl | 16 +++++++++++++--- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/Koha/UI/Form/Builder/Biblio.pm b/Koha/UI/Form/Builder/Biblio.pm index c17d4965e4..72d7db99dc 100644 --- a/Koha/UI/Form/Builder/Biblio.pm +++ b/Koha/UI/Form/Builder/Biblio.pm @@ -51,6 +51,7 @@ sub new { my $self = {}; $self->{biblionumber} = $params->{biblionumber} =~ s/\D//gr; + $self->{unique_keys} = {}; # just in case biblionumber obtained from CGI and passed directly here contains weird characters like spaces bless $self, $class; @@ -383,7 +384,16 @@ sub build_authorized_values_list { =cut sub create_key { - return int(rand(1000000)); + my ($self) = @_; + my $unique_keys = $self->{unique_keys}; + my $max_num = 10000000; + #TODO: Note this could lead to a near infinite loop + while (my $value = int(rand($max_num)) ){ + if ( ! $unique_keys->{$value} ){ + $unique_keys->{$value} = 1; + return $value; + } + } } 1; diff --git a/cataloguing/addbiblio.pl b/cataloguing/addbiblio.pl index 1b973b660e..626c3cb4c4 100755 --- a/cataloguing/addbiblio.pl +++ b/cataloguing/addbiblio.pl @@ -183,7 +183,15 @@ sub MARCfindbreeding { =cut sub CreateKey { - return int(rand(10000000)); + my ($unique_keys) = @_; + my $max_num = 10000000; + #TODO: Note this could lead to a near infinite loop + while (my $value = int(rand($max_num)) ){ + if ( ! $unique_keys->{$value} ){ + $unique_keys->{$value} = 1; + return $value; + } + } } =head2 GetMandatoryFieldZ3950 @@ -228,6 +236,8 @@ sub format_indicator { sub build_tabs { my ( $template, $record, $dbh, $encoding,$input ) = @_; + my $unique_keys = {}; + # fill arrays my @loop_data = (); my $tag; @@ -279,7 +289,7 @@ sub build_tabs { $i++; next if ! $tag; my ($indicator1, $indicator2); - my $index_tag = CreateKey; + my $index_tag = CreateKey($unique_keys); # if MARC::Record is not empty =>use it as master loop, then add missing subfields that should be in the tab. # if MARC::Record is empty => use tab as master loop. @@ -409,7 +419,7 @@ sub build_tabs { important => $tagslib->{$tag}->{important}, subfield_loop => \@subfields_data, fixedfield => $tag < 10?1:0, - random => CreateKey, + random => CreateKey($unique_keys), ); if ($tag >= 10){ # no indicator for 00x tags $tag_data{indicator1} = format_indicator($field->indicator(1)), -- 2.39.2