Passed
Push — master ( 28fcf3...e27c42 )
by William
02:20
created

ShapeFile::supportsDbase()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
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 191
    public static function supportsDbase(): bool
94
    {
95 191
        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 223
    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 223
        $this->shapeType = $shapeType;
114 223
        $this->boundingBox = $boundingBox;
115 223
        $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 223
        $this->fileLength = 50;
122 223
    }
123
124
    /**
125
     * Loads shapefile and dbase (if supported).
126
     *
127
     * @param string $fileName File mask to load (eg. example.*)
128
     */
129 199
    public function loadFromFile(string $fileName): bool
130
    {
131 199
        if (! empty($fileName)) {
132 191
            $this->fileName = $fileName;
133 191
            $result = $this->openSHPFile();
134
        } else {
135
            /* We operate on buffer emulated by readSHP / eofSHP */
136 8
            $result = true;
137
        }
138
139 199
        if ($result && ($this->openDBFFile())) {
140 171
            if (! $this->loadHeaders()) {
141 10
                $this->closeSHPFile();
142 10
                $this->closeDBFFile();
143
144 10
                return false;
145
            }
146
147 161
            if (! $this->loadRecords()) {
148
                $this->closeSHPFile();
149
                $this->closeDBFFile();
150
151
                return false;
152
            }
153
154 161
            $this->closeSHPFile();
155 161
            $this->closeDBFFile();
156
157 161
            return true;
158
        }
159
160 28
        return false;
161
    }
162
163
    /**
164
     * Saves shapefile.
165
     *
166
     * @param string|null $fileName Name of file, otherwise existing is used
167
     */
168 113
    public function saveToFile(?string $fileName = null): bool
169
    {
170 113
        if ($fileName !== null) {
171 113
            $this->fileName = $fileName;
172
        }
173
174 113
        if (! $this->openSHPFile(true) || (! $this->openSHXFile(true)) || (! $this->createDBFFile())) {
175
            return false;
176
        }
177
178 113
        $this->saveHeaders();
179 113
        $this->saveRecords();
180 113
        $this->closeSHPFile();
181 113
        $this->closeSHXFile();
182 113
        $this->closeDBFFile();
183
184 113
        return true;
185
    }
186
187
    /**
188
     * Generates filename with given extension.
189
     *
190
     * @param string $extension Extension to use (including dot)
191
     */
192 202
    private function getFilename(string $extension): string
193
    {
194 202
        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 105
    private function updateBBox(string $type, array $data): void
204
    {
205 105
        $min = $type . 'min';
206 105
        $max = $type . 'max';
207
208 105
        if (! isset($this->boundingBox[$min])
209 105
            || $this->boundingBox[$min] == 0.0
210 105
            || ($this->boundingBox[$min] > $data[$min])
211
        ) {
212 105
            $this->boundingBox[$min] = $data[$min];
213
        }
214
215 105
        if (isset($this->boundingBox[$max])
216 105
            && $this->boundingBox[$max] != 0.0
217 105
            && ($this->boundingBox[$max] >= $data[$max])
218
        ) {
219 9
            return;
220
        }
221
222 105
        $this->boundingBox[$max] = $data[$max];
223 105
    }
224
225
    /**
226
     * Adds record to shape file.
227
     *
228
     * @return int Number of added record
229
     */
230 105
    public function addRecord(ShapeRecord $record): int
231
    {
232 105
        if (isset($this->dbfHeader) && (is_array($this->dbfHeader))) {
233 99
            $record->updateDBFInfo($this->dbfHeader);
234
        }
235
236 105
        $this->fileLength += $record->getContentLength() + 4;
237 105
        $this->records[] = $record;
238 105
        $this->records[count($this->records) - 1]->recordNumber = count($this->records);
239
240 105
        $this->updateBBox('x', $record->shpData);
241 105
        $this->updateBBox('y', $record->shpData);
242
243 105
        if (in_array($this->shapeType, [11, 13, 15, 18, 21, 23, 25, 28])) {
244 64
            $this->updateBBox('m', $record->shpData);
245
        }
246
247 105
        if (in_array($this->shapeType, [11, 13, 15, 18])) {
248 32
            $this->updateBBox('z', $record->shpData);
249
        }
250
251 105
        return count($this->records) - 1;
252
    }
253
254
    /**
255
     * Deletes record from shapefile.
256
     */
257 3
    public function deleteRecord(int $index): void
258
    {
259 3
        if (! isset($this->records[$index])) {
260
            return;
261
        }
262
263 3
        $this->fileLength -= $this->records[$index]->getContentLength() + 4;
264 3
        $count = count($this->records) - 1;
265 3
        for ($i = $index; $i < $count; ++$i) {
266 3
            $this->records[$i] = $this->records[$i + 1];
267
        }
268
269 3
        unset($this->records[count($this->records) - 1]);
270 3
        $this->deleteRecordFromDBF($index);
271 3
    }
272
273
    /**
274
     * Returns array defining fields in DBF file.
275
     *
276
     * @return array|null see setDBFHeader for more information
277
     */
278 8
    public function getDBFHeader(): ?array
279
    {
280 8
        return $this->dbfHeader;
281
    }
282
283
    /**
284
     * Changes array defining fields in DBF file, used in dbase_create call.
285
     *
286
     * @param array $header An array of arrays, each array describing the
287
     *                      format of one field of the database. Each
288
     *                      field consists of a name, a character indicating
289
     *                      the field type, and optionally, a length,
290
     *                      a precision and a nullable flag.
291
     */
292 105
    public function setDBFHeader(array $header): void
293
    {
294 105
        $this->dbfHeader = $header;
295
296 105
        $count = count($this->records);
297 105
        for ($i = 0; $i < $count; ++$i) {
298 9
            $this->records[$i]->updateDBFInfo($header);
299
        }
300 105
    }
301
302
    /**
303
     * Lookups value in the DBF file and returns index.
304
     *
305
     * @param string $field Field to match
306
     * @param mixed  $value Value to match
307
     */
308 8
    public function getIndexFromDBFData(string $field, $value): int
309
    {
310 8
        foreach ($this->records as $index => $record) {
311 8
            if (isset($record->dbfData[$field]) &&
312 8
                (trim(strtoupper($record->dbfData[$field])) === strtoupper($value))
313
            ) {
314 4
                return $index;
315
            }
316
        }
317
318 8
        return -1;
319
    }
320
321
    /**
322
     * Loads DBF metadata.
323
     */
324 66
    private function loadDBFHeader(): array
325
    {
326 66
        $DBFFile = fopen($this->getFilename('.dbf'), 'r');
327
328 66
        $result = [];
329 66
        $i = 1;
330 66
        $inHeader = true;
331
332 66
        while ($inHeader) {
333 66
            if (! feof($DBFFile)) {
334 66
                $buff32 = fread($DBFFile, 32);
335 66
                if ($i > 1) {
336 66
                    if (substr($buff32, 0, 1) === chr(13)) {
337 66
                        $inHeader = false;
338
                    } else {
339 66
                        $pos = strpos(substr($buff32, 0, 10), chr(0));
340 66
                        $pos = ($pos === false ? 10 : $pos);
341
342 66
                        $fieldName = substr($buff32, 0, $pos);
343 66
                        $fieldType = substr($buff32, 11, 1);
344 66
                        $fieldLen = ord(substr($buff32, 16, 1));
345 66
                        $fieldDec = ord(substr($buff32, 17, 1));
346
347 66
                        array_push($result, [$fieldName, $fieldType, $fieldLen, $fieldDec]);
348
                    }
349
                }
350
351 66
                ++$i;
352
            } else {
353
                $inHeader = false;
354
            }
355
        }
356
357 66
        fclose($DBFFile);
358
359 66
        return $result;
360
    }
361
362
    /**
363
     * Deletes record from the DBF file.
364
     */
365 3
    private function deleteRecordFromDBF(int $index): void
366
    {
367 3
        if ($this->dbfFile === null || ! @dbase_delete_record($this->dbfFile, $index)) {
0 ignored issues
show
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

367
        if ($this->dbfFile === null || ! @/** @scrutinizer ignore-call */ dbase_delete_record($this->dbfFile, $index)) {
Loading history...
368 3
            return;
369
        }
370
371
        dbase_pack($this->dbfFile);
0 ignored issues
show
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

371
        /** @scrutinizer ignore-call */ 
372
        dbase_pack($this->dbfFile);
Loading history...
372
    }
373
374
    /**
375
     * Loads SHP file metadata.
376
     */
377 171
    private function loadHeaders(): bool
378
    {
379 171
        if (Util::loadData('N', $this->readSHP(4)) !== self::MAGIC) {
380 10
            $this->setError('Not a SHP file (file code mismatch)');
381
382 10
            return false;
383
        }
384
385
        /* Skip 20 unused bytes */
386 161
        $this->readSHP(20);
387
388 161
        $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...
389
390
        /* We currently ignore version */
391 161
        $this->readSHP(4);
392
393 161
        $this->shapeType = Util::loadData('V', $this->readSHP(4));
394
395 161
        $this->boundingBox = [];
396 161
        $this->boundingBox['xmin'] = Util::loadData('d', $this->readSHP(8));
397 161
        $this->boundingBox['ymin'] = Util::loadData('d', $this->readSHP(8));
398 161
        $this->boundingBox['xmax'] = Util::loadData('d', $this->readSHP(8));
399 161
        $this->boundingBox['ymax'] = Util::loadData('d', $this->readSHP(8));
400 161
        $this->boundingBox['zmin'] = Util::loadData('d', $this->readSHP(8));
401 161
        $this->boundingBox['zmax'] = Util::loadData('d', $this->readSHP(8));
402 161
        $this->boundingBox['mmin'] = Util::loadData('d', $this->readSHP(8));
403 161
        $this->boundingBox['mmax'] = Util::loadData('d', $this->readSHP(8));
404
405 161
        if (self::supportsDbase()) {
406 66
            $this->dbfHeader = $this->loadDBFHeader();
407
        }
408
409 161
        return true;
410
    }
411
412
    /**
413
     * Saves bounding box record, possibly using 0 instead of not set values.
414
     *
415
     * @param resource $file File object
416
     * @param string   $type Bounding box dimension (eg. xmax, mmin...)
417
     */
418 113
    private function saveBBoxRecord($file, string $type): void
419
    {
420 113
        fwrite($file, Util::packDouble(
421 113
            $this->boundingBox[$type] ?? 0
422
        ));
423 113
    }
424
425
    /**
426
     * Saves bounding box to a file.
427
     *
428
     * @param resource $file File object
429
     */
430 113
    private function saveBBox($file): void
431
    {
432 113
        $this->saveBBoxRecord($file, 'xmin');
433 113
        $this->saveBBoxRecord($file, 'ymin');
434 113
        $this->saveBBoxRecord($file, 'xmax');
435 113
        $this->saveBBoxRecord($file, 'ymax');
436 113
        $this->saveBBoxRecord($file, 'zmin');
437 113
        $this->saveBBoxRecord($file, 'zmax');
438 113
        $this->saveBBoxRecord($file, 'mmin');
439 113
        $this->saveBBoxRecord($file, 'mmax');
440 113
    }
441
442
    /**
443
     * Saves SHP and SHX file metadata.
444
     */
445 113
    private function saveHeaders(): void
446
    {
447 113
        fwrite($this->shpFile, pack('NNNNNN', self::MAGIC, 0, 0, 0, 0, 0));
448 113
        fwrite($this->shpFile, pack('N', $this->fileLength));
449 113
        fwrite($this->shpFile, pack('V', 1000));
450 113
        fwrite($this->shpFile, pack('V', $this->shapeType));
451 113
        $this->saveBBox($this->shpFile);
452
453 113
        fwrite($this->shxFile, pack('NNNNNN', self::MAGIC, 0, 0, 0, 0, 0));
454 113
        fwrite($this->shxFile, pack('N', 50 + 4 * count($this->records)));
455 113
        fwrite($this->shxFile, pack('V', 1000));
456 113
        fwrite($this->shxFile, pack('V', $this->shapeType));
457 113
        $this->saveBBox($this->shxFile);
458 113
    }
459
460
    /**
461
     * Loads records from SHP file (and DBF).
462
     */
463 161
    private function loadRecords(): bool
464
    {
465
        /* Need to start at offset 100 */
466 161
        while (! $this->eofSHP()) {
467 161
            $record = new ShapeRecord(-1);
468 161
            $record->loadFromFile($this, $this->shpFile, $this->dbfFile);
469 161
            if ($record->lastError !== '') {
470
                $this->setError($record->lastError);
471
472
                return false;
473
            }
474
475 161
            if (($record->shapeType === false || $record->shapeType === '') && $this->eofSHP()) {
476 161
                break;
477
            }
478
479 161
            $this->records[] = $record;
480
        }
481
482 161
        return true;
483
    }
484
485
    /**
486
     * Saves records to SHP and SHX files.
487
     */
488 113
    private function saveRecords(): void
489
    {
490 113
        $offset = 50;
491 113
        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...
492 8
            return;
493
        }
494
495 105
        foreach ($this->records as $index => $record) {
496
            //Save the record to the .shp file
497 105
            $record->saveToFile($this->shpFile, $this->dbfFile, $index + 1);
498
499
            //Save the record to the .shx file
500 105
            fwrite($this->shxFile, pack('N', $offset));
501 105
            fwrite($this->shxFile, pack('N', $record->getContentLength()));
502 105
            $offset += 4 + $record->getContentLength();
503
        }
504 105
    }
505
506
    /**
507
     * Generic interface to open files.
508
     *
509
     * @param bool   $toWrite   Whether file should be opened for writing
510
     * @param string $extension File extension
511
     * @param string $name      Verbose file name to report errors
512
     *
513
     * @return resource|false File handle
514
     */
515 199
    private function openFile(bool $toWrite, string $extension, string $name)
516
    {
517 199
        $shpName = $this->getFilename($extension);
518 199
        $result = @fopen($shpName, ($toWrite ? 'wb+' : 'rb'));
519 199
        if (! $result) {
0 ignored issues
show
introduced by
$result is of type false|resource, thus it always evaluated to false.
Loading history...
520 16
            $this->setError(sprintf('It wasn\'t possible to open the %s file "%s"', $name, $shpName));
521
522 16
            return false;
523
        }
524
525 183
        return $result;
526
    }
527
528
    /**
529
     * Opens SHP file.
530
     *
531
     * @param bool $toWrite Whether file should be opened for writing
532
     */
533 199
    private function openSHPFile(bool $toWrite = false): bool
534
    {
535 199
        $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...
536
537 199
        return (bool) $this->shpFile;
538
    }
539
540
    /**
541
     * Closes SHP file.
542
     */
543 179
    private function closeSHPFile(): void
544
    {
545 179
        if (! $this->shpFile) {
546 5
            return;
547
        }
548
549 174
        fclose($this->shpFile);
550 174
        $this->shpFile = null;
551 174
    }
552
553
    /**
554
     * Opens SHX file.
555
     *
556
     * @param bool $toWrite Whether file should be opened for writing
557
     */
558 113
    private function openSHXFile(bool $toWrite = false): bool
559
    {
560 113
        $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...
561
562 113
        return (bool) $this->shxFile;
563
    }
564
565
    /**
566
     * Closes SHX file.
567
     */
568 113
    private function closeSHXFile(): void
569
    {
570 113
        if (! $this->shxFile) {
571
            return;
572
        }
573
574 113
        fclose($this->shxFile);
575 113
        $this->shxFile = null;
576 113
    }
577
578
    /**
579
     * Creates DBF file.
580
     */
581 113
    private function createDBFFile(): bool
582
    {
583 113
        if (! self::supportsDbase() || ! is_array($this->dbfHeader) || count($this->dbfHeader) === 0) {
584 68
            $this->dbfFile = null;
585
586 68
            return true;
587
        }
588
589 45
        $dbfName = $this->getFilename('.dbf');
590
591
        /* Unlink existing file */
592 45
        if (file_exists($dbfName)) {
593 6
            unlink($dbfName);
594
        }
595
596
        /* Create new file */
597 45
        $this->dbfFile = @dbase_create($dbfName, $this->dbfHeader);
0 ignored issues
show
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

597
        $this->dbfFile = @/** @scrutinizer ignore-call */ dbase_create($dbfName, $this->dbfHeader);
Loading history...
598 45
        if ($this->dbfFile === false) {
599
            $this->setError(sprintf('It wasn\'t possible to create the DBase file "%s"', $dbfName));
600
601
            return false;
602
        }
603
604 45
        return true;
605
    }
606
607
    /**
608
     * Loads DBF file if supported.
609
     */
610 183
    private function openDBFFile(): bool
611
    {
612 183
        if (! self::supportsDbase()) {
613 105
            $this->dbfFile = null;
614
615 105
            return true;
616
        }
617
618 78
        $dbfName = $this->getFilename('.dbf');
619 78
        if (! is_readable($dbfName)) {
620 9
            $this->setError(sprintf('It wasn\'t possible to find the DBase file "%s"', $dbfName));
621
622 9
            return false;
623
        }
624
625 69
        $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

625
        $this->dbfFile = @/** @scrutinizer ignore-call */ dbase_open($dbfName, 0);
Loading history...
626 69
        if (! $this->dbfFile) {
627 3
            $this->setError(sprintf('It wasn\'t possible to open the DBase file "%s"', $dbfName));
628
629 3
            return false;
630
        }
631
632 66
        return true;
633
    }
634
635
    /**
636
     * Closes DBF file.
637
     */
638 179
    private function closeDBFFile(): void
639
    {
640 179
        if (! $this->dbfFile) {
641 113
            return;
642
        }
643
644 66
        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

644
        /** @scrutinizer ignore-call */ 
645
        dbase_close($this->dbfFile);
Loading history...
645 66
        $this->dbfFile = null;
646 66
    }
647
648
    /**
649
     * Sets error message.
650
     */
651 38
    public function setError(string $error): void
652
    {
653 38
        $this->lastError = $error;
654 38
    }
655
656
    /**
657
     * Reads given number of bytes from SHP file.
658
     *
659
     * @return string|false
660
     */
661 171
    public function readSHP(int $bytes)
662
    {
663 171
        if ($this->shpFile === null) {
664 5
            return false;
665
        }
666
667 166
        return fread($this->shpFile, $bytes);
668
    }
669
670
    /**
671
     * Checks whether file is at EOF.
672
     */
673 161
    public function eofSHP(): bool
674
    {
675 161
        return feof($this->shpFile);
676
    }
677
678
    /**
679
     * Returns shape name.
680
     */
681 8
    public function getShapeName(): string
682
    {
683 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

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