1<?php /* vim: set noet ts=4 sw=4 ft=php: : */ 2 3// This script will only work if included from "update-backend"! 4 5// Fetch ip-to-country.com data and index database 6function fetch_ip_to_country($root) 7{ 8 // Files used / affected 9 $ipdbt = "ip-to-country.db~"; 10 $ipdbc = "ip-to-country.dbr~"; 11 $ipdb = "$root/backend/ip-to-country.db"; 12 $ipidx = "$root/backend/ip-to-country.idx"; 13 14 // Create one index entry for at least 15 // every '$indexby'th record in the db 16 $indexby = 10000000; 17 18 // Get last modified date of ip-to-country data 19 if (file_exists($ipdb)) { $lastmod = filemtime($ipdb); } 20 else { $lastmod = 0; } 21 22 // Fetch data from server to local temporary file 23 $succ = fetch_into_file("http://www.directi.com/iptocountry/" . 24 "?site=php.net&dbformat=1&lastupdate=" . 25 $lastmod, $ipdbt); 26 27 // No success in getting the DB 28 if (!$succ) { return FALSE; } 29 30 /* 31 The following code checks the structure of the file 32 received. If this is an updated data file, then it 33 should start with a given line and end with a given line, 34 and all lines inside should be 24 bytes long with a 35 specific format. If the data received is not in this 36 format, then we reject to replace the old file with this. 37 */ 38 39 // Open temporary database for reading 40 $ipdbf = @fopen($ipdbt, "r"); 41 if (!$ipdbf) { die("Unable to open '$ipdbt' for reading"); } 42 43 // Open local rewritten database for writing 44 $ipdbcf = @fopen($ipdbc, "w"); 45 if (!$ipdbcf) { die("Unable to open '$ipdbc' for writing"); } 46 47 // Initial state is the first line and 48 // the file is expected to be ok 49 $state = 'firstline'; $fileok = TRUE; 50 51 // While we can read a line from the file 52 while (!feof($ipdbf) && ($line = fgets($ipdbf))) { 53 54 // Check the input depending on the state 55 switch ($state) { 56 57 // First line is defined, and after it we 58 // switch to the 'data' state 59 case 'firstline' : 60 if (trim($line) != "#Directi IP-to-Country Db: Start") { 61 $fileok = FALSE; 62 break 2; 63 } else { $state = 'data'; } 64 break; 65 66 // In the data state we either get the last line, 67 // or we get a data line containing 24 bytes, in 68 // which case we write it out to the local rewritten 69 // database 70 case 'data' : 71 if (trim($line) == "#Directi IP-to-Country Db: End") { 72 $state = 'lastline'; 73 } elseif (!preg_match("!\\d{20}\\w{3}\n!", $line)) { 74 $fileok = FALSE; 75 break 2; 76 } else { 77 fwrite($ipdbcf, $line); 78 } 79 break; 80 81 // We should not receive any data after the last 82 // line, only whitespace is allowed 83 case 'lastline' : 84 if (strlen(trim($line)) > 0) { 85 $fileok = FALSE; 86 break 2; 87 } 88 break; 89 } 90 } 91 fclose($ipdbf); 92 fclose($ipdbcf); 93 94 // Remove the temp file. If the data is ok, move 95 // it to the destination, or else delete that too 96 unlink($ipdbt); 97 if (file_exists($ipdbc)) { 98 if (!$fileok) { 99 unlink($ipdbc); 100 } else { 101 rename($ipdbc, $ipdb); 102 create_ip_to_country_index($ipdb, $ipidx, $indexby); 103 } 104 } 105} 106 107// Create local index for ip-to-country.com data 108function create_ip_to_country_index($ipdb, $ipidx, $indexby) 109{ 110 // Last indexed number and last record number 111 $lastidx = $recnum = 0; 112 113 // We store the index in a PHP array temporarily 114 $idx_list = [$indexby, "0,0"]; 115 116 // Open database for reading 117 $ipdbf = fopen($ipdb, "r"); 118 119 // Return with error in case of we cannot open the db 120 if (!$ipdbf) { die("Unable to open '$ipdb' for reading"); } 121 122 // While we can read the file 123 while (!feof($ipdbf)) { 124 125 // Get one record 126 $record = fread($ipdbf, 24); 127 128 // Unable to read a record and not at end => error 129 if (strlen($record) != 24 && !feof($ipdbf)) { 130 die("Incorrect ip-to-country database format"); 131 } 132 133 // This is a new record 134 $recnum++; 135 136 // Get the start of the range for this record 137 $range_start = (float) substr($record, 0, 10); 138 139 // If this range starts a new step with our granularity, 140 // add a new element to the index array 141 if (intval($range_start / $indexby) > $lastidx) { 142 $lastidx = intval($range_start / $indexby); 143 $idx_list[] = "$lastidx,$recnum"; 144 } 145 } 146 147 // Close the database file 148 fclose($ipdbf); 149 150 // Write out index to file 151 $ipidxf = fopen($ipidx, "w"); 152 if (!$ipidxf) { die("Unable to open '$ipidx' for writing"); } 153 fwrite($ipidxf, join("\n", $idx_list)); 154 fclose($ipidxf); 155} 156