Skip to content
This repository was archived by the owner on Apr 23, 2020. It is now read-only.

Commit 2543200

Browse files
committed
Fix indexing
1 parent 2dc3b44 commit 2543200

File tree

4 files changed

+120
-92
lines changed

4 files changed

+120
-92
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-
examples/tmp

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# IP Tool
22
![Logo](https://github.com/ddrv/iptool/wiki/img/iptool.png)
3-
> IP Tool. Define data by IP Address
3+
> IP Tool. Define data by IP Address.
44
55
[Documentation](https://github.com/ddrv/iptool/wiki)
6+
7+
The idea is taken from [Sypex Geo](https://sypexgeo.net)

src/Converter.php

Lines changed: 92 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,9 @@ public function addCSV($name,$file,$ignoreFirstRows=true,$encoding='UTF-8',$deli
251251
$test = @fopen($file,'rb');
252252
if ($test === false) {
253253
$this->errors[] = $srcId.' Can\'t open file';
254+
} else {
255+
fclose($test);
254256
}
255-
fclose($test);
256257
if (!in_array($encoding,$this->encodings)) {
257258
$this->errors[] = $srcId.' Parameter encoding must be '.implode(',',$this->encodings);
258259
}
@@ -380,81 +381,81 @@ public function addNetworks($csv,$ipFormat,$firstIp,$lastIp,$registers) {
380381
* @param string $file
381382
*/
382383
public function create($file) {
383-
if (true) {
384-
$tmpDb = $this->temporaryDir . DIRECTORY_SEPARATOR . uniqid().'tmp.sqlite';
385-
try {
386-
$this->pdo = new PDO('sqlite:' . $tmpDb);
387-
$this->pdo->exec('PRAGMA foreign_keys = 1;PRAGMA encoding = \'UTF-8\';');
388-
} catch (PDOException $e) {
389-
return;
390-
}
391-
$this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
392-
$this->createTmpDb();
393-
$registers = $this->createTmpRegisters();
394-
$networks = $this->createTmpNetworks();
395-
396-
/* Remove temporary SQLite database */
397-
if (is_writable($tmpDb)) unlink($tmpDb);
398-
399-
/* Create header */
400-
$header = pack('C', self::VERSION);
401-
$header .= pack('C', count($this->meta['registers']));
402-
$nameLen = 1;
403-
$packLen = strlen($this->meta['networks']['pack']);
404-
$len = ($this->meta['networks']['len'] > 255)?'I1':'C1';
405-
$itm = ($this->meta['networks']['items'] > 255)?'I1':'C1';
406-
foreach ($this->meta['registers'] as $registerName => $register) {
407-
if (strlen($registerName) > $nameLen) $nameLen = strlen($registerName);
408-
if (strlen($register['pack']) > $packLen) $packLen = strlen($register['pack']);
409-
if (($register['len'] > 255) && $len == 'C1') $len = 'I1';
410-
if (($register['items'] > 255) && $itm == 'C1') $itm = 'I1';
411-
}
412-
$pack = 'A'.$nameLen.'A'.$packLen.$len.$itm;
413-
$unpack = 'A'.$nameLen.'name/A'.$packLen.'pack/'.$len.'len/'.$itm.'items';
414-
$header .= pack('I',strlen($unpack));
415-
$header .= pack('A*',$unpack);
416-
$header .= pack('I',strlen(pack($pack,'','',0,0)));
417-
foreach ($this->meta['registers'] as $registerName => $register) {
418-
$header .= pack($pack,$registerName,$register['pack'],$register['len'],$register['items']);
419-
}
420-
$header .= pack($pack,'n',$this->meta['networks']['pack'],$this->meta['networks']['len'],$this->meta['networks']['items']);
421-
$header .= $this->packArray('I*',$this->meta['index']);
422-
$headerLen = strlen($header);
423-
$letter = 'C';
424-
if ($headerLen > 255) $letter = 'I';
425-
426-
/* Create binary database */
427-
$database = fopen($file,'w');
428-
fwrite($database,'DIT'.$letter.pack($letter,$headerLen).$header);
429-
430-
/* Write networks to database */
431-
$stream = fopen($networks,'rb');
384+
if (!empty($this->errors)) return null;
385+
$tmpDb = $this->temporaryDir . DIRECTORY_SEPARATOR . uniqid().'tmp.sqlite';
386+
try {
387+
$this->pdo = new PDO('sqlite:' . $tmpDb);
388+
$this->pdo->exec('PRAGMA foreign_keys = 1;PRAGMA encoding = \'UTF-8\';');
389+
} catch (PDOException $e) {
390+
return;
391+
}
392+
$this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
393+
$this->createTmpDb();
394+
$registers = $this->createTmpRegisters();
395+
$networks = $this->createTmpNetworks();
396+
397+
/* Remove temporary SQLite database */
398+
if (is_writable($tmpDb)) unlink($tmpDb);
399+
400+
/* Create header */
401+
$header = pack('C', self::VERSION);
402+
$header .= pack('C', count($this->meta['registers']));
403+
$nameLen = 1;
404+
$packLen = strlen($this->meta['networks']['pack']);
405+
$len = ($this->meta['networks']['len'] > 255)?'I1':'C1';
406+
$itm = ($this->meta['networks']['items'] > 255)?'I1':'C1';
407+
foreach ($this->meta['registers'] as $registerName => $register) {
408+
if (strlen($registerName) > $nameLen) $nameLen = strlen($registerName);
409+
if (strlen($register['pack']) > $packLen) $packLen = strlen($register['pack']);
410+
if (($register['len'] > 255) && $len == 'C1') $len = 'I1';
411+
if (($register['items'] > 255) && $itm == 'C1') $itm = 'I1';
412+
}
413+
$pack = 'A'.$nameLen.'A'.$packLen.$len.$itm;
414+
$unpack = 'A'.$nameLen.'name/A'.$packLen.'pack/'.$len.'len/'.$itm.'items';
415+
$header .= pack('I',strlen($unpack));
416+
$header .= pack('A*',$unpack);
417+
$header .= pack('I',strlen(pack($pack,'','',0,0)));
418+
foreach ($this->meta['registers'] as $registerName => $register) {
419+
$header .= pack($pack,$registerName,$register['pack'],$register['len'],$register['items']);
420+
}
421+
$header .= pack($pack,'n',$this->meta['networks']['pack'],$this->meta['networks']['len'],$this->meta['networks']['items']);
422+
$header .= $this->packArray('I*',$this->meta['index']);
423+
$headerLen = strlen($header);
424+
$letter = 'C';
425+
if ($headerLen > 255) $letter = 'I';
426+
427+
/* Create binary database */
428+
$database = fopen($file,'w');
429+
fwrite($database,'DIT'.$letter.pack($letter,$headerLen).$header);
430+
431+
/* Write networks to database */
432+
$stream = fopen($networks,'rb');
433+
stream_copy_to_stream($stream,$database);
434+
fclose($stream);
435+
436+
/* Remove networks temporary file */
437+
if (is_writable($networks)) unlink($networks);
438+
439+
/* Write registers to database */
440+
foreach ($registers as $register) {
441+
$stream = fopen($register,'rb');
432442
stream_copy_to_stream($stream,$database);
433443
fclose($stream);
434-
435-
/* Remove networks temporary file */
436-
if (is_writable($networks)) unlink($networks);
437-
438-
/* Write registers to database */
439-
foreach ($registers as $register) {
440-
$stream = fopen($register,'rb');
441-
stream_copy_to_stream($stream,$database);
442-
fclose($stream);
443-
/* Remove register temporary file */
444-
if (is_writable($register)) unlink($register);
445-
}
446-
447-
fwrite($database,pack('N1A128',time(),$this->author));
448-
fwrite($database,pack('A*',$this->license));
449-
fclose($database);
444+
/* Remove register temporary file */
445+
if (is_writable($register)) unlink($register);
450446
}
447+
448+
fwrite($database,pack('N1A128',time(),$this->author));
449+
fwrite($database,pack('A*',$this->license));
450+
fclose($database);
451451
return;
452452
}
453453

454454
/**
455455
* Create temporary database.
456456
*/
457457
protected function createTmpDb() {
458+
if (empty($this->registers)) return;
458459
foreach ($this->registers as $table=>$register) {
459460
$fields = array('`_pk`', '`_used`');
460461
$params = array(':_pk',':_used');
@@ -466,10 +467,10 @@ protected function createTmpDb() {
466467
$params[] = ':' . $f;
467468
$fieldToColumn[$f] = $field['column'];
468469
}
469-
$sql = 'CREATE TABLE `' . $table . '` (' . implode(',', $fields) . ', CONSTRAINT `_pk` PRIMARY KEY (`_pk`) ON CONFLICT IGNORE);';
470-
$sql .= 'CREATE INDEX `_used` ON `'.$table.'` (`_used`);';
470+
$sql = 'CREATE '.'TABLE `' . $table . '` (' . implode(',', $fields) . ', CONSTRAINT `_pk` PRIMARY KEY (`_pk`) ON CONFLICT IGNORE);';
471+
$sql .= 'CREATE '.'INDEX `_used` ON `'.$table.'` (`_used`);';
471472
$this->pdo->exec($sql);
472-
$sql = 'INSERT INTO `'.$table.'` (' . implode(',', $fields) . ') VALUES (' . implode(',', $params) . ');';
473+
$sql = 'INSERT '.'INTO `'.$table.'` (' . implode(',', $fields) . ') VALUES (' . implode(',', $params) . ');';
473474
$prepare['insert'][$table] = $this->pdo->prepare($sql);
474475
$this->pdo->beginTransaction();
475476
$file = $this->csv[$register['csv']];
@@ -514,9 +515,9 @@ protected function createTmpDb() {
514515
$this->pdo->commit();
515516
}
516517

517-
$sql = "CREATE TABLE `_ips` (`id` INTEGER PRIMARY KEY ON CONFLICT IGNORE AUTOINCREMENT, `ip` INTEGER,`action` TEXT, `parameter` TEXT, `value` TEXT, `offset` TEXT); CREATE INDEX `ip` ON `_ips` (`ip`); CREATE INDEX `parameter` ON `_ips` (`parameter`); CREATE INDEX `value` ON `_ips` (`value`);";
518+
$sql = 'CREATE '.'TABLE `_ips` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `ip` INTEGER,`action` TEXT, `parameter` TEXT, `value` TEXT, `offset` TEXT); CREATE INDEX `ip` ON `_ips` (`ip`); CREATE INDEX `parameter` ON `_ips` (`parameter`); CREATE INDEX `value` ON `_ips` (`value`);';
518519
$this->pdo->exec($sql);
519-
$prepare['insert']['ips'] = $this->pdo->prepare("INSERT INTO `_ips` (`ip`,`action`,`parameter`,`value`) VALUES (:ip,:action,:parameter,:value);");
520+
$prepare['insert']['ips'] = $this->pdo->prepare('INSERT '.'INTO `_ips` (`ip`,`action`,`parameter`,`value`) VALUES (:ip,:action,:parameter,:value);');
520521
foreach ($this->networks as $network) {
521522
$file = $this->csv[$network['csv']];
522523
$csv = fopen($file['file'], 'r');
@@ -596,8 +597,11 @@ protected function createTmpDb() {
596597

597598
/**
598599
* Create temporary registers files.
600+
*
601+
* @return array
599602
*/
600603
protected function createTmpRegisters() {
604+
if (empty($this->registers)) return array();
601605
$files = array();
602606
foreach ($this->registers as $table=>$register) {
603607
$offset = 0;
@@ -655,7 +659,7 @@ protected function createTmpRegisters() {
655659
$offset ++;
656660
fwrite($tmpFile,$bin);
657661
}
658-
$this->pdo->exec('UPDATE `_ips` SET `offset` =\''.($check?$offset:0).'\' WHERE `parameter` = \''.$table.'\' AND `value`=\''.$rowId.'\';');
662+
$this->pdo->exec('UPDATE '.'`_ips` SET `offset` =\''.($check?$offset:0).'\' WHERE `parameter` = \''.$table.'\' AND `value`=\''.$rowId.'\';');
659663
}
660664
$this->meta['registers'][$table]['items'] = $offset;
661665
$this->pdo->commit();
@@ -666,12 +670,15 @@ protected function createTmpRegisters() {
666670

667671
/**
668672
* Create temporary networks files
673+
*
674+
* @return string
669675
*/
670676
protected function createTmpNetworks() {
671677
$ip = 0;
672678
$fields = array();
673679
$values = array();
674680
$format = array();
681+
if (empty($this->registers)) return null;
675682
foreach ($this->registers as $register=>$null) {
676683
$format['pack'][$register] = 'C';
677684
$format['unpack'][$register] = 'C'.$register;
@@ -686,21 +693,21 @@ protected function createTmpNetworks() {
686693
$empty = self::packArray($pack,$fields);
687694
$bin = pack('N',$ip).$empty;
688695
$this->meta['networks']['pack'] = implode('/',$format['unpack']);
689-
$this->meta['networks']['items'] = 1;
696+
$offset = 0;
690697
$this->meta['networks']['len'] = strlen($bin);
691698
$this->meta['index'][0] = 0;
692699
$file = $this->temporaryDir.DIRECTORY_SEPARATOR.'networks.'.uniqid().'.tmp';
693700
$tmpFile = fopen($file,'w');
694-
$ipinfo = $this->pdo->query('SELECT * FROM `_ips` ORDER BY `ip` ASC, `action` DESC, `id` ASC;');
701+
$ipinfo = $this->pdo->query('SELECT * '.'FROM `_ips` ORDER BY `ip` ASC, `action` DESC, `id` ASC;');
695702
while ($row = $ipinfo->fetch()) {
696703
if ($row['ip'] !== $ip) {
697704
foreach ($values as $param=>$v) {
698705
$fields[$param] = array_pop($v);
699706
}
700707
fwrite($tmpFile,pack('N',$ip).self::packArray($pack,$fields));
701708
$octet = (int)long2ip($ip);
702-
$this->meta['networks']['items']++;
703-
if (!isset($this->meta['index'][$octet])) $this->meta['index'][$octet] = $this->meta['networks']['items'];
709+
if (!isset($this->meta['index'][$octet])) $this->meta['index'][$octet] = $offset;
710+
$offset++;
704711
$ip = $row['ip'];
705712
}
706713
if ($row['action'] == 'remove') {
@@ -712,11 +719,16 @@ protected function createTmpNetworks() {
712719
$values[$row['parameter']][] = $row['offset'];
713720
}
714721
}
715-
716-
foreach ($values as $param=>$v) {
717-
$fields[$param] = array_pop($v);
722+
if ($ip < ip2long('255.255.255.255')) {
723+
foreach ($values as $param => $v) {
724+
$fields[$param] = array_pop($v);
725+
}
726+
$octet = (int)long2ip($ip);
727+
if (!isset($this->meta['index'][$octet])) $this->meta['index'][$octet] = $offset;
728+
$offset++;
729+
fwrite($tmpFile, pack('N', $ip) . self::packArray($pack, $fields));
718730
}
719-
fwrite($tmpFile,pack('N',$ip).self::packArray($pack,$fields));
731+
$this->meta['networks']['items'] = $offset;
720732
for($i=1;$i<=255;$i++) {
721733
if (!isset($this->meta['index'][$i])) $this->meta['index'][$i] = $this->meta['index'][$i-1];
722734
}

src/Iptool.php

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
/**
55
* Class Iptool
66
*
7-
* the idea is taken from Sypex Geo @see https://sypexgeo.net
8-
*
97
* @property boolean $isCorrect
108
* @property array $errors
119
* @property array $meta
@@ -84,8 +82,6 @@ public function __construct($databaseFile) {
8482
'version' => $tmp['ver'],
8583
];
8684
$registersCount = $tmp['count'];
87-
//$tmp = unpack('IformatLen',substr($header,$offset,4));
88-
//$offset += 4;
8985
$registersFormatLen = $tmp['formatLen'];
9086
$tmp = unpack('A*format',substr($header,$offset,$registersFormatLen));
9187
$offset += $registersFormatLen;
@@ -117,7 +113,7 @@ public function __construct($databaseFile) {
117113
$offset += ($this->meta['networks']['len'] * $this->meta['networks']['items']);
118114
foreach ($this->meta['registers'] as $r=>$register) {
119115
$this->meta['registers'][$r]['offset'] = $offset;
120-
$offset += ($register['len'] * $register['items']);
116+
$offset += ($register['len'] * ($register['items']+1));
121117
}
122118
$this->fileSize = filesize($databaseFile);
123119
$this->isCorrect = true;
@@ -152,12 +148,13 @@ public function find($ip) {
152148
$blocks = fread($this->db,$blockCount*$this->meta['networks']['len']);
153149
$offset = 0;
154150
$step = ceil(sqrt($blockCount));
155-
$check = substr($blocks, $offset + ($this->meta['networks']['len'] * $step), 4);
156151

152+
$check = substr($blocks, $offset + ($this->meta['networks']['len'] * $step), 4);
157153
while ($check && $long >= $check && ($offset < ($blockCount)*$this->meta['networks']['len'])) {
158154
$offset += $this->meta['networks']['len'] * $step;
159155
$check = substr($blocks, $offset + ($this->meta['networks']['len'] * $step), 4);
160156
}
157+
161158
do {
162159
if ($offset > strlen($blocks)) {
163160
$offset = strlen($blocks)-$this->meta['networks']['len'];
@@ -176,17 +173,18 @@ public function find($ip) {
176173
}
177174
}
178175
if (!$next) {
179-
$next = pack('N',ip2long('255.255.255.255'));
176+
$next = pack('N',ip2long('255.255.255.255')+1);
180177
}
181178
$network = unpack('Nfirst/Nlast',$first.$next);
182-
$data['network'] = array(long2ip($network['first']),long2ip($network['last']));
179+
$data['network'] = array(long2ip($network['first']),long2ip($network['last']-1));
183180
foreach ($registers as $register=>$item) {
184-
$data['data'][$register] = $this->getRegisterData($register,$item);
181+
$data['data'][$register] = $this->getRegisterRecord($register,$item);
185182
}
186183
return $data;
187184
}
188185

189-
public function getRegisterData($register,$item) {
186+
public function getRegisterRecord($register,$item) {
187+
if ($item > $this->meta['registers'][$register]['items']) $item = 0;
190188
$seek = $this->meta['registers'][$register]['offset']+($item * $this->meta['registers'][$register]['len']);
191189
fseek($this->db,$seek);
192190
$data = unpack($this->meta['registers'][$register]['pack'],fread($this->db,$this->meta['registers'][$register]['len']));
@@ -218,5 +216,22 @@ public function about() {
218216
$about = array_replace($about, $tmp);
219217
return $about;
220218
}
219+
220+
/**
221+
* Return array of register rows
222+
*
223+
* @param $register
224+
* @return array
225+
*/
226+
public function getRegister($register) {
227+
if (!isset($this->meta['registers'][$register])) return array();
228+
$result = array();
229+
$seek = $this->meta['registers'][$register]['offset']+$this->meta['registers'][$register]['len'];
230+
fseek($this->db,$seek);
231+
for($i = 1;$i<=$this->meta['registers'][$register]['items'];$i++) {
232+
$result[$i] = unpack($this->meta['registers'][$register]['pack'],fread($this->db,$this->meta['registers'][$register]['len']));
233+
}
234+
return $result;
235+
}
221236
}
222237
}

0 commit comments

Comments
 (0)