log = fopen("../scripts/import_voter_history.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 VoterVue 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 History Import Process"); $this->importVoterHistory(); $this->log("Voter History Import Process Completed"); } // ==================== // Import Voter History // ==================== private function importVoterHistory() { $this->log("Processing Voter History Records"); $path = '/data/ositssrc/projects/votervue_raw_data/20251210_Voter_History_20251210'; $files = glob("{$path}/*.txt"); sort($files); $SQL = "INSERT IGNORE INTO voterhistory ( voterhistory_county_code, voterhistory_voter_id, voterhistory_election_date, voterhistory_election_type, voterhistory_history_code ) VALUES ( ?, ?, ?, ?, ? )"; $statement = $this->connection->prepare($SQL); $counter = 0; $batchCounter = 0; $batchSize = 50000; foreach ($files as $file) { $this->log("Importing history file: {$file}"); $fh = fopen($file, 'r'); if ($fh === false) { $this->log("Unable to open {$file}"); continue; } $lineNum = 0; try { // Start transaction for this file $this->connection->beginTransaction(); while (($line = fgets($fh)) !== false) { $lineNum++; $line = rtrim($line, "\r\n"); if ($line === '') { continue; } $cols = explode("\t", $line); if (count($cols) < 5) { $this->log("Skipped malformed line {$lineNum} in {$file} (cols=" . count($cols) . ")"); continue; } [$county_code, $voter_id, $election_date, $election_type, $history_code] = $cols; $statement->execute([ $this->normalize($county_code), $this->normalize($voter_id), $this->parseDate($election_date), $this->normalize($election_type), $this->normalize($history_code) ]); $counter++; $batchCounter++; // Commit every batchSize rows if ($batchCounter >= $batchSize) { $this->connection->commit(); $this->connection->beginTransaction(); $batchCounter = 0; $this->log("Processed {$counter} history records..."); } } // Final commit for this file $this->connection->commit(); $batchCounter = 0; } catch (Throwable $e) { // Roll back any open transaction for this file if ($this->connection->inTransaction()) { $this->connection->rollBack(); } $this->log("Insert failed {$file}:{$lineNum} - " . $e->getMessage()); } fclose($fh); } $this->log("Completed voter history 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; } } ?>