new PersonInfo('dag', 'password1', 1), 'Sally Goodson' => new PersonInfo('sag', 'pwtwo', 1), 'Ted Dawson' => new PersonInfo('twd', 'password3', 2), 'Nelly Dawson' => new PersonInfo('nd', 'pwfour', 2), 'Phil Dodger' => new PersonInfo('pbd', 'password5', 3), 'Tina Dodger' => new PersonInfo('tod', 'pwsix', 3) ); class PersonInfo { public $initials = ''; public $md5 = ''; public $password = ''; public $family_id = ''; public $family_md5 = ''; public function __construct($initials, $password, $family_id) { $this->initials = $initials; $this->password = $password; $this->family_id = $family_id; $this->md5 = md5("{$initials}_{$family_id}"); $this->family_md5 = md5(get_class($this) . "_{$family_id}"); } } function get_results($persons_array_in, $selections, $is_md5s) { $results = array(); $md5_arr = array(); $fam_md5_arr = array(); $name_to_md5 = array(); foreach ($persons_array_in as $person_name => $person_obj) { $md5_arr[] = $person_obj->md5; $fam_md5_arr[] = $person_obj->family_md5; $name_to_md5[$person_obj->md5] = $person_name; } sort($md5_arr); $fam_md5_arr = array_unique($fam_md5_arr); sort($fam_md5_arr); $md5_map = array_flip($md5_arr); $fam_md5_map = array_flip($fam_md5_arr); if ($is_md5s) { $tmp = array(); foreach ($selections as $key_md5 => $val_md5) { $tmp[$name_to_md5[$key_md5]] = $name_to_md5[$val_md5]; } $selections = $tmp; } static $family_ids = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; foreach ($selections as $giver_name => $recipient_name) { $giver = $persons_array_in[$giver_name]; $recipient = $persons_array_in[$recipient_name]; $giver_num = $md5_map[$giver->md5] + 1; $recipient_num = $md5_map[$recipient->md5] + 1; $giver_fam = $fam_md5_map[$giver->family_md5]; $recipient_fam = $fam_md5_map[$recipient->family_md5]; if ($giver_fam < strlen($family_ids)) { $giver_fam = $family_ids[$fam_md5_map[$giver->family_md5]]; } if ($recipient_fam < strlen($family_ids)) { $recipient_fam = $family_ids[$fam_md5_map[$recipient->family_md5]]; } $results[] = "Person #{$giver_num} in family {$giver_fam} is giving to " . "person #{$recipient_num} in family {$recipient_fam}."; } sort($results); return $results; } function make_picks_file($persons_array_in, $datafile, &$errors, &$successes, &$debug) { if (!is_array($errors)) { return FALSE; } if (!is_array($successes)) { $errors[] = 'Unexpected successes array.'; return FALSE; } if (!is_array($persons_array_in)) { $errors[] = 'Unexpected persons array.'; return FALSE; } if (!is_string($datafile)) { $errors[] = 'Invalid output data file name.'; return FALSE; } if (!is_null($debug)) { if (!is_array($debug)) { $debug = array(); } } $selections_with_lowest_interfamily_giving = NULL; $num_people_interfamily_giving = NULL; global $max_ideal_results_attempts; for ($cnt = 0; $cnt < $max_ideal_results_attempts; $cnt++) { $selections = array(); $persons_array = $persons_array_in; $persons_names = array_keys($persons_array); $num_left_in_family = 0; foreach ($persons_names as $current_person) { $pick_is_ok = FALSE; while (!$pick_is_ok) { $persons_remaining = array_keys($persons_array); $random_choice = 0; if (count($persons_remaining) > 0) { $random_choice = rand(0, count($persons_remaining) - 1); } $person_picked = $persons_remaining[$random_choice]; $current_person_obj = $persons_array_in[$current_person]; $picked_person_obj = $persons_array_in[$person_picked]; if ($current_person_obj->family_id == $picked_person_obj->family_id) { $do_try_again = FALSE; // If there is only one selection left, and that person is the selector, then // go ahead and do it -- but show an error (this should never really happen) if ( (count($persons_remaining) == 1) && ($current_person_obj->md5 == $picked_person_obj->md5) ) { $errors[] = 'Data warning: One person is giving to themselves!'; } // If the selector is the same person as the one selected, and there is more // people to choose from, try again else if ($current_person_obj->md5 == $picked_person_obj->md5) { $do_try_again = TRUE; continue; } // See if everyone who is left in persons_remaining are in the same family, if // so, let this go as long as they current person and the picked person aren't // the same person. foreach ($persons_remaining as $person_remaining_item) { $person_remaining_item_obj = $persons_array_in[$person_remaining_item]; if ($person_remaining_item_obj->family_id == $current_person_obj->family_id) { $num_left_in_family++; } else { $num_left_in_family = 0; $do_try_again = TRUE; break; } } if ($do_try_again) { continue; } } $selections[$current_person] = $person_picked; unset($persons_array[$person_picked]); $pick_is_ok = TRUE; } } if (!is_null($debug)) { $debug[] = "Attempt {$cnt} resulted in {$num_left_in_family} persons interfamily giving."; } if ( (is_null($num_people_interfamily_giving)) || ($num_left_in_family < $num_people_interfamily_giving) ) { $num_people_interfamily_giving = $num_left_in_family; $selections_with_lowest_interfamily_giving = $selections; } if ($num_left_in_family == 0) { break; } } assert(is_array($selections_with_lowest_interfamily_giving)); assert(is_int($num_people_interfamily_giving)); $selections = $selections_with_lowest_interfamily_giving; $num_left_in_family = $num_people_interfamily_giving; if ($num_left_in_family > 0) { // If some selections had to be made in the same family, show an error about it $errors[] = "Data warning: {$num_left_in_family} people in the same family are " . ' giving to another in the same family.'; } $selections_for_file = array(); foreach ($selections as $giver_name => $recipient_name) { $giver = $persons_array_in[$giver_name]; $recipient = $persons_array_in[$recipient_name]; $selections_for_file[$giver->md5] = $recipient->md5; } if (!is_null($debug)) { $debug = array_merge($debug, get_results($persons_array_in, $selections, FALSE)); } if (file_put_contents($datafile, json_encode($selections_for_file)) === FALSE) { $errors[] = 'Unable to save to data file.'; return FALSE; } $successes[] = 'Data file successfully created.'; return TRUE; } $errors = array(); $successes = array(); $debug_msgs = ($do_debug) ? array() : NULL; //Test for any md5 collisions $md5_tests = array(); foreach ($persons as $tmp_name => $person_tmp) { if (isset($md5_tests[$person_tmp->md5])) { $errors[] = "Person name md5 collision for {$tmp_name}. Please change name to resolve."; } else { $md5_tests[$person_tmp->md5] = 1; } } foreach ($persons as $tmp_name => $person_tmp) { if ( (isset($md5_tests[$person_tmp->family_md5])) && ($md5_tests[$person_tmp->family_md5] != $person_tmp->family_id) ) { $errors[] = "Family ID md5 collision for {$person_tmp->family_id}. Please family ID to resolve."; } else { $md5_tests[$person_tmp->family_md5] = $person_tmp->family_id; } } $person_initials = NULL; $person_name = ''; $person_recipient = ''; if ( (isset($_REQUEST['action'])) && ($_REQUEST['action'] == 'submit') ) { if ( (isset($_REQUEST['person'])) && (!empty($_REQUEST['person'])) ) { $person_name = $_REQUEST['person']; if (isset($persons[$person_name])) { if ((isset($_POST['userpw'])) && ($_POST['userpw'] == $persons[$person_name]->password)) { $person_initials = $persons[$person_name]->initials; if (($picks_json = file_get_contents($datafile)) === FALSE) { $errors[] = 'Unable to read data file.'; return FALSE; } $selections = json_decode($picks_json, TRUE); $person_md5 = $persons[$person_name]->md5; $recipient_md5 = $selections[$person_md5]; foreach ($persons as $person_iter_name => $person_iter_obj) { if ($recipient_md5 == $person_iter_obj->md5) { $person_recipient = $person_iter_name; break; } } } else { $errors[] = "Invalid password for {$person_name}."; } } else { $errors[] = 'Unknown person.'; } } else { $errors[] = 'You must select a person from the list.'; } } $is_admin = FALSE; if ( (isset($_REQUEST['action'])) && ($_REQUEST['action'] == 'admin') && (isset($_POST['pw'])) ) { if ($_POST['pw'] == $admin_password) { $is_admin = TRUE; } else { $errors[] = 'Admin password incorrect.'; } } $is_admin_submit = FALSE; $is_admin_submit_iam = ''; $results_output = NULL; if ( (isset($_REQUEST['action'])) && ($_REQUEST['action'] == 'admin_submit') && (isset($_POST['pw'])) ) { if ($_POST['pw'] == $admin_password) { $is_admin_submit = TRUE; if (isset($_POST['admin_action'])) { switch ($_POST['admin_action']) { case 'reset': $is_admin_submit_iam = ' resetting the picks list data file...'; make_picks_file($persons, $datafile, $errors, $successes, $debug_msgs); break; case 'seelist': if (($picks_json = file_get_contents($datafile)) === FALSE) { $errors[] = 'Unable to read data file.'; return FALSE; } $selections = json_decode($picks_json, TRUE); $results_output = get_results($persons, $selections, TRUE); break; } } } else { $errors[] = 'Admin password incorrect.'; } } $is_login = FALSE; if ( (isset($_REQUEST['action'])) && ($_REQUEST['action'] == 'login') ) { $is_login = TRUE; } $for_person = ''; if (!is_null($person_initials)) { $for_person = " for {$person_name}"; } $iam_person =':'; if ($is_login) { $iam_person = ' logging in as administrator:'; } else if ($is_admin) { $iam_person = ' logged in as administrator:'; } else if (!is_null($person_initials)) { $iam_person = " {$person_name}"; } print << Christmas Hat{$for_person}

Christmas Hat

EOHTML; $status_types = array('errors', 'successes', 'debug_msgs'); foreach ($status_types as $status_type) { if (!empty($$status_type)) { print "
\n"; foreach ($$status_type as $item) { print "{$item}
\n"; } print "

\n"; } } if (!empty($results_output)) { print "
\n"; print "

Pick Results:

\n"; print implode('
', $results_output); print "

"; } print <<"Christmas Hat" already randomly picked the name of your Christmas gift recepient out of a hat, so let's see who you got!

I am{$iam_person}

EOHTML; if ($is_login) { print <<

Admin password:  

EOHTML; } else if ($is_admin) { print <<What do you want to do?

Reset all hat picks
See obfuscated pick list

Password is required to do any action:

Admin password:  

EOHTML; } else if (is_null($person_initials)) { print <<

EOHTML; $radio_outputs = array(); foreach ($persons as $person_name => $person_info) { $name_parts = explode(' ', $person_name, 2); $last_name = isset($name_parts[1]) ? $name_parts[1] : $person_name; $person_name = htmlentities($person_name); $radio_outputs[$last_name . $person_name] = "" . " {$person_name}
"; } ksort($radio_outputs); print "\n"; foreach ($radio_outputs as $ro_key => $ro_val) { print $ro_val . "\n"; } print <<

And my password is:  

EOHTML; } else if (!empty($person_recipient)) { print <<

Your Pick:

{$person_recipient}

Done

EOHTML; } print << EOHTML; ?>