Make 50 to 80 or so characters, the limits for validity checking.
//
// RETURNS
// o On SUCCESS
// $record_key STRING
//
// o On FAILURE
// ARRAY( $error_message STRING )
// -------------------------------------------------------------------------
// =========================================================================
// Init.
// =========================================================================
$ns = __NAMESPACE__ ;
$fn = __FUNCTION__ ;
// =========================================================================
// GUID Part...
// =========================================================================
// -------------------------------------------------------------------------
// NOTE!
// =====
// MSDN defines GUID as "a 128-bit integer (16 bytes) that can be used
// across all computers and networks wherever a unique identifier is
// required. Such an identifier has a very low probability of being
// duplicated."
//
// GUID consists of alphanumeric characters only and is grouped in five
// groups separated by hyphens as seen in this example:
// 3f2504e0-4f89-11d3-9a0c-0305e82c3301
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// From:-
// http://www.php.net/manual/en/function.com-create-guid.php
// -------------------------------------------------------------------------
if ( function_exists( '\com_create_guid' ) === TRUE ) {
$guid_part = strtolower( trim( com_create_guid() , '{}' ) ) ;
} else {
$guid_part = strtolower( sprintf(
'%04X%04X-%04X-%04X-%04X-%04X%04X%04X' ,
mt_rand( 0 , 65535 ) ,
mt_rand( 0 , 65535 ) ,
mt_rand( 0 , 65535 ) ,
mt_rand( 16384 , 20479 ) ,
mt_rand( 32768 , 49151 ) ,
mt_rand( 0 , 65535 ) ,
mt_rand( 0 , 65535 ) ,
mt_rand( 0 , 65535 )
) ) ;
}
// =========================================================================
// MicroTime Part...
// =========================================================================
// -------------------------------------------------------------------------
// NOTE!
// =====
// By adding in the micro-time we guarantee a reasonable degree of
// uniqueness. Since microtime() is accurate to 1us (= 1 millionth of
// a second).
//
// But it is (at least theoretically,) possible for this function:-
// get_unique_record_key()
//
// to be called more than once in a given 1us period (particularly on
// very fast machines)
//
// ---
//
// Note that on a standard 2012 era desktop, the following code:-
//
// while ( TRUE ) {
// $gtod = gettimeofday() ;
// echo '
' , $gtod['sec'] , ' — ' , $gtod['usec'];
// }
//
// generates (eg):=-
//
// 1400040711 -- 999977
// 1400040711 -- 999981
// 1400040711 -- 999985
// 1400040711 -- 999988
// 1400040711 -- 999999
// 1400040712 -- 2
// 1400040712 -- 6
// 1400040712 -- 10
// 1400040712 -- 13
// 1400040712 -- 17
// 1400040712 -- 20
// ... --
// 1400040712 -- 91
// 1400040712 -- 95
// 1400040712 -- 98
// 1400040712 -- 102
// 1400040712 -- 106
// ... --
// 1400040712 -- 982
// 1400040712 -- 986
// 1400040712 -- 989
// 1400040712 -- 993
// 1400040712 -- 996
// 1400040712 -- 1000
// 1400040712 -- 1004
// 1400040712 -- 1007
// ...
//
// So in general (on standard desktops), two sequential calls to:-
// gettimeofday()
//
// will generate different micro-second precesion time values.
//
// But to guarantee that two sequential calls to:-
// get_unique_record_key()
//
// generate two different micro-second precision time values. we:-
//
// o Call "gettimeofday()" once, to get an initial value.
//
// o Then call "gettimeofday()" repetitively, until we get a
// different value.
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// mixed gettimeofday ([ bool $return_float = false ] )
// - - - - - - - - - - - - - - - - - - - - - - - - - -
// This is an interface to gettimeofday(2). It returns an associative array
// containing the data returned from the system call.
//
// return_float
// When set to TRUE, a float instead of an array is returned.
//
// By default an array is returned. If return_float is set, then a float is
// returned.
//
// Array keys:
//
// "sec" - seconds since the Unix Epoch
// "usec" - microseconds
// "minuteswest" - minutes west of Greenwich
// "dsttime" - type of dst correction
//
// (PHP 4, PHP 5)
//
// CHANGELOG
// Version Description
// 5.1.0 The return_float parameter was added.
//
// NOTE!
// =====
// The "microtime()" function has a note that says:-
// "This function is only available on operating systems that support
// the gettimeofday() system call."
//
// Does this note apply to the "gettimeofday()" function too ?
// -------------------------------------------------------------------------
if ( \function_exists( '\gettimeofday' ) ) {
// ----------------------------------------------------------------------
// Use the "gettimeofday()" function...
// ----------------------------------------------------------------------
$gtod = gettimeofday() ;
$initial_microtime_part = $gtod['sec'] . '-' . $gtod['usec'] ;
// ---------------------------------------------------------------------
while ( TRUE ) {
$gtod = gettimeofday() ;
$microtime_part = $gtod['sec'] . '-' . $gtod['usec'] ;
if ( $microtime_part !== $initial_microtime_part ) {
break ;
}
}
// ---------------------------------------------------------------------
} else {
// ---------------------------------------------------------------------
// NO "gettimeofday()" function...
// ---------------------------------------------------------------------
$initial_time = time() ;
// ---------------------------------------------------------------------
while ( TRUE ) {
$microtime_part = time() ;
if ( $microtime_part !== $initial_time ) {
break ;
}
}
// ---------------------------------------------------------------------
$microtime_part .= '-' . mt_rand( 0 , 999999 ) ;
// ---------------------------------------------------------------------
}
// =========================================================================
// Sequential Record Number Part...
// =========================================================================
// -------------------------------------------------------------------------
// get_option( $option, $default )
// - - - - - - - - - - - - - - - -
// A safe way of getting values for a named option from the options database
// table. If the desired option does not exist, or no value is associated
// with it, FALSE will be returned.
//
// $option
// (string) (required) Name of the option to retrieve. A concise
// list of valid options is below, but a more complete one can be
// found at the Option Reference. Matches $option_name in
// register_setting() for custom options.
//
// Default: None
//
// Underscores separate words, lowercase only - this is going to be
// in a database.
//
// $default
// (mixed) (optional) The default value to return if no value is
// returned (ie. the option is not in the database).
//
// Default: false
//
// RETURN VALUES
// (mixed)
// Current value for the specified option. If the specified option does
// not exist, returns boolean FALSE.
//
// CHANGELOG
// Since 1.5.0
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// update_option( $option, $new_value )
// - - - - - - - - - - - - - - - - - -
// Use the function update_option() to update a named option/value pair to
// the options database table. The $option (option name) value is escaped
// with $wpdb->prepare before the INSERT statement but not the option value,
// this value should always be properly sanitized.
//
// This function may be used in place of add_option, although it is not as
// flexible. update_option will check to see if the option already exists.
// If it does not, it will be added with add_option('option_name',
// 'option_value'). Unless you need to specify the optional arguments of
// add_option(), update_option() is a useful catch-all for both adding and
// updating options.
//
// Note: This function cannot be used to change whether an option is to
// be loaded (or not loaded) by wp_load_alloptions(). In that case,
// a delete_option() should be followed by use of the add_option()
// function.
//
// $option
// (string) (required) Name of the option to update. Must not
// exceed 64 characters. A list of valid default options to update
// can be found at the Option Reference.
//
// Default: None
//
// $newvalue
// (mixed) (required) The NEW value for this option name. This
// value can be an integer, string, array, or object.
//
// Default: None
//
// RETURN VALUE
// (boolean)
// True if option value has changed, false if not or if update failed.
//
// CHANGE LOG
// Since: 1.0.0
// -------------------------------------------------------------------------
$option_name = 'great_kiwi_dataset_manager_last_used_sequential_record_number' ;
// 61 characters (max. 64)
//echo '
' , strlen( $option_name ) ;
// -------------------------------------------------------------------------
$last_used_sequential_record_number = \get_option( $option_name ) ;
//echo '
WAS: ' , $last_used_sequential_record_number ;
// -------------------------------------------------------------------------
if ( $last_used_sequential_record_number === FALSE ) {
$last_used_sequential_record_number = 1 ;
} else {
if ( $last_used_sequential_record_number == PHP_INT_MAX ) {
$last_used_sequential_record_number = 1 ;
} else {
$last_used_sequential_record_number++ ;
}
}
//if ( $last_used_sequential_record_number === 8 ) {
// $last_used_sequential_record_number = PHP_INT_MAX - 2 ;
//}
//echo '
NOW: ' , $last_used_sequential_record_number ;
// -------------------------------------------------------------------------
$ok = \update_option( $option_name , $last_used_sequential_record_number ) ;
// -------------------------------------------------------------------------
if ( $ok !== TRUE ) {
$msg = <<
' , $candidate_record_key ;
// -------------------------------------------------------------------------
if ( ! \is_string( $candidate_record_key ) ) {
return FALSE ;
}
// -------------------------------------------------------------------------
if ( strlen( $candidate_record_key ) === 13
&&
\ctype_alnum( $candidate_record_key )
) {
return TRUE ;
// Old style record key created with "uniqid()"
}
// -------------------------------------------------------------------------
// New style record keys (from May 2014), are like (eg):-
//
// 1 2 3 4 5
// 123456789012345678901234567890123456789012345678901
// 3f2504e0-4f89-11d3-9a0c-0305e82c3301-1400040711-0-1
//
// 1 2 3 4 5 6
// 12345678901234567890123456789012345678901234567890123456789012345
// 3f2504e0-4f89-11d3-9a0c-0305e82c3301-1400040711-999977-2147483647
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^
// GUID PART MICROTIME PART SEQUENTIAL
// RECORD NO.
// PART
//
// So it's 51 to 65 characters long. And if PHP_INT_MAX (for the
// "sequential record number" part), were to increase, it could be even
// longer.
//
// => Make 50 to 80 or so characters, the limits for validity checking.
// -------------------------------------------------------------------------
// NOTE! The special regular expression characters are:
// . \ + * ? [ ^ ] $ ( ) { } = ! < > | : -
$pattern =
'/^[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}-\d{10}-\d{1,6}-\d{1,10}$/'
;
// -------------------------------------------------------------------------
$number_matches = \preg_match(
$pattern ,
$candidate_record_key
) ;
// preg_match() returns 1 if the pattern matches
// given subject, 0 if it does not, or FALSE if an
// error occurred.
// -------------------------------------------------------------------------
if ( $number_matches === FALSE ) {
$ns = __NAMESPACE__ ;
$fn = __FUNCTION__ ;
$msg = <<