<?php

/*
   ###########################################################################
   RANDOM NAMES TABLE GENERATOR - WITH 30-DAY COOKIE

   AUTHOR   : Jay Tanner - 2025
   LANGUAGE : PHP v8.2.12
   LICENSE  : Public Domain

   This program generates a listing of up to 100 randomized names per list.

   The list can be all male names, all female names or a mixture of both.

   The source names data is derived from the 2010 United States census data
   of names sorted downward according to decreasing frequency, the most
   common names occuring at the top of the list and the rarely used names
   at the bottom of the list.

  ###########################################################################
*/

   
ob_start(); // Initialize output buffer.

   
$cYear date('Y'); // Current year.

   
$xGenderMFR '';

// ---------------------------------------------------------------
// Define the program cookie name and set it to expire in 30 days.

   
$CookieNameString 'Random-Name-Table-Generator';
   
$SetToExpireIn30Days time() + 30*86400;


// ---------------------------------
// Define PHP program and HTML info.

   
$_AUTHOR_           "Jay Tanner - $cYear";
   
$_PROGRAM_VERSION_  'v2.0 - '$at "&#97;&#116;&#32;&#76;&#111;&#99;&#97;&#108;&#32;&#84;&#105;&#109;&#101;&#32;"$LTC "&#85;&#84;&#67;";
   
$_SCRIPT_FILE_PATH_ Filter_Input(INPUT_SERVER'SCRIPT_FILENAME');
   
$_REVISION_DATE_    $_PROGRAM_VERSION_ .'Revised: 'date("Y-F-d-l $at h:i:s A   ($LTC"FileMTime($_SCRIPT_FILE_PATH_))."&minus;05:00)";
   
$_BROWSER_TAB_TEXT_ "Random Names Table Generator";
   
$_INTERFACE_TITLE_  "<span style='font-size:14.5pt;'>Random Names Table Generator</span><br><br><span style='font-size:10pt;'>PHP Program by Jay Tanner - $cYear</span>";


// -------------------------------------
// Define main TextArea text and background
// colors and HTML table row span. If an
// error is reported, then these colors
// will change internally to red/white.

   
$TxColor 'black';
   
$BgColor 'white';

// ----------------------------------------
// Count ALL names in source data listings.

   
Count_All_Names();

// ---------------------------------------------
// Do this only if [SUBMIT] button was clicked.

   
$w Filter_Input(INPUT_POST'SubmitButton');

   if (!IsSet(
$w))
  {

/* ----------------------------------------------------------------------
   If this program is being called externally, rather than being executed
   by clicking the [SUBMIT] button, and an active cookie also exists,
   then restore the previously saved interface settings from it. If
   the user leaves and comes back later, all the interface settings
   will be remembered and restored if the cookie was not deleted.
*/
   
$w Filter_Input(INPUT_COOKIE$CookieNameString);

   if (IsSet(
$w))
      {
       
$CookieDataString Filter_Input(INPUT_COOKIE$CookieNameString);
       list(
$GenderMFR,$ListSize,$TopFirst,$TopMiddle$TopLast) = Preg_Split("[\|]"$CookieDataString);
      }

   else

// -----------------------------------------------------------
// If there is no previous cookie with the interface settings,
// then set the initial default interface startup values and
// store them in a new cookie.

 
{
  
$GenderMFR  'M';
  
$ListSize  '10';
  
$TopFirst  '250';
  
$TopMiddle '250';
  
$TopLast   '500';

// -------------------------------------------
// Store current interface settings in cookie.

   
$CookieDataString "$GenderMFR|$ListSize|$TopFirst|$TopMiddle|$TopLast";
   
SetCookie ($CookieNameString$CookieDataString$SetToExpireIn30Days);
  } 
// End of  else {...}

  
// End of  if (!isset(_POST['SubmitButton']))


// ------------------------------------------
// Read values of all interface arguments and
// set any empty arguments to default values.

   
$w Filter_Input(INPUT_POST'SubmitButton');

   if (isset(
$w))
{
   
$GenderMFR  trim(Filter_Input(INPUT_POST'GenderMFR'));
   
$GenderMFR  StrToUpper(substr($GenderMFR,0,1));

   
$ListSize  trim(Filter_Input(INPUT_POST'ListSize'));
   
$TopFirst  trim(Filter_Input(INPUT_POST'TopFirst'));
   
$TopMiddle trim(Filter_Input(INPUT_POST'TopMiddle'));
   
$TopLast   trim(Filter_Input(INPUT_POST'TopLast'));

// ---------------------
// Set default value(s).

   
if ($GenderMFR  == '') {$GenderMFR  'M';}
   if (
$ListSize  == '') {$ListSize  '10';}
   if (
$TopFirst  == '') {$TopFirst  '250';}
   if (
$TopMiddle == '') {$TopMiddle '250';}
   if (
$TopLast   == '') {$TopLast   '500';}

// -------------------------------------
// Store interface argument in a cookie.

   
$CookieDataString "$GenderMFR|$ListSize|$TopFirst|$TopMiddle|$TopLast";
   
SetCookie ($CookieNameString$CookieDataString$SetToExpireIn30Days);
}

   if (
$GenderMFR == 'M')
      {
$FirstNamesCount $MaleNamesCount;}
   else
     {
$FirstNamesCount $FemaleNamesCount;}

   
$GenderMFRText = ($GenderMFR == 'F')? 'Female':'Male';
   
$ns = ($ListSize <> 1)? 's':'';

// ----------------------------------------------
// OPTIONALLY CHECK ARGUMENT VALUES FOR VALIDITY.
// IF ERROR, SET ERROR FLAG AND MESSAGE VALUES.

   
$ErrFlag FALSE;
   
$ErrMssg '';


   if (
$TopLast $LastNamesCount)
   {
    
$ErrFlag TRUE;
    
$ErrMssg "Invalid top last name limit:\n'$TopLast'\n\nThe top limit is $LastNamesCount.";
   }


   if (
$TopMiddle $FirstNamesCount)
   {
    
$ErrFlag TRUE;
    
$ErrMssg "Invalid top middle name limit:\n'$TopMiddle'\n\nThe top limit is $FirstNamesCount for $GenderMFRText names.";
   }



   if (
$TopFirst $FirstNamesCount)
   {
    
$ErrFlag TRUE;
    
$ErrMssg "Invalid top first name limit:\n'$TopFirst'\n\nThe top limit is $FirstNamesCount for $GenderMFRText names.";
   }


   if (
$ListSize 100)
   {
    
$ErrFlag TRUE;
    
$ErrMssg "Invalid list size:\n'$ListSize'\n\nList size limit must be in the range from 1 to 100.";
   }



   if (
$GenderMFR <> 'F' and $GenderMFR <> 'M' and $GenderMFR <> 'R')
   {
    
$ErrFlag TRUE;
    
$ErrMssg "Invalid gender symbol specified:\n'$GenderMFR'\n\nUse: 'M' For all Male names \n     'F' For all Female names \n     'R' For Randomly mixed Male/Female names \n\nNOT CASE-SENSITIVE";
   }



// *******************************************************************
// *******************************************************************

// -----------------------------
// Set initial uniform width for
// tables alignment in pixels.

   
$TableWidth '780';


// ******************************************
// ******************************************
// If error was reported (TRUE), then display
// the error message on a red background.

   
if ($ErrFlag === TRUE)
  {
   
$TxColor 'white';
   
$BgColor '#CC0000';
   
$TextArea2Text '';

   
$TextArea1Text =
"=== ERROR ===

$ErrMssg";
  }

else


  {
// *********************************************************
// BEGIN MAIN COMPUTATIONS HERE IF NO ERRORS DETECTED ABOVE.
// *********************************************************

// --------------------------------------------------------
// Generate the listing of randomized male or female names.
// It can be a single name or a list of multiple names.

   
if ($GenderMFR == 'M')
      {
$X Random_Male_Names   ($ListSize,$TopFirst,$TopMiddle,$TopLast);}

   if (
$GenderMFR == 'F')
      {
$X Random_Female_Names ($ListSize,$TopFirst,$TopMiddle,$TopLast);}

   if (
$GenderMFR == 'R')
      {
$X Random_Gender_Names ($ListSize,$TopFirst,$TopMiddle,$TopLast);}

   
$TextArea1Text $X;
  }


// ****************************
// Define TextArea2 text block.

   
$TextArea2Text =
"The names are randomly constructed from 2010 U.S.A. census data consisting
of 
$MaleNamesCount male names, $FemaleNamesCount female names and $LastNamesCount last names in order of
frequency.

If you need a list of random names to test a program or are a writer who is
looking for ideas for names of characters in a story, this program may come
in handy for randomly generating test data or character name ideas.

To increase diversity of the listing to include more foreign-sounding names,
simply raise the size of the tops of the corresponding name category.  This
will increase the occurrence of the more rarely used names in the listing,
which occur closer to the bottom of the names frequencies data list.

Gender Setting:
M = Males Names List
F = Female Names List
R = Random M/F List

-----------------------------------------
The initial default program settings are:

M   = Generate male names
10  = List Size = How many names to include in the list.  (Limit = 100)
250 = Select from top 250 most frequent male first names. (Limit = 
$MaleNamesCount)
250 = Select from top 250 most frequent middle names.     (Limit = 
$MaleNamesCount)
500 = Select from top 500 most frequent last names.       (Limit = 
$LastNamesCount)

"
;


if (
$GenderMFR == 'M') {$xGenderMFR 'Male';}
if (
$GenderMFR == 'F') {$xGenderMFR 'Female';}
if (
$GenderMFR == 'R') {$xGenderMFR 'Male / Female';}

/* **************************************************************************
   Determine number of text columns and rows to use in the output text areas.
   These values vary randomly according to the text block width and length.
   The idea is to eliminate the need for scroll-bars within the text areas
   or worry as much about the variable dimensions of a text display area.
*/

// --------------------------------------------
// Text Area 1 - Default = At least 80 columns.

   
$Text1Cols Max(Array_Map('StrLen'PReg_Split("[\n]"trim($TextArea1Text))));
   if (
$Text1Cols 80) {$Text1Cols 80;}  // Default
   
$Text1Rows Substr_Count($TextArea1Text"\n");

// --------------------------------------------
// Text Area 2 - Default = At least 80 columns.

   
$Text2Cols Max(Array_Map('StrLen'PReg_Split("[\n]"trim($TextArea2Text))));
   if (
$Text2Cols 80) {$Text2Cols 80;} // Default
   
$Text2Rows Substr_Count($TextArea2Text"\n");



// ******************************************
// ******************************************
// GENERATE CLIENT WEB PAGE TO DISPLAY OUTPUT

   
print <<< _HTML

<!DOCTYPE HTML>
<HTML>

<head>
<title>
$_BROWSER_TAB_TEXT_</title>

<meta name='viewport' content='width=device-width, initial-scale=0.8'>

<meta http-equiv='content-type' content='text/html; charset=UTF-8'>
<meta http-equiv='pragma'  content='no-cache'>
<meta http-equiv='expires' content='-1'>
<meta name='description' content='Random Names Table Generator'>
<meta name='keywords' content='random names, random'>
<meta name='author' content='Jay Tanner - https://www.NeoProgrammics.com'>
<meta name='robots' content='index,follow'>
<meta name='googlebot' content='index,follow'>

<style>

 BODY {color:white; background:black; font-family:Verdana; font-size:12pt; line-height:125%;}

 TABLE
{font-size:13pt; border: 1px solid black;}


 TD
{
 color:black; background:white; line-height:150%; font-size:10pt;
 padding:6px; text-align:center;
}


 UL
{font-family:Verdana; font-size:12pt; line-height:150%; text-align:justify;}


 PRE
{
 background:white; color:black; font-family:monospace; font-size:12.5pt;
 font-weight:bold; text-align:left; line-height:125%; padding:6px;
 border:2px solid black; border-radius:8px;
 page-break-before:page;
}


 DIV
{
 background:white; color:black; font-family:Verdana; font-size:11pt;
 font-weight:normal; line-height:125%; padding:6px;
}


 TEXTAREA
{
 background:white; color:black; font-family:monospace; font-size:13pt;
 font-weight:bold; padding:4pt; white-space:pre; border-radius:8px;
 line-height:125%;
}


 INPUT[type='text']::-ms-clear {width:0; height:0;}

 INPUT[type='text']
{
 font-family:monospace; color:black; background:white; font-size:13pt;
 font-weight:bold; text-align:center; box-shadow:2px 2px 3px #666666;
 border:2px solid black; border-radius:4px;
}
 INPUT[type='text']:focus
{
 font-family:monospace; background:white; box-shadow:2px 2px 3px #666666;
 font-size:13pt; border:2px solid blue; text-align:center; font-weight:bold;
 border-radius:4px;
}



 INPUT[type='submit']
{
 background:black; color:cyan; font-family:Verdana; font-size:10pt;
 font-weight:bold; border-radius:4px; border:4px solid #777777;
 padding:3pt;
}
 INPUT[type='submit']:hover
{
 background:black; color:white; font-family:Verdana; font-size:10pt;
 font-weight:bold; border-radius:4px; border:4px solid red;
 padding:3pt;
}





// Link states MUST be set in the following order:
// :link, :visited, :hover, :active

 A:link
{
 font-size:10pt; background:transparent; color:#8080FF; border-radius:4px;
 font-family:Verdana; font-weight:bold; text-decoration:none;
 line-height:175%; padding:3px; border:1px solid transparent;
}
 A:visited
{
 font-size:10pt; background:transparent; color:DarkCyan; border-radius:4px;
}
 A:hover
{
 font-size:10pt; background:yellow; color:black; border:1px solid black;
 box-shadow:1px 1px 3px #222222; border-radius:4px;
}
 A:active
{
 font-size:10pt; background:yellow; color:black; border-radius:4px;
}


 HR {background:red; height:4px; border:0px;}


[title-text]:hover:after
{
 opacity:1.0;
 transition:all 1.0s ease 1.0s;
 text-align:left;
 visibility:visible;
}

[title-text]:after
{
 opacity:1.0;
 content:attr(title-text);
 text-align:left;
 left:50%;
 background-color:yellow;
 color:black;
 font-size:10pt;
 position:absolute;
 padding:1px 5px 2px 5px;
 white-space:pre;
 border:1px solid red;
 z-index:1;
 visibility:hidden;
}

[title-text] {position: relative;}


::selection{background-color:yellow !important; color:black !important;}
::-moz-selection{background-color:yellow !important; color:black !important;}
</style>

</head>

<body>

<!-- Define container form --->
<form name="form1" method="post" action="">

<!-- Define main page title/header. --->
<table width="
$TableWidth" align="center" border="0" cellspacing="1" cellpadding="3">


<tr><td colspan="99" style="color:white; background-color:#000066; border:2px solid white; border-radius:8px 8px 0px 0px;">
$_INTERFACE_TITLE_</td></tr>
</table>


<!-- Define input (GenderMFR) text box  --->
<table width="
$TableWidth" align="center" border="0" cellspacing="1" cellpadding="3">
<tr>
<td style="line-height:175%;" width='20%' title=' M = Male Names \n F  = Female Names \n R  = Random M/F Mix '>Select&nbsp;Names&nbsp;Gender<br><input name="GenderMFR"  type="text" value="
$GenderMFR"  size="2" maxlength="1"><br>M / F / R</td>

<td style="line-height:175%;" width='20%'>Listing Size<br><input name="ListSize"  type="text" value="
$ListSize"  size="4" maxlength="3"><br>Up to 100 Names</td>

<td style="line-height:175%;" width='20%' title=" Choose from up to 
$FirstNamesCount first names." >Select From the Top<br><input name="TopFirst"  type="text" value="$TopFirst"  size="5" maxlength="4"><br>of&nbsp;$FirstNamesCount&nbsp;First&nbsp;Names</td>

<td style="line-height:175%;" width='20%' title=' Choose from up to 
$FirstNamesCount middle names. '>Select From the Top<br><input name="TopMiddle"  type="text" value="$TopMiddle"  size="5" maxlength="4"><br>of&nbsp;$FirstNamesCount&nbsp;Middle&nbsp;Names</td>

<td style="line-height:175%;" width='20%' title=' Choose from up to 
$LastNamesCount last names. '>Select From the Top<br><input name="TopLast"  type="text" value="$TopLast"  size="7" maxlength="6"><br>of&nbsp;$LastNamesCount&nbsp;Last&nbsp;Names</td>

</tr>
</table>



<!-- Define [SUBMIT] button --->
<table width="
$TableWidth" align="center" border="0" cellspacing="1" cellpadding="3">
<tr><td colspan="99" style="background-color:black;"><input type="submit" name="SubmitButton" value=" S U B M I T "></td></tr>

<tr>
<td colspan='3' style='background:transparent; color:black; font-size:10pt;
                       text-align:center;'>
                       &nbsp;
<a href='View-Source-Code.php' target='_blank'
   style='font-family:Verdana; color:black; background:yellow;
         text-decoration:none; border:1px solid black; padding:4px;
         border-radius:4px;'>
         &nbsp;<span style='font-weight:normal;'>View/Copy PHP Source Code</span>&nbsp;
</a>
&nbsp;
<a href='Random-Names-Table-Generator.7z' target='_blank'
   style='font-family:Verdana; color:black; background:yellow;
         text-decoration:none; border:1px solid black; padding:4px;
         border-radius:4px;'>&nbsp;
         <span style='font-weight:normal;'>Download Program and Data &nbsp;</span>&nbsp;
</a>
<br>
</td>
</tr>
</table>



<!-- Define TextArea1 --->
<table width="
$TableWidth" align="center" border="0" cellspacing="1" cellpadding="3">
<tr>
<td colspan="99" style="text-align:center; color:white; background-color:black;"><br>Below is a Listing of 
$ListSize Randomly Generated $xGenderMFR Name$ns.<br><span style='color:GreenYellow;'>Double-Click Within the Text Area to Select/Copy the Full List</span><br>
<textarea ID="TextArea1" name="TextArea1" style="color:
$TxColor; background:$BgColor; padding:6px; border:2px solid white;" cols="$Text1Cols" rows="$Text1Rows" ReadOnly OnDblClick="this.select();" OnMouseUp="return true;">
$TextArea1Text
</textarea>
</td>
</tr>
</table>



<!-- Define TextArea2 --->
<table width="
$TableWidth" align="center" border="0" cellspacing="1" cellpadding="3">
<tr>
<td colspan="99" style="text-align:center; color:GreenYellow; background:black;">Double-Click Within Text Area to Select ALL Text<br>
<textarea ID="TextArea2" name="TextArea2" style="color:black; background:white; padding:6px;" cols="
$Text2Cols" rows="$Text2Rows" ReadOnly OnDblClick="this.select();" OnMouseUp="return true;">
$TextArea2Text
</textarea>
</tr>
</table>


<!-- Define page footer --->
<table width="
$TableWidth" align="center" border="0" cellspacing="1" cellpadding="3">
<tr>
<td colspan="99" style="color:GreenYellow; background:black;">PHP Program by 
$_AUTHOR_<br><span style="color:silver; background:black;">$_REVISION_DATE_</span></td>
</tr>
</table>

</form>
<!-- End of container form --->


<!-- Extra bottom scroll space --->
<br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br>

</body>
</HTML>



_HTML;







/*
   ###########################################################################
   This function returns a complete random male name string.
   ###########################################################################
*/
   
function Random_Male_Names ($N=1$TopF=3999$TopM=3999$TopL=162253)
{
   
$N    trim($N);
   
$TopF trim($TopF);
   
$TopM trim($TopM);
   
$TopL trim($TopL);

   
$NamesList '';

   for (
$i=0;   $i $N;   $i++)
  {
   
$FirstName Random_Male_First_Name ($TopF);

   
$Middle Random_Male_First_Name($TopM);
             if (
MT_Rand() % == 0) {$Middle substr($Middle,0,1).'. ';}
             if (
MT_Rand() % == 0) {$Middle '';}

   
$LastName Random_Surname($TopL);

   
$RandomMaleNameStr Str_Replace('  '' '"$FirstName $Middle $LastName");
   
$NamesList .= "$RandomMaleNameStr\n";
  }
   return 
trim($NamesList);

// End of  Random_Male_Names (...)







/*
   ###########################################################################
   This function returns a complete random female name string.
   ###########################################################################
*/
   
function Random_Female_Names ($N=1$TopF=4000$TopM=4000$TopL=162253)
{
   
$N    trim($N);
   
$TopF trim($TopF);
   
$TopM trim($TopM);
   
$TopL trim($TopL);

   
$NamesList '';

   for (
$i=0;   $i $N;   $i++)
  {
   
$FirstName Random_Female_First_Name($TopF);

   
$Middle Random_Female_First_Name($TopM);
             if (
MT_Rand() % == 0) {$Middle substr($Middle,0,1).'. ';}
             if (
MT_Rand() % == 0) {$Middle '';}

   
$LastName Random_Surname($TopL);

   
$RandomFemaleNameStr Str_Replace('  '' '"$FirstName $Middle $LastName");
   
$NamesList .= "$RandomFemaleNameStr\n";
  }
   return 
trim($NamesList);

// End of  Random_Female_Names (...)








/*
   This function generates a randomized mixed male/female names.
*/

   
function Random_Gender_Names ($N=1$TopF=4000$TopM=4000$TopL=162253)
{
   
$N trim($N);
   
$TopF trim($TopF);
   
$TopM trim($TopM);
   
$TopL trim($TopL);

   
$NamesList '';


   for (
$i=0;   $i $N;   $i++)
  {
   if (
MT_Rand() % == 0)
      {
$X Random_Male_Names   (1,$TopF,$TopM,$TopL);}
   else
      {
$X Random_Female_Names (1,$TopF,$TopM,$TopL);}

   
$NamesList .= "$X\n";
  }
   return 
trim($NamesList);

}


















/*
   ###########################################################################
   This function returns a single random male name from the full list.
   ###########################################################################
*/

   
function Random_Male_First_Name($TopN=3999)
{
   
$N trim($TopN);  if ($N 3999) {$N 3999;}

   
$FileText trim(File_Get_Contents('data/male-first-names.txt'));

   
$wArray PReg_Split("[\n]"$FileText);
   
$wCount count($wArray);

   
$RandomFirstNameText trim($wArray[Random_Int(0$N-1)]);

   unset (
$wArray);
   return 
$RandomFirstNameText;
}





/*
   ###########################################################################
   This function returns a single random female first name from the full list.
   ###########################################################################
*/

   
function Random_Female_First_Name($TopN=3997)
{
   
$N trim($TopN);  if ($N 3997) {$N 3997;}

   
$FileText trim(File_Get_Contents('data/female-first-names.txt'));

   
$wArray PReg_Split("[\n]"$FileText);
   
$wCount count($wArray);

   
$RandomFirstNameText trim($wArray[Random_Int(0$N-1)]);

   unset (
$wArray);
   return 
$RandomFirstNameText;
}




/*
   This function returns a single random surname from the full list.
*/

   
function Random_Surname ($TopN=162253)
{
   
$N trim($TopN);

   
$FileText trim(File_Get_Contents('data/last-names.txt'));

   
$wArray PReg_Split("[\n]"$FileText);
   
$wCount count($wArray);

   
$RandomSurnameText trim($wArray[Random_Int(0$N-1)]);

   unset (
$wArray);
   return 
$RandomSurnameText;
}





// Count names in all work files.

   
function Count_All_Names()
{
   GLOBAL 
$MaleNamesCount;
   GLOBAL 
$FemaleNamesCount;
   GLOBAL 
$LastNamesCount;

   
$MaleNamesCount   Substr_Count(trim(File_Get_Contents('data/male-first-names.txt')), "\n");
   
$FemaleNamesCount Substr_Count(trim(File_Get_Contents('data/female-first-names.txt')), "\n");
   
$LastNamesCount   Substr_Count(trim(File_Get_Contents('data/last-names.txt')), "\n");

   return 
"$MaleNamesCount FemaleNamesCount LastNamesCount";
}






// END OF PROGRAM



?>