DatabaseColumns.php
[Pman.Core] / Import / Core_geoip.php
1 <?php
2
3 require_once 'Pman/Roo.php';
4
5 class Pman_Core_Import_Core_geoip extends Pman_Roo
6 {
7     static $cli_desc = "Insert the geoip database";
8     
9     static $cli_opts = array();
10     
11     var $id_mapping = array();
12
13     function getAuth()
14     {
15         $ff = HTML_FlexyFramework::get();
16         if (!$ff->cli) {
17             die("access denied");
18         }
19         HTML_FlexyFramework::ensureSingle(__FILE__, $this);
20         return true;
21     }
22     
23     function post()
24     {
25         $this->get();
26     }
27     
28     var $processed = 0;
29     var $total = 0;
30     var $echo = '';
31     
32     function get()
33     {
34         
35         PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array($this, 'onPearError'));
36         
37         $location = '/tmp/GeoLite2-City-Locations.csv';
38         $block = '/tmp/GeoLite2-City-Blocks.csv';
39         
40         if(!file_exists($location) || !file_exists($block)){
41             $this->jerr('GeoLite2-City-Locations.csv OR GeoLite2-City-Blocks.csv does not exists?!');
42         }
43         
44         $this->log("Insert location data start");
45         
46         $this->insertLocation($location);
47         
48         $this->log("Insert Block data start");
49         
50         $this->insertBlock($block);
51         
52         $this->jok("DONE");
53     }
54     
55     function insertLocation($csv)
56     {
57         ini_set("auto_detect_line_endings", true);
58         
59         
60         
61         $fh = fopen($csv, 'r');
62         
63         if (!$fh) {
64             $this->jerr("invalid location file");
65         }
66         
67         $req = array(
68             'GEONAME_ID', 'CONTINENT_CODE', 'CONTINENT_NAME',
69             'COUNTRY_ISO_CODE', 'COUNTRY_NAME', 'SUBDIVISION_ISO_CODE',
70             'SUBDIVISION_NAME', 'CITY_NAME', 'METRO_CODE',
71             'TIME_ZONE'
72         );
73         
74         $cols = false;
75         
76         $this->processed = 0;
77         $this->total = count(file($csv));
78         $this->echo = '';
79         
80         while(false !== ($n = fgetcsv($fh,10000, ',', '"'))) {
81             if(!array_filter($n)){ // empty row
82                 continue;
83             }
84             
85             if (!$cols) {
86                 $cols = array();
87                 foreach($n as $k) {
88                     $cols[] = strtoupper(trim($k));
89                 }
90                 
91                 if (empty($cols)) {
92                     continue;
93                 }
94                 foreach($req as $r) {
95                     if (!in_array($r,$cols)) {
96                         $cols = false;
97                         break;
98                     }
99                 }
100                 continue;
101             }
102             
103             $row = array();
104             
105             foreach($cols as $i=>$k) {
106                 $row[$k] = trim($n[$i]);
107             }
108             
109             $this->processLocation($row);
110             
111             $this->processed++;
112             
113             $this->processStatus();
114         }
115         
116     }
117     
118     function insertBlock($csv)
119     {
120         ini_set("auto_detect_line_endings", true);
121         
122         $fh = fopen($csv, 'r');
123         if (!$fh) {
124             $this->jerr("invalid location file");
125         }
126         
127         $req = array(
128             'NETWORK_START_IP', 'NETWORK_MASK_LENGTH', 'GEONAME_ID',
129             'REGISTERED_COUNTRY_GEONAME_ID', 'REPRESENTED_COUNTRY_GEONAME_ID', 'POSTAL_CODE',
130             'LATITUDE', 'LONGITUDE', 'IS_ANONYMOUS_PROXY',
131             'IS_SATELLITE_PROVIDER'
132         );
133         
134         $cols = false;
135         
136         $this->processed = 0;
137         $this->total = count(file($csv));
138         $this->echo = '';
139         
140         while(false !== ($n = fgetcsv($fh,10000, ',', '"'))) {
141             if(!array_filter($n)){ // empty row
142                 continue;
143             }
144             
145             if (!$cols) {
146                 $cols = array();
147                 foreach($n as $k) {
148                     $cols[] = strtoupper(trim($k));
149                 }
150                 
151                 if (empty($cols)) {
152                     continue;
153                 }
154                 foreach($req as $r) {
155                     if (!in_array($r,$cols)) {
156                         $cols = false;
157                         break;
158                     }
159                 }
160                 continue;
161             }
162             
163             $row = array();
164             
165             foreach($cols as $i=>$k) {
166                 $row[$k] = trim($n[$i]);
167             }
168             
169             $this->processBlock($row);
170             
171             $this->processed++;
172             
173             $this->processStatus();
174             
175         }
176         
177     }
178     
179     
180     
181     function processLocation($row)
182     {   
183         $continent = $this->processContinent($row['CONTINENT_CODE'], $row['CONTINENT_NAME']);
184         
185         $country = $this->processCountry($row['COUNTRY_ISO_CODE'], $row['COUNTRY_NAME'], $continent);
186         
187         $division = $this->processDivision($row['SUBDIVISION_ISO_CODE'], $row['SUBDIVISION_NAME']);
188         
189         $city = $this->processCity($row['CITY_NAME'], $row['METRO_CODE'], $row['TIME_ZONE'], $country, $division);
190         
191         if(!empty($city) && !empty($city->id)){
192             $this->id_mapping[$row['GEONAME_ID']] = $city->id;
193         }
194     }
195     
196     function processContinent($code, $name)
197     {
198         if(empty($code)){
199             return false;
200         }
201         
202         $continent = DB_DataObject::factory('core_geoip_continent');
203         if(!$continent->get('code', $code)){
204             $continent->setFrom(array(
205                 'code' => $code,
206                 'name' => (!empty($name)) ? $name : $code
207             ));
208
209             $continent->insert();
210         }
211         
212         return $continent;
213     }
214     
215     function processCountry($code, $name, $continent)
216     {
217         if(empty($code)){
218             return false;
219         }
220         
221         $country = DB_DataObject::factory('core_geoip_country');
222         if(!$country->get('code', $code)){
223             $country->setFrom(array(
224                 'code' => $code,
225                 'name' => (!empty($name)) ? $name : $code,
226                 'continent_id' => (!empty($continent) && !empty($continent->id)) ? $continent->id : 0
227             ));
228
229             $country->insert();
230         }
231         
232         return $country;
233     }
234     
235     function processDivision($code, $name)
236     {
237         if(empty($code)){
238             return false;
239         }
240         
241         $division = DB_DataObject::factory('core_geoip_division');
242         if(!$division->get('code', $code)){
243             $division->setFrom(array(
244                 'code' => $code,
245                 'name' => (!empty($name)) ? $name : $code
246             ));
247
248             $division->insert();
249         }
250         
251         return $division;
252     }
253     
254     function processCity($name, $metro_code, $time_zone, $country, $division)
255     {
256         if(empty($name)){
257             return false;
258         }
259         
260         $city = DB_DataObject::factory('core_geoip_city');
261         
262         if($city->get('name', $name)){
263             return $city;
264         }
265         
266         $city->setFrom(array(
267             'name' => $name,
268             'metro_code' => $metro_code,
269             'time_zone' => $time_zone,
270             'country_id' => (!empty($country) && !empty($country->id)) ? $country->id : 0,
271             'division_id' => (!empty($division) && !empty($division->id)) ? $division->id : 0
272         ));
273         
274         $city->insert();
275         
276         return $city;
277         
278     }
279     
280     function processBlock($row)
281     {
282         if(empty($this->id_mapping[$row['GEONAME_ID']])){
283             $this->log("Missing mapping for {$row['GEONAME_ID']}");
284             $this->log("IP : {$row['NETWORK_START_IP']}");
285             return;
286         }
287         
288         $network_mapping = DB_DataObject::factory('core_geoip_network_mapping');
289         
290         $start_ip = array_pop(explode(":", $row['NETWORK_START_IP']));
291         
292         $network_mapping->setFrom(array(
293             'start_ip' => $start_ip,
294             'mask_length' => pow(2, (128 - $row['NETWORK_MASK_LENGTH'])),
295             'city_id' => $this->id_mapping[$row['GEONAME_ID']]
296         ));
297         
298         if(!$network_mapping->find(true)){
299             $network_mapping->insert();
300         }
301         
302         $location = DB_DataObject::factory('core_geoip_location');
303         if(!$location->get('city_id', $network_mapping->city_id)){
304             $location->setFrom(array(
305                 'latitude' => $row['LATITUDE'],
306                 'longitude' => $row['LONGITUDE'],
307                 'city_id' => $network_mapping->city_id
308             ));
309         }
310         
311         
312         if(!empty($row['POSTAL_CODE'])){
313             $city = DB_DataObject::factory('core_geoip_city');
314             if($city->get($network_mapping->city_id)){
315                 return;
316             }
317
318             $oc = clone($city);
319             $city->postal_code = $row['POSTAL_CODE'];
320             
321             $city->update($oc);
322         }
323         
324     }
325     
326     function processStatus()
327     {
328         echo "\033[K"; // Erase to end of line:
329             
330         if (strlen($this->echo)) {
331             echo "\033[".strlen($this->echo)."D";    // Move $length characters backward
332         }
333
334         $this->echo = str_pad(ROUND(($this->processed / $this->total),2) * 100, 3, ' ', STR_PAD_LEFT) .
335             " % (" . str_pad(($this->processed), strlen($this->total), ' ', STR_PAD_LEFT) .
336             " / {$this->total})";
337
338
339         echo $this->echo;
340
341         if($this->processed == $this->total){
342             echo "\n";
343         }
344     }
345     
346     function log($str)
347     {
348         echo "$str \n";
349     }
350 }