We often need to create a unique value to index something by - a unique filename, primary key in a database, user id, or url. The situations we need these in are varied; We might want to write to different temp files so our scripts don't interfere with each other. We might want to hand tickets out to users and make sure our tickets are can't be confused with one another no matter where the user got that ticket from. We might want to store rows in a table en mass without having to rely on an auto-incrementing key.
I've seen many schemes to create unique numbers. The simplest solution of starting with one and working your way up to two, then three, then four, and so on is effective but can be unreliable if you don't have one process doing the allocation (as you'll end up with a race condition where while program's counting then allocating a number, another program is doing the same and they both get the same number.) Sometimes it's impossible to have a central program to do the allocation (like with normally offline systems half way round the world) - and sometimes it's just too much hassle (who wants to write a service just to serve webpages?)
Data::UUID will give you a globally unique identifier without needing a central server. It'll give you a thirty six character string based on the time it's called - measured very, very accurately, and something that it can determine that is unique to your computer (like the mac address in your network card.) And it'll guarantee that at no other time will that string anywhere in the world be issued again.
Creating and using Data::UUID strings is simple.
use Data::UUID; my $uf = Data::UUID->new(); # creates a factory; print $uf->create_str(), "\n" for 1..10;
This (on and only on my laptop and only at this time and no other time) prints:
DA4BBCAA-47AF-11D9-B274-8E5F89426015 DA4C28A2-47AF-11D9-B274-8E5F89426015 DA4C5836-47AF-11D9-B274-8E5F89426015 DA4C8B8A-47AF-11D9-B274-8E5F89426015 DA4CB628-47AF-11D9-B274-8E5F89426015 DA4CDE32-47AF-11D9-B274-8E5F89426015 DA4D3972-47AF-11D9-B274-8E5F89426015 DA4D810C-47AF-11D9-B274-8E5F89426015 DA4DB096-47AF-11D9-B274-8E5F89426015 DA4DD990-47AF-11D9-B274-8E5F89426015
You'll note that quite a lot of the string is the same for each
instance. That's because for the most part a large part of the data
hasn't changed. Most of the time is still the same (it's just the
ticks and seconds that are changing) and the seed that's unique to the
machine doesn't change. If I run it again about an hour later we see
that the 47AF
in the second column has changed into a 47BA
as
a little time has passed, but the rest stays the same.
C604815E-47BA-11D9-B274-8E5F89426015 C604F2C4-47BA-11D9-B274-8E5F89426015 C6052460-47BA-11D9-B274-8E5F89426015 C60550F2-47BA-11D9-B274-8E5F89426015 C605776C-47BA-11D9-B274-8E5F89426015 C605A8D6-47BA-11D9-B274-8E5F89426015 C605D3B0-47BA-11D9-B274-8E5F89426015 C606006A-47BA-11D9-B274-8E5F89426015 C6062748-47BA-11D9-B274-8E5F89426015 C6064DE0-47BA-11D9-B274-8E5F89426015
If we run the same code on a separate computer quickly afterwards we notice that the start of the string is the same (apart from it's progressed on a slight time in the time it took us to change windows) but the end of the string is radically different.
CBEC90C0-47BA-11D9-9C9F-AE87831498F6 CBECAEA2-47BA-11D9-9C9F-AE87831498F6 CBECB8B6-47BA-11D9-9C9F-AE87831498F6 CBECC0CC-47BA-11D9-9C9F-AE87831498F6 CBECC810-47BA-11D9-9C9F-AE87831498F6 CBECD044-47BA-11D9-9C9F-AE87831498F6 CBECD756-47BA-11D9-9C9F-AE87831498F6 CBECDE72-47BA-11D9-9C9F-AE87831498F6 CBECE58E-47BA-11D9-9C9F-AE87831498F6 CBECECA0-47BA-11D9-9C9F-AE87831498F6
Imagine we have a CGI script that creates a table of data from some constantly changing source. In addition to displaying this data on the web we want to offer this data as an Excel file for download. The thing we need to remember is that this data keeps changing - so the link at the bottom of the page can't be a link to a separate CGI that goes and fetches the data source again, it has to be a link to a excel spreadsheet we create when we create the webpage.
In order to allow many people to use the website at the same time we need a unique filename for each excel document to prevent new users overwriting the excel sheets that were previously created. And this is where Data::UUID comes in.
#!/usr/bin/perl
# turn on perl's safety features use strict; use warnings;
# load the modules we need use HTML::Entities; use Data::UUID; use Spreadsheet::WriteExcel;
# get the data for now. This data is constantly changing # so the results will be different each time it's called. use Fake::Datasource; my @tables = Fake::Datasource->tables();
# create a unique filename my $filename = Data::UUID->new->create_str . ".xls";
We now need to create the HTML. We loop though the array of tables, and the array of rows contained within and through each value. At the end we print a link to the Excel file we're going to create.
print "<html><body>";
# each table... foreach my $table (@tables) { print '<table border="1">';
# ...has many rows which contain columns foreach my $row (@{ $table }) { print "<tr>"; foreach my $col (@{ $row }) { print "<td>".encode_entities($col)."</td>" } print "</tr>"; } print "</table>"; }
print qq{<a href="/files/$filename">Download as Excel</a>}; print "</body></html>";
Now all that's left to do is do the same thing to create the Excel file:
# create a new excel file my $workbook = Spreadsheet::WriteExcel->new("files/$filename");
# for each table add a sheet... foreach my $table (@tables) { my $sheet = $workbook->add_worksheet();
# ...and write each row in that table to the sheet my $row_index = 0; foreach my $row (@{ $table }) { $sheet->write_row($row_index++, 0, $row); } }
And we're done.