Passed
Push — master ( 5f09f0...990103 )
by William
18:42 queued 16:08
created

ShapeFile::saveBBoxRecord()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 4
ccs 3
cts 3
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 */
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 201
    public static function supportsDbase(): bool
94
    {
95 201
        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 mixed|null $fileName    File name
102
     */
103 225
    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
        $fileName = null
112
    ) {
113 225
        $this->shapeType = $shapeType;
114 225
        $this->boundingBox = $boundingBox;
115 225
        $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 225
        $this->fileLength = 50;
122 225
    }
123
124
    /**
125
     * Loads shapefile and dbase (if supported).
126
     *
127
     * @param string $fileName File mask to load (eg. example.*)
128
     */
129 209
    public function loadFromFile(string $fileName): bool
130
    {
131 209
        if (! empty($fileName)) {
132 201
            $this->fileName = $fileName;
133 201
            $result = $this->openSHPFile();
134
        } else {
135
            /* We operate on buffer emulated by readSHP / eofSHP */
136 8
            $result = true;
137
        }
138
139 209
        if ($result && ($this->openDBFFile())) {
140 173
            if (! $this->loadHeaders()) {
141 6
                $this->closeSHPFile();
142 6
                $this->closeDBFFile();
143
144 6
                return false;
145
            }
146
147 167
            if (! $this->loadRecords()) {
148
                $this->closeSHPFile();
149
                $this->closeDBFFile();
150
151
                return false;
152
            }
153
154 167
            $this->closeSHPFile();
155 167
            $this->closeDBFFile();
156
157 167
            return true;
158
        }
159
160 36
        return false;
161
    }
162
163
    /**
164
     * Saves shapefile.
165
     *
166
     * @param string|null $fileName Name of file, otherwise existing is used
167
     */
168 119
    public function saveToFile(?string $fileName = null): bool
169
    {
170 119
        if ($fileName !== null) {
171 119
            $this->fileName = $fileName;
172
        }
173
174 119
        if (! $this->openSHPFile(true) || (! $this->openSHXFile(true)) || (! $this->createDBFFile())) {
175
            return false;
176
        }
177
178 119
        $this->saveHeaders();
179 119
        $this->saveRecords();
180 119
        $this->closeSHPFile();
181 119
        $this->closeSHXFile();
182 119
        $this->closeDBFFile();
183
184 119
        return true;
185
    }
186
187
    /**
188
     * Generates filename with given extension.
189
     *
190
     * @param string $extension Extension to use (including dot)
191
     */
192 214
    private function getFilename(string $extension): string
193
    {
194 214
        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 111
    private function updateBBox(string $type, array $data): void
204
    {
205 111
        $min = $type . 'min';
206 111
        $max = $type . 'max';
207
208 111
        if (! isset($this->boundingBox[$min])
209 111
            || $this->boundingBox[$min] == 0.0
210 111
            || ($this->boundingBox[$min] > $data[$min])
211
        ) {
212 111
            $this->boundingBox[$min] = $data[$min];
213
        }
214
215 111
        if (isset($this->boundingBox[$max])
216 111
            && $this->boundingBox[$max] != 0.0
217 111
            && ($this->boundingBox[$max] >= $data[$max])
218
        ) {
219 15
            return;
220
        }
221
222 111
        $this->boundingBox[$max] = $data[$max];
223 111
    }
224
225
    /**
226
     * Adds record to shape file.
227
     *
228
     * @return int Number of added record
229
     */
230 111
    public function addRecord(ShapeRecord $record): int
231
    {
232 111
        if (isset($this->dbfHeader) && (is_array($this->dbfHeader))) {
233 101
            $record->updateDBFInfo($this->dbfHeader);
234
        }
235
236 111
        $this->fileLength += $record->getContentLength() + 4;
237 111
        $this->records[] = $record;
238 111
        $this->records[count($this->records) - 1]->recordNumber = count($this->records);
239
240 111
        $this->updateBBox('x', $record->shpData);
241 111
        $this->updateBBox('y', $record->shpData);
242
243 111
        if (in_array($this->shapeType, [11, 13, 15, 18, 21, 23, 25, 28])) {
244 64
            $this->updateBBox('m', $record->shpData);
245
        }
246
247 111
        if (in_array($this->shapeType, [11, 13, 15, 18])) {
248 32
            $this->updateBBox('z', $record->shpData);
249
        }
250
251 111
        return count($this->records) - 1;
252
    }
253
254
    /**
255
     * Deletes record from shapefile.
256
     */
257 5
    public function deleteRecord(int $index): void
258
    {
259 5
        if (! isset($this->records[$index])) {
260
            return;
261
        }
262
263 5
        $this->fileLength -= $this->records[$index]->getContentLength() + 4;
264 5
        $count = count($this->records) - 1;
265 5
        for ($i = $index; $i < $count; ++$i) {
266 5
            $this->records[$i] = $this->records[$i + 1];
267
        }
268
269 5
        unset($this->records[count($this->records) - 1]);
270 5
        $this->deleteRecordFromDBF($index);
271 5
    }
272
273
    /**
274
     * Returns array defining fields in DBF file.
275
     *
276
     * @return array see setDBFHeader for more information
277
     */
278
    public function getDBFHeader(): array
279
    {
280
        return $this->dbfHeader;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->dbfHeader could return the type null which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
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 111
    public function setDBFHeader(array $header): void
293
    {
294 111
        $this->dbfHeader = $header;
295
296 111
        $count = count($this->records);
297 111
        for ($i = 0; $i < $count; ++$i) {
298 15
            $this->records[$i]->updateDBFInfo($header);
299
        }
300 111
    }
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 6
                return $index;
315
            }
316
        }
317
318 8
        return -1;
319
    }
320
321
    /**
322
     * Loads DBF metadata.
323
     */
324 110
    private function loadDBFHeader(): array
325
    {
326 110
        $DBFFile = fopen($this->getFilename('.dbf'), 'r');
327
328 110
        $result = [];
329 110
        $i = 1;
330 110
        $inHeader = true;
331
332 110
        while ($inHeader) {
333 110
            if (! feof($DBFFile)) {
334 110
                $buff32 = fread($DBFFile, 32);
335 110
                if ($i > 1) {
336 110
                    if (substr($buff32, 0, 1) === chr(13)) {
337 110
                        $inHeader = false;
338
                    } else {
339 110
                        $pos = strpos(substr($buff32, 0, 10), chr(0));
340 110
                        $pos = ($pos === false ? 10 : $pos);
341
342 110
                        $fieldName = substr($buff32, 0, $pos);
343 110
                        $fieldType = substr($buff32, 11, 1);
344 110
                        $fieldLen = ord(substr($buff32, 16, 1));
345 110
                        $fieldDec = ord(substr($buff32, 17, 1));
346
347 110
                        array_push($result, [$fieldName, $fieldType, $fieldLen, $fieldDec]);
348
                    }
349
                }
350
351 110
                ++$i;
352
            } else {
353
                $inHeader = false;
354
            }
355
        }
356
357 110
        fclose($DBFFile);
358
359 110
        return $result;
360
    }
361
362
    /**
363
     * Deletes record from the DBF file.
364
     */
365 5
    private function deleteRecordFromDBF(int $index): void
366
    {
367 5
        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 5
            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 173
    private function loadHeaders(): bool
378
    {
379 173
        if (Util::loadData('N', $this->readSHP(4)) !== self::MAGIC) {
380 6
            $this->setError('Not a SHP file (file code mismatch)');
381
382 6
            return false;
383
        }
384
385
        /* Skip 20 unused bytes */
386 167
        $this->readSHP(20);
387
388 167
        $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 167
        $this->readSHP(4);
392
393 167
        $this->shapeType = Util::loadData('V', $this->readSHP(4));
394
395 167
        $this->boundingBox = [];
396 167
        $this->boundingBox['xmin'] = Util::loadData('d', $this->readSHP(8));
397 167
        $this->boundingBox['ymin'] = Util::loadData('d', $this->readSHP(8));
398 167
        $this->boundingBox['xmax'] = Util::loadData('d', $this->readSHP(8));
399 167
        $this->boundingBox['ymax'] = Util::loadData('d', $this->readSHP(8));
400 167
        $this->boundingBox['zmin'] = Util::loadData('d', $this->readSHP(8));
401 167
        $this->boundingBox['zmax'] = Util::loadData('d', $this->readSHP(8));
402 167
        $this->boundingBox['mmin'] = Util::loadData('d', $this->readSHP(8));
403 167
        $this->boundingBox['mmax'] = Util::loadData('d', $this->readSHP(8));
404
405 167
        if (self::supportsDbase()) {
406 110
            $this->dbfHeader = $this->loadDBFHeader();
407
        }
408
409 167
        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 119
    private function saveBBoxRecord($file, string $type): void
419
    {
420 119
        fwrite($file, Util::packDouble(
421 119
            $this->boundingBox[$type] ?? 0
422
        ));
423 119
    }
424
425
    /**
426
     * Saves bounding box to a file.
427
     *
428
     * @param resource $file File object
429
     */
430 119
    private function saveBBox($file): void
431
    {
432 119
        $this->saveBBoxRecord($file, 'xmin');
433 119
        $this->saveBBoxRecord($file, 'ymin');
434 119
        $this->saveBBoxRecord($file, 'xmax');
435 119
        $this->saveBBoxRecord($file, 'ymax');
436 119
        $this->saveBBoxRecord($file, 'zmin');
437 119
        $this->saveBBoxRecord($file, 'zmax');
438 119
        $this->saveBBoxRecord($file, 'mmin');
439 119
        $this->saveBBoxRecord($file, 'mmax');
440 119
    }
441
442
    /**
443
     * Saves SHP and SHX file metadata.
444
     */
445 119
    private function saveHeaders(): void
446
    {
447 119
        fwrite($this->shpFile, pack('NNNNNN', self::MAGIC, 0, 0, 0, 0, 0));
448 119
        fwrite($this->shpFile, pack('N', $this->fileLength));
449 119
        fwrite($this->shpFile, pack('V', 1000));
450 119
        fwrite($this->shpFile, pack('V', $this->shapeType));
451 119
        $this->saveBBox($this->shpFile);
452
453 119
        fwrite($this->shxFile, pack('NNNNNN', self::MAGIC, 0, 0, 0, 0, 0));
454 119
        fwrite($this->shxFile, pack('N', 50 + 4 * count($this->records)));
455 119
        fwrite($this->shxFile, pack('V', 1000));
456 119
        fwrite($this->shxFile, pack('V', $this->shapeType));
457 119
        $this->saveBBox($this->shxFile);
458 119
    }
459
460
    /**
461
     * Loads records from SHP file (and DBF).
462
     */
463 167
    private function loadRecords(): bool
464
    {
465
        /* Need to start at offset 100 */
466 167
        while (! $this->eofSHP()) {
467 167
            $record = new ShapeRecord(-1);
468 167
            $record->loadFromFile($this, $this->shpFile, $this->dbfFile);
469 167
            if ($record->lastError !== '') {
470
                $this->setError($record->lastError);
471
472
                return false;
473
            }
474
475 167
            if (($record->shapeType === false || $record->shapeType === '') && $this->eofSHP()) {
476 167
                break;
477
            }
478
479 167
            $this->records[] = $record;
480
        }
481
482 167
        return true;
483
    }
484
485
    /**
486
     * Saves records to SHP and SHX files.
487
     */
488 119
    private function saveRecords(): void
489
    {
490 119
        $offset = 50;
491 119
        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 111
        foreach ($this->records as $index => $record) {
496
            //Save the record to the .shp file
497 111
            $record->saveToFile($this->shpFile, $this->dbfFile, $index + 1);
498
499
            //Save the record to the .shx file
500 111
            fwrite($this->shxFile, pack('N', $offset));
501 111
            fwrite($this->shxFile, pack('N', $record->getContentLength()));
502 111
            $offset += 4 + $record->getContentLength();
503
        }
504 111
    }
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 209
    private function openFile(bool $toWrite, string $extension, string $name)
516
    {
517 209
        $shpName = $this->getFilename($extension);
518 209
        $result = @fopen($shpName, ($toWrite ? 'wb+' : 'rb'));
519 209
        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 193
        return $result;
526
    }
527
528
    /**
529
     * Opens SHP file.
530
     *
531
     * @param bool $toWrite Whether file should be opened for writing
532
     */
533 209
    private function openSHPFile(bool $toWrite = false): bool
534
    {
535 209
        $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 209
        return (bool) $this->shpFile;
538
    }
539
540
    /**
541
     * Closes SHP file.
542
     */
543 181
    private function closeSHPFile(): void
544
    {
545 181
        if (! $this->shpFile) {
546 3
            return;
547
        }
548
549 178
        fclose($this->shpFile);
550 178
        $this->shpFile = null;
551 178
    }
552
553
    /**
554
     * Opens SHX file.
555
     *
556
     * @param bool $toWrite Whether file should be opened for writing
557
     */
558 119
    private function openSHXFile(bool $toWrite = false): bool
559
    {
560 119
        $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 119
        return (bool) $this->shxFile;
563
    }
564
565
    /**
566
     * Closes SHX file.
567
     */
568 119
    private function closeSHXFile(): void
569
    {
570 119
        if (! $this->shxFile) {
571
            return;
572
        }
573
574 119
        fclose($this->shxFile);
575 119
        $this->shxFile = null;
576 119
    }
577
578
    /**
579
     * Creates DBF file.
580
     */
581 119
    private function createDBFFile(): bool
582
    {
583 119
        if (! self::supportsDbase() || ! is_array($this->dbfHeader) || count($this->dbfHeader) === 0) {
584 44
            $this->dbfFile = null;
585
586 44
            return true;
587
        }
588
589 75
        $dbfName = $this->getFilename('.dbf');
590
591
        /* Unlink existing file */
592 75
        if (file_exists($dbfName)) {
593 10
            unlink($dbfName);
594
        }
595
596
        /* Create new file */
597 75
        $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 75
        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 75
        return true;
605
    }
606
607
    /**
608
     * Loads DBF file if supported.
609
     */
610 193
    private function openDBFFile(): bool
611
    {
612 193
        if (! self::supportsDbase()) {
613 63
            $this->dbfFile = null;
614
615 63
            return true;
616
        }
617
618 130
        $dbfName = $this->getFilename('.dbf');
619 130
        if (! is_readable($dbfName)) {
620 15
            $this->setError(sprintf('It wasn\'t possible to find the DBase file "%s"', $dbfName));
621
622 15
            return false;
623
        }
624
625 115
        $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 115
        if (! $this->dbfFile) {
627 5
            $this->setError(sprintf('It wasn\'t possible to open the DBase file "%s"', $dbfName));
628
629 5
            return false;
630
        }
631
632 110
        return true;
633
    }
634
635
    /**
636
     * Closes DBF file.
637
     */
638 181
    private function closeDBFFile(): void
639
    {
640 181
        if (! $this->dbfFile) {
641 71
            return;
642
        }
643
644 110
        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 110
        $this->dbfFile = null;
646 110
    }
647
648
    /**
649
     * Sets error message.
650
     */
651 42
    public function setError(string $error): void
652
    {
653 42
        $this->lastError = $error;
654 42
    }
655
656
    /**
657
     * Reads given number of bytes from SHP file.
658
     *
659
     * @return string|false
660
     */
661 173
    public function readSHP(int $bytes)
662
    {
663 173
        if ($this->shpFile === null) {
664 3
            return false;
665
        }
666
667 170
        return fread($this->shpFile, $bytes);
668
    }
669
670
    /**
671
     * Checks whether file is at EOF.
672
     */
673 167
    public function eofSHP(): bool
674
    {
675 167
        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