Passed
Push — master ( 749f83...6dfd79 )
by Maurício
07:38
created

ShapeFile::getIndexFromDBFData()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 6
nc 3
nop 2
dl 0
loc 12
ccs 6
cts 6
cp 1
crap 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * phpMyAdmin ShapeFile library
7
 * <https://github.com/phpmyadmin/shapefile/>.
8
 *
9
 * Copyright 2006-2007 Ovidio <ovidio AT users.sourceforge.net>
10
 * Copyright 2016 - 2017 Michal Čihař <[email protected]>
11
 *
12
 * This program is free software; you can redistribute it and/or
13
 * modify it under the terms of the GNU General Public License
14
 * as published by the Free Software Foundation.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU General Public License
22
 * along with this program; if not, you can download one from
23
 * https://www.gnu.org/copyleft/gpl.html.
24
 */
25
26
namespace PhpMyAdmin\ShapeFile;
27
28
use function array_push;
29
use function chr;
30
use function count;
31
use function extension_loaded;
32
use function fclose;
33
use function feof;
34
use function file_exists;
35
use function fopen;
36
use function fread;
37
use function fwrite;
38
use function in_array;
39
use function is_array;
40
use function is_readable;
41
use function ord;
42
use function pack;
43
use function sprintf;
44
use function str_replace;
45
use function strpos;
46
use function strtoupper;
47
use function substr;
48
use function trim;
49
use function unlink;
50
51
/**
52
 * ShapeFile class.
53
 */
54
class ShapeFile
55
{
56
    public const MAGIC = 0x270a;
57
58
    /** @var string|null */
59
    public $fileName;
60
61
    /** @var resource|null */
62
    private $shpFile = null;
63
    /** @var resource|null */
64
    private $shxFile = null;
65
    /** @var resource|null */
66
    private $dbfFile = null;
67
68
    /** @var array|null */
69
    private $dbfHeader;
70
71
    /** @var string */
72
    public $lastError = '';
73
74
    /** @var array */
75
    public $boundingBox = [
76
        'xmin' => 0.0,
77
        'ymin' => 0.0,
78
        'xmax' => 0.0,
79
        'ymax' => 0.0,
80
    ];
81
    /** @var int */
82
    private $fileLength = 0;
83
84
    /** @var int|false */
85
    public $shapeType = 0;
86
87
    /** @var array */
88
    public $records = [];
89
90
    /**
91
     * Checks whether dbase manipulations are supported.
92
     */
93 186
    public static function supportsDbase(): bool
94
    {
95 186
        return extension_loaded('dbase');
96
    }
97
98
    /**
99
     * @param int         $shapeType   File shape type, should be same as all records
100
     * @param array       $boundingBox File bounding box
101
     * @param string|null $fileName    File name
102
     */
103 218
    public function __construct(
104
        int $shapeType,
105
        array $boundingBox = [
106
            'xmin' => 0.0,
107
            'ymin' => 0.0,
108
            'xmax' => 0.0,
109
            'ymax' => 0.0,
110
        ],
111
        ?string $fileName = null
112
    ) {
113 218
        $this->shapeType = $shapeType;
114 218
        $this->boundingBox = $boundingBox;
115 218
        $this->fileName = $fileName;
116
117
        /**
118
         * The value for file length is the total length of the file in 16-bit words
119
         * (including the fifty 16-bit words that make up the header).
120
         */
121 218
        $this->fileLength = 50;
122 52
    }
123
124
    /**
125
     * Loads shapefile and dbase (if supported).
126
     *
127
     * @param string $fileName File mask to load (eg. example.*)
128
     */
129 194
    public function loadFromFile(string $fileName): bool
130
    {
131 194
        if (! empty($fileName)) {
132 186
            $this->fileName = $fileName;
133 186
            $result = $this->openSHPFile();
134
        } else {
135
            /* We operate on buffer emulated by readSHP / eofSHP */
136 8
            $result = true;
137
        }
138
139 194
        if ($result && ($this->openDBFFile())) {
140 170
            if (! $this->loadHeaders()) {
141 12
                $this->closeSHPFile();
142 12
                $this->closeDBFFile();
143
144 12
                return false;
145
            }
146
147 158
            if (! $this->loadRecords()) {
148
                $this->closeSHPFile();
149
                $this->closeDBFFile();
150
151
                return false;
152
            }
153
154 158
            $this->closeSHPFile();
155 158
            $this->closeDBFFile();
156
157 158
            return true;
158
        }
159
160 24
        return false;
161
    }
162
163
    /**
164
     * Saves shapefile.
165
     *
166
     * @param string|null $fileName Name of file, otherwise existing is used
167
     */
168 110
    public function saveToFile(?string $fileName = null): bool
169
    {
170 110
        if ($fileName !== null) {
171 110
            $this->fileName = $fileName;
172
        }
173
174 110
        if (! $this->openSHPFile(true) || (! $this->openSHXFile(true)) || (! $this->createDBFFile())) {
175
            return false;
176
        }
177
178 110
        $this->saveHeaders();
179 110
        $this->saveRecords();
180 110
        $this->closeSHPFile();
181 110
        $this->closeSHXFile();
182 110
        $this->closeDBFFile();
183
184 110
        return true;
185
    }
186
187
    /**
188
     * Generates filename with given extension.
189
     *
190
     * @param string $extension Extension to use (including dot)
191
     */
192 196
    private function getFilename(string $extension): string
193
    {
194 196
        return str_replace('.*', $extension, (string) $this->fileName);
195
    }
196
197
    /**
198
     * Updates bounding box based on shpData.
199
     *
200
     * @param string $type Type of box
201
     * @param array  $data ShapeRecord shpData
202
     */
203 102
    private function updateBBox(string $type, array $data): void
204
    {
205 102
        $min = $type . 'min';
206 102
        $max = $type . 'max';
207
208
        if (
209 102
            ! isset($this->boundingBox[$min])
210 102
            || $this->boundingBox[$min] == 0.0 // phpcs:ignore SlevomatCodingStandard.Operators.DisallowEqualOperators
211 102
            || ($this->boundingBox[$min] > $data[$min])
212
        ) {
213 102
            $this->boundingBox[$min] = $data[$min];
214
        }
215
216
        if (
217 102
            isset($this->boundingBox[$max])
218 102
            && $this->boundingBox[$max] != 0.0 // phpcs:ignore SlevomatCodingStandard.Operators.DisallowEqualOperators
219 102
            && ($this->boundingBox[$max] >= $data[$max])
220
        ) {
221 6
            return;
222
        }
223
224 102
        $this->boundingBox[$max] = $data[$max];
225 24
    }
226
227
    /**
228
     * Adds record to shape file.
229
     *
230
     * @return int Number of added record
231
     */
232 102
    public function addRecord(ShapeRecord $record): int
233
    {
234 102
        if (isset($this->dbfHeader) && (is_array($this->dbfHeader))) {
235 98
            $record->updateDBFInfo($this->dbfHeader);
236
        }
237
238 102
        $this->fileLength += $record->getContentLength() + 4;
239 102
        $this->records[] = $record;
240 102
        $this->records[count($this->records) - 1]->recordNumber = count($this->records);
241
242 102
        $this->updateBBox('x', $record->shpData);
243 102
        $this->updateBBox('y', $record->shpData);
244
245 102
        if (in_array($this->shapeType, [11, 13, 15, 18, 21, 23, 25, 28])) {
246 64
            $this->updateBBox('m', $record->shpData);
247
        }
248
249 102
        if (in_array($this->shapeType, [11, 13, 15, 18])) {
250 32
            $this->updateBBox('z', $record->shpData);
251
        }
252
253 102
        return count($this->records) - 1;
254
    }
255
256
    /**
257
     * Deletes record from shapefile.
258
     */
259 2
    public function deleteRecord(int $index): void
260
    {
261 2
        if (! isset($this->records[$index])) {
262
            return;
263
        }
264
265 2
        $this->fileLength -= $this->records[$index]->getContentLength() + 4;
266 2
        $count = count($this->records) - 1;
267 2
        for ($i = $index; $i < $count; ++$i) {
268 2
            $this->records[$i] = $this->records[$i + 1];
269
        }
270
271 2
        unset($this->records[count($this->records) - 1]);
272 2
        $this->deleteRecordFromDBF($index);
273
    }
274
275
    /**
276
     * Returns array defining fields in DBF file.
277
     *
278
     * @return array|null see setDBFHeader for more information
279
     */
280 8
    public function getDBFHeader(): ?array
281
    {
282 8
        return $this->dbfHeader;
283
    }
284
285
    /**
286
     * Changes array defining fields in DBF file, used in dbase_create call.
287
     *
288
     * @param array $header An array of arrays, each array describing the
289
     *                      format of one field of the database. Each
290
     *                      field consists of a name, a character indicating
291
     *                      the field type, and optionally, a length,
292
     *                      a precision and a nullable flag.
293
     */
294 102
    public function setDBFHeader(array $header): void
295
    {
296 102
        $this->dbfHeader = $header;
297
298 102
        $count = count($this->records);
299 102
        for ($i = 0; $i < $count; ++$i) {
300 6
            $this->records[$i]->updateDBFInfo($header);
301
        }
302 24
    }
303
304
    /**
305
     * Lookups value in the DBF file and returns index.
306
     *
307
     * @param string $field Field to match
308
     * @param mixed  $value Value to match
309
     */
310 8
    public function getIndexFromDBFData(string $field, $value): int
311
    {
312 8
        foreach ($this->records as $index => $record) {
313
            if (
314 8
                isset($record->dbfData[$field]) &&
315 8
                (trim(strtoupper($record->dbfData[$field])) === strtoupper($value))
316
            ) {
317 3
                return $index;
318
            }
319
        }
320
321 8
        return -1;
322
    }
323
324
    /**
325
     * Loads DBF metadata.
326
     */
327 44
    private function loadDBFHeader(): array
328
    {
329 44
        $DBFFile = fopen($this->getFilename('.dbf'), 'r');
330
331 44
        $result = [];
332 44
        $i = 1;
333 44
        $inHeader = true;
334
335 44
        while ($inHeader) {
336 44
            if (! feof($DBFFile)) {
337 44
                $buff32 = fread($DBFFile, 32);
338 44
                if ($i > 1) {
339 44
                    if (substr($buff32, 0, 1) === chr(13)) {
340 44
                        $inHeader = false;
341
                    } else {
342 44
                        $pos = strpos(substr($buff32, 0, 10), chr(0));
343 44
                        $pos = ($pos === false ? 10 : $pos);
344
345 44
                        $fieldName = substr($buff32, 0, $pos);
346 44
                        $fieldType = substr($buff32, 11, 1);
347 44
                        $fieldLen = ord(substr($buff32, 16, 1));
348 44
                        $fieldDec = ord(substr($buff32, 17, 1));
349
350 44
                        array_push($result, [$fieldName, $fieldType, $fieldLen, $fieldDec]);
351
                    }
352
                }
353
354 44
                ++$i;
355
            } else {
356
                $inHeader = false;
357
            }
358
        }
359
360 44
        fclose($DBFFile);
361
362 44
        return $result;
363
    }
364
365
    /**
366
     * Deletes record from the DBF file.
367
     */
368 2
    private function deleteRecordFromDBF(int $index): void
369
    {
370 2
        if ($this->dbfFile === null || ! @dbase_delete_record($this->dbfFile, $index)) {
0 ignored issues
show
introduced by
Function dbase_delete_record() should not be referenced via a fallback global name, but via a use statement.
Loading history...
Bug introduced by
The function dbase_delete_record was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

370
        if ($this->dbfFile === null || ! @/** @scrutinizer ignore-call */ dbase_delete_record($this->dbfFile, $index)) {
Loading history...
371 2
            return;
372
        }
373
374
        dbase_pack($this->dbfFile);
0 ignored issues
show
introduced by
Function dbase_pack() should not be referenced via a fallback global name, but via a use statement.
Loading history...
Bug introduced by
The function dbase_pack was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

374
        /** @scrutinizer ignore-call */ 
375
        dbase_pack($this->dbfFile);
Loading history...
375
    }
376
377
    /**
378
     * Loads SHP file metadata.
379
     */
380 170
    private function loadHeaders(): bool
381
    {
382 170
        if (Util::loadData('N', $this->readSHP(4)) !== self::MAGIC) {
383 12
            $this->setError('Not a SHP file (file code mismatch)');
384
385 12
            return false;
386
        }
387
388
        /* Skip 20 unused bytes */
389 158
        $this->readSHP(20);
390
391 158
        $this->fileLength = Util::loadData('N', $this->readSHP(4));
0 ignored issues
show
Documentation Bug introduced by
It seems like PhpMyAdmin\ShapeFile\Uti...'N', $this->readSHP(4)) can also be of type false. However, the property $fileLength is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
392
393
        /* We currently ignore version */
394 158
        $this->readSHP(4);
395
396 158
        $this->shapeType = Util::loadData('V', $this->readSHP(4));
397
398 158
        $this->boundingBox = [];
399 158
        $this->boundingBox['xmin'] = Util::loadData('d', $this->readSHP(8));
400 158
        $this->boundingBox['ymin'] = Util::loadData('d', $this->readSHP(8));
401 158
        $this->boundingBox['xmax'] = Util::loadData('d', $this->readSHP(8));
402 158
        $this->boundingBox['ymax'] = Util::loadData('d', $this->readSHP(8));
403 158
        $this->boundingBox['zmin'] = Util::loadData('d', $this->readSHP(8));
404 158
        $this->boundingBox['zmax'] = Util::loadData('d', $this->readSHP(8));
405 158
        $this->boundingBox['mmin'] = Util::loadData('d', $this->readSHP(8));
406 158
        $this->boundingBox['mmax'] = Util::loadData('d', $this->readSHP(8));
407
408 158
        if (self::supportsDbase()) {
409 44
            $this->dbfHeader = $this->loadDBFHeader();
410
        }
411
412 158
        return true;
413
    }
414
415
    /**
416
     * Saves bounding box record, possibly using 0 instead of not set values.
417
     *
418
     * @param resource $file File object
419
     * @param string   $type Bounding box dimension (eg. xmax, mmin...)
420
     */
421 110
    private function saveBBoxRecord($file, string $type): void
422
    {
423 110
        fwrite($file, Util::packDouble(
424 110
            $this->boundingBox[$type] ?? 0
425
        ));
426 26
    }
427
428
    /**
429
     * Saves bounding box to a file.
430
     *
431
     * @param resource $file File object
432
     */
433 110
    private function saveBBox($file): void
434
    {
435 110
        $this->saveBBoxRecord($file, 'xmin');
436 110
        $this->saveBBoxRecord($file, 'ymin');
437 110
        $this->saveBBoxRecord($file, 'xmax');
438 110
        $this->saveBBoxRecord($file, 'ymax');
439 110
        $this->saveBBoxRecord($file, 'zmin');
440 110
        $this->saveBBoxRecord($file, 'zmax');
441 110
        $this->saveBBoxRecord($file, 'mmin');
442 110
        $this->saveBBoxRecord($file, 'mmax');
443 26
    }
444
445
    /**
446
     * Saves SHP and SHX file metadata.
447
     */
448 110
    private function saveHeaders(): void
449
    {
450 110
        fwrite($this->shpFile, pack('NNNNNN', self::MAGIC, 0, 0, 0, 0, 0));
451 110
        fwrite($this->shpFile, pack('N', $this->fileLength));
452 110
        fwrite($this->shpFile, pack('V', 1000));
453 110
        fwrite($this->shpFile, pack('V', $this->shapeType));
454 110
        $this->saveBBox($this->shpFile);
455
456 110
        fwrite($this->shxFile, pack('NNNNNN', self::MAGIC, 0, 0, 0, 0, 0));
457 110
        fwrite($this->shxFile, pack('N', 50 + 4 * count($this->records)));
458 110
        fwrite($this->shxFile, pack('V', 1000));
459 110
        fwrite($this->shxFile, pack('V', $this->shapeType));
460 110
        $this->saveBBox($this->shxFile);
461 26
    }
462
463
    /**
464
     * Loads records from SHP file (and DBF).
465
     */
466 158
    private function loadRecords(): bool
467
    {
468
        /* Need to start at offset 100 */
469 158
        while (! $this->eofSHP()) {
470 158
            $record = new ShapeRecord(-1);
471 158
            $record->loadFromFile($this, $this->shpFile, $this->dbfFile);
472 158
            if ($record->lastError !== '') {
473
                $this->setError($record->lastError);
474
475
                return false;
476
            }
477
478 158
            if (($record->shapeType === false || $record->shapeType === '') && $this->eofSHP()) {
479 158
                break;
480
            }
481
482 158
            $this->records[] = $record;
483
        }
484
485 158
        return true;
486
    }
487
488
    /**
489
     * Saves records to SHP and SHX files.
490
     */
491 110
    private function saveRecords(): void
492
    {
493 110
        $offset = 50;
494 110
        if (! is_array($this->records) || (count($this->records) <= 0)) {
0 ignored issues
show
introduced by
The condition is_array($this->records) is always true.
Loading history...
495 8
            return;
496
        }
497
498 102
        foreach ($this->records as $index => $record) {
499
            //Save the record to the .shp file
500 102
            $record->saveToFile($this->shpFile, $this->dbfFile, $index + 1);
501
502
            //Save the record to the .shx file
503 102
            fwrite($this->shxFile, pack('N', $offset));
504 102
            fwrite($this->shxFile, pack('N', $record->getContentLength()));
505 102
            $offset += 4 + $record->getContentLength();
506
        }
507 24
    }
508
509
    /**
510
     * Generic interface to open files.
511
     *
512
     * @param bool   $toWrite   Whether file should be opened for writing
513
     * @param string $extension File extension
514
     * @param string $name      Verbose file name to report errors
515
     *
516
     * @return resource|false File handle
517
     */
518 194
    private function openFile(bool $toWrite, string $extension, string $name)
519
    {
520 194
        $shpName = $this->getFilename($extension);
521 194
        $result = @fopen($shpName, ($toWrite ? 'wb+' : 'rb'));
522 194
        if (! $result) {
0 ignored issues
show
introduced by
$result is of type false|resource, thus it always evaluated to false.
Loading history...
523 16
            $this->setError(sprintf('It wasn\'t possible to open the %s file "%s"', $name, $shpName));
524
525 16
            return false;
526
        }
527
528 178
        return $result;
529
    }
530
531
    /**
532
     * Opens SHP file.
533
     *
534
     * @param bool $toWrite Whether file should be opened for writing
535
     */
536 194
    private function openSHPFile(bool $toWrite = false): bool
537
    {
538 194
        $this->shpFile = $this->openFile($toWrite, '.shp', 'Shape');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->openFile($toWrite, '.shp', 'Shape') of type false is incompatible with the declared type null|resource of property $shpFile.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
539
540 194
        return (bool) $this->shpFile;
541
    }
542
543
    /**
544
     * Closes SHP file.
545
     */
546 178
    private function closeSHPFile(): void
547
    {
548 178
        if (! $this->shpFile) {
549 6
            return;
550
        }
551
552 172
        fclose($this->shpFile);
553 172
        $this->shpFile = null;
554 42
    }
555
556
    /**
557
     * Opens SHX file.
558
     *
559
     * @param bool $toWrite Whether file should be opened for writing
560
     */
561 110
    private function openSHXFile(bool $toWrite = false): bool
562
    {
563 110
        $this->shxFile = $this->openFile($toWrite, '.shx', 'Index');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->openFile($toWrite, '.shx', 'Index') of type false is incompatible with the declared type null|resource of property $shxFile.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
564
565 110
        return (bool) $this->shxFile;
566
    }
567
568
    /**
569
     * Closes SHX file.
570
     */
571 110
    private function closeSHXFile(): void
572
    {
573 110
        if (! $this->shxFile) {
574
            return;
575
        }
576
577 110
        fclose($this->shxFile);
578 110
        $this->shxFile = null;
579 26
    }
580
581
    /**
582
     * Creates DBF file.
583
     */
584 110
    private function createDBFFile(): bool
585
    {
586 110
        if (! self::supportsDbase() || ! is_array($this->dbfHeader) || count($this->dbfHeader) === 0) {
587 80
            $this->dbfFile = null;
588
589 80
            return true;
590
        }
591
592 30
        $dbfName = $this->getFilename('.dbf');
593
594
        /* Unlink existing file */
595 30
        if (file_exists($dbfName)) {
596 4
            unlink($dbfName);
597
        }
598
599
        /* Create new file */
600 30
        $this->dbfFile = @dbase_create($dbfName, $this->dbfHeader);
0 ignored issues
show
introduced by
Function dbase_create() should not be referenced via a fallback global name, but via a use statement.
Loading history...
Bug introduced by
The function dbase_create was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

600
        $this->dbfFile = @/** @scrutinizer ignore-call */ dbase_create($dbfName, $this->dbfHeader);
Loading history...
601 30
        if ($this->dbfFile === false) {
602
            $this->setError(sprintf('It wasn\'t possible to create the DBase file "%s"', $dbfName));
603
604
            return false;
605
        }
606
607 30
        return true;
608
    }
609
610
    /**
611
     * Loads DBF file if supported.
612
     */
613 178
    private function openDBFFile(): bool
614
    {
615 178
        if (! self::supportsDbase()) {
616 126
            $this->dbfFile = null;
617
618 126
            return true;
619
        }
620
621 52
        $dbfName = $this->getFilename('.dbf');
622 52
        if (! is_readable($dbfName)) {
623 6
            $this->setError(sprintf('It wasn\'t possible to find the DBase file "%s"', $dbfName));
624
625 6
            return false;
626
        }
627
628 46
        $this->dbfFile = @dbase_open($dbfName, 0);
0 ignored issues
show
Bug introduced by
The function dbase_open was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

628
        $this->dbfFile = @/** @scrutinizer ignore-call */ dbase_open($dbfName, 0);
Loading history...
introduced by
Function dbase_open() should not be referenced via a fallback global name, but via a use statement.
Loading history...
629 46
        if (! $this->dbfFile) {
630 2
            $this->setError(sprintf('It wasn\'t possible to open the DBase file "%s"', $dbfName));
631
632 2
            return false;
633
        }
634
635 44
        return true;
636
    }
637
638
    /**
639
     * Closes DBF file.
640
     */
641 178
    private function closeDBFFile(): void
642
    {
643 178
        if (! $this->dbfFile) {
644 134
            return;
645
        }
646
647 44
        dbase_close($this->dbfFile);
0 ignored issues
show
Bug introduced by
The function dbase_close was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

647
        /** @scrutinizer ignore-call */ 
648
        dbase_close($this->dbfFile);
Loading history...
introduced by
Function dbase_close() should not be referenced via a fallback global name, but via a use statement.
Loading history...
648 44
        $this->dbfFile = null;
649
    }
650
651
    /**
652
     * Sets error message.
653
     */
654 36
    public function setError(string $error): void
655
    {
656 36
        $this->lastError = $error;
657 8
    }
658
659
    /**
660
     * Reads given number of bytes from SHP file.
661
     *
662
     * @return string|false
663
     */
664 170
    public function readSHP(int $bytes)
665
    {
666 170
        if ($this->shpFile === null) {
667 6
            return false;
668
        }
669
670 164
        return fread($this->shpFile, $bytes);
671
    }
672
673
    /**
674
     * Checks whether file is at EOF.
675
     */
676 158
    public function eofSHP(): bool
677
    {
678 158
        return feof($this->shpFile);
679
    }
680
681
    /**
682
     * Returns shape name.
683
     */
684 8
    public function getShapeName(): string
685
    {
686 8
        return Util::nameShape($this->shapeType);
0 ignored issues
show
Bug introduced by
It seems like $this->shapeType can also be of type boolean; however, parameter $type of PhpMyAdmin\ShapeFile\Util::nameShape() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

686
        return Util::nameShape(/** @scrutinizer ignore-type */ $this->shapeType);
Loading history...
687
    }
688
689
    /**
690
     * Check whether file contains measure data.
691
     *
692
     * For some reason this is distinguished by zero bounding box in the
693
     * specification.
694
     */
695 64
    public function hasMeasure(): bool
696
    {
697
        // phpcs:ignore SlevomatCodingStandard.Operators.DisallowEqualOperators.DisallowedNotEqualOperator
698 64
        return $this->boundingBox['mmin'] != 0 || $this->boundingBox['mmax'] != 0;
699
    }
700
}
701