log = fopen("../scripts/import_voter_records.log", "w+"); if ($this->log === false) { error_log("VoterVue : Unable to open log file"); exit(); } $this->log(str_repeat("*", 50)); // Get Settings $this->settings = new SimpleXMLElement((file_exists("../xml/settings.xml") ? file_get_contents("../xml/settings.xml") : "")); if ($this->settings->count() === 0) { error_log("VoterVue : Unable to initialize settings"); exit(); } // Open Database Connections $this->connection = $this->connect(); } // ================================================ // Return a New DEC-DR Database Database Connection // ================================================ public function connect() { try { $host = (string) $this->settings->DatabaseServer; $database = (string) $this->settings->DatabaseName; $user = (string) $this->settings->DatabaseUser; $password = (string) $this->settings->DatabasePassword; $connection = new PDO("mysql:host={$host};dbname={$database};charset=utf8", $user, $password); $connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOException | Exception $e) { trigger_error($e->getMessage()); } return $connection; } // ============================= // Log a message to the Log File // ============================= private function log($message = "") { fwrite($this->log, date("Y-m-d H:i A") . " : " . "{$message} \n"); } // =================== // Process Parcel Data // =================== public function process() { $this->log("Starting Voter Record Import Process"); $this->importVoterRecords(); $this->log("Voter Record Import Process Complete"); } // ==================== // Import Voter Records // ==================== private function importVoterRecords() { $this->log("Processing Voter Records"); $voter_record_file_path = '/data/ositssrc/projects/votervue_raw_data/20251210_Voter_Detail_20251210'; $voter_history_files = glob("{$voter_record_file_path}/*.txt"); sort($voter_history_files); $SQL = "INSERT INTO voters ( voter_county_code, voter_id, voter_name_last, voter_name_suffix, voter_name_first, voter_name_middle, voter_public_records_exempt, voter_residence_address_1, voter_residence_address_2, voter_residence_city, voter_residence_state, voter_residence_zipcode, voter_mailing_address_1, voter_mailing_address_2, voter_mailing_address_3, voter_mailing_city, voter_mailing_state, voter_mailing_zipcode, voter_mailing_country, voter_gender, voter_race, voter_birth_date, voter_registration_date, voter_party_affiliation, voter_precinct, voter_precinct_group, voter_precinct_split, voter_precinct_suffix, voter_voter_status, voter_congressional_district, voter_house_district, voter_senate_district, voter_county_commission_district, voter_school_board_district, voter_daytime_area_code, voter_daytime_phone_number, voter_daytime_phone_extension, voter_email_address ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )"; $statement = $this->connection->prepare($SQL); $counter = 0; foreach ($voter_history_files as $file) { $this->log("Importing file: {$file}"); $voterhistory = fopen($file, 'r'); if ($voterhistory === false) { $this->log("Unable to open {$file}"); echo "❌ Unable to open {$file}\n"; continue; } $lineNum = 0; while (($line = fgets($voterhistory)) !== false) { $lineNum++; $line = rtrim($line, "\r\n"); if ($line === '') { continue; } $cols = explode("\t", $line); if (count($cols) < 38) { $this->log("Skipped malformed line {$lineNum} in {$file} (cols=" . count($cols) . ")"); continue; } [$county_code, $voter_id, $name_last, $name_suffix, $name_first, $name_middle, $public_exempt, $res_addr1, $res_addr2, $res_city, $res_state, $res_zip, $mail_addr1, $mail_addr2, $mail_addr3, $mail_city, $mail_state, $mail_zip, $mail_country, $gender, $race, $birth_date, $reg_date, $party, $precinct, $precinct_group, $precinct_split, $precinct_suffix, $status, $cd, $hd, $sd, $ccd, $sbd, $area, $phone, $ext, $email] = $cols; try { $statement->execute([ $this->normalize($county_code), $this->normalize($voter_id), $this->normalize($name_last), $this->normalize($name_suffix), $this->normalize($name_first), $this->normalize($name_middle), $this->normalize($public_exempt), $this->normalize($res_addr1), $this->normalize($res_addr2), $this->normalize($res_city), $this->normalize($res_state), $this->normalize($res_zip), $this->normalize($mail_addr1), $this->normalize($mail_addr2), $this->normalize($mail_addr3), $this->normalize($mail_city), $this->normalize($mail_state), $this->normalize($mail_zip), $this->normalize($mail_country), $this->normalize($gender), $this->normalize($race), $this->parseDate($birth_date), $this->parseDate($reg_date), $this->normalize($party), $this->normalize($precinct), $this->normalize($precinct_group), $this->normalize($precinct_split), $this->normalize($precinct_suffix), $this->normalize($status), $this->normalize($cd), $this->normalize($hd), $this->normalize($sd), $this->normalize($ccd), $this->normalize($sbd), $this->normalize($area), $this->normalize($phone), $this->normalize($ext), $this->normalize($email) ]); $counter++; if (($counter % 10) === 0) { $this->log("Processed {$counter} records..."); } } catch (Throwable $e) { $this->log("Insert failed {$file}:{$lineNum} - " . $e->getMessage()); echo "❌ Insert failed {$file}:{$lineNum} → {$e->getMessage()}\n"; } } fclose($voterhistory); } $this->log("Completed voter import. Total records processed: {$counter}"); } // ================================= // Return a $this->normalized String // ================================= private function normalize(?string $value): ?string { $value = trim((string) $value); return ($value === '' || $value === '*') ? null : $value; } // ==================== // Return a Parsed Date // ==================== private function parseDate(?string $value): ?string { $value = $this->normalize($value); if ($value === null) { return null; } $dt = DateTime::createFromFormat('m/d/Y', $value); return $dt ? $dt->format('Y-m-d') : null; } } ?>