• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

adriansuter / php-autoload-override / 12951325128

24 Jan 2025 02:10PM UTC coverage: 93.235% (-5.3%) from 98.529%
12951325128

push

github

adriansuter
Update phpunit.

317 of 340 relevant lines covered (93.24%)

3.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.02
/src/FileStreamWrapper.php
1
<?php
2

3
/**
4
 * PHP Autoload Override (https://github.com/adriansuter/php-autoload-override)
5
 *
6
 * @license https://github.com/adriansuter/php-autoload-override/blob/master/LICENSE.md (MIT License)
7
 */
8

9
declare(strict_types=1);
10

11
namespace AdrianSuter\Autoload\Override;
12

13
use InvalidArgumentException;
14
use RuntimeException;
15

16
use function chgrp;
17
use function chmod;
18
use function chown;
19
use function closedir;
20
use function fclose;
21
use function feof;
22
use function fflush;
23
use function fgets;
24
use function file_get_contents;
25
use function fopen;
26
use function fseek;
27
use function fstat;
28
use function ftruncate;
29
use function fwrite;
30
use function is_int;
31
use function is_null;
32
use function is_resource;
33
use function is_string;
34
use function lstat;
35
use function mkdir;
36
use function opendir;
37
use function readdir;
38
use function rename;
39
use function rewinddir;
40
use function rmdir;
41
use function stat;
42
use function stream_set_blocking;
43
use function stream_set_timeout;
44
use function stream_set_write_buffer;
45
use function stream_wrapper_register;
46
use function stream_wrapper_restore;
47
use function stream_wrapper_unregister;
48
use function touch;
49
use function unlink;
50

51
// phpcs:disable PSR1.Methods.CamelCapsMethodName
52
class FileStreamWrapper
53
{
54
    /**
55
     * @var resource|null
56
     */
57
    public $context;
58

59
    /**
60
     * @var resource|null|false
61
     */
62
    private $resource;
63

64
    /**
65
     * Close directory handle.
66
     *
67
     * @return bool
68
     */
69
    public function dir_closedir(): bool
70
    {
71
        @stream_wrapper_restore('file');
2✔
72

73
        if (is_resource($this->resource)) {
2✔
74
            closedir($this->resource);
2✔
75
        }
76

77
        stream_wrapper_unregister('file');
2✔
78
        stream_wrapper_register('file', self::class);
2✔
79

80
        return true;
2✔
81
    }
82

83
    /**
84
     * Open directory handle.
85
     *
86
     * @param string $path
87
     * @param int    $options
88
     *
89
     * @return bool
90
     * @noinspection PhpUnusedParameterInspection
91
     */
92
    public function dir_opendir(string $path, int $options): bool
93
    {
94
        @stream_wrapper_restore('file');
2✔
95

96
        if (is_resource($this->context)) {
2✔
97
            $this->resource = opendir($path, $this->context);
1✔
98
        } else {
99
            $this->resource = opendir($path);
1✔
100
        }
101

102
        stream_wrapper_unregister('file');
2✔
103
        stream_wrapper_register('file', self::class);
2✔
104

105
        return is_resource($this->resource);
2✔
106
    }
107

108
    /**
109
     * Read entry from directory handle.
110
     *
111
     * @return false|string
112
     * @noinspection PhpUnused
113
     */
114
    public function dir_readdir()
115
    {
116
        @stream_wrapper_restore('file');
1✔
117

118
        $r = false;
1✔
119
        if (is_resource($this->resource)) {
1✔
120
            $r = readdir($this->resource);
1✔
121
        }
122

123
        stream_wrapper_unregister('file');
1✔
124
        stream_wrapper_register('file', self::class);
1✔
125

126
        return $r;
1✔
127
    }
128

129
    /**
130
     * Rewind directory handle.
131
     *
132
     * @return bool
133
     * @noinspection PhpUnused
134
     */
135
    public function dir_rewinddir(): bool
136
    {
137
        @stream_wrapper_restore('file');
1✔
138

139
        if (is_resource($this->resource)) {
1✔
140
            rewinddir($this->resource);
1✔
141
        }
142

143
        stream_wrapper_unregister('file');
1✔
144
        stream_wrapper_register('file', self::class);
1✔
145

146
        return true;
1✔
147
    }
148

149
    /**
150
     * Create a directory.
151
     *
152
     * @param string $path
153
     * @param int    $mode
154
     * @param int    $options
155
     *
156
     * @return bool
157
     */
158
    public function mkdir(string $path, int $mode, int $options): bool
159
    {
160
        @stream_wrapper_restore('file');
2✔
161

162
        $recursive = $options & STREAM_MKDIR_RECURSIVE ? true : false;
2✔
163
        if (is_resource($this->context)) {
2✔
164
            $r = mkdir($path, $mode, $recursive, $this->context);
1✔
165
        } else {
166
            $r = mkdir($path, $mode, $recursive);
1✔
167
        }
168

169
        stream_wrapper_unregister('file');
2✔
170
        stream_wrapper_register('file', self::class);
2✔
171

172
        return $r;
2✔
173
    }
174

175
    /**
176
     * Rename a file or directory.
177
     *
178
     * @param string $path_from
179
     * @param string $path_to
180
     *
181
     * @return bool
182
     */
183
    public function rename(string $path_from, string $path_to): bool
184
    {
185
        @stream_wrapper_restore('file');
2✔
186

187
        if (is_resource($this->context)) {
2✔
188
            $r = rename($path_from, $path_to, $this->context);
1✔
189
        } else {
190
            $r = rename($path_from, $path_to);
1✔
191
        }
192

193
        stream_wrapper_unregister('file');
2✔
194
        stream_wrapper_register('file', self::class);
2✔
195

196
        return $r;
2✔
197
    }
198

199
    /**
200
     * Remove a directory.
201
     *
202
     * @param string $path
203
     * @param int    $options
204
     *
205
     * @return bool
206
     * @noinspection PhpUnusedParameterInspection
207
     */
208
    public function rmdir(string $path, int $options): bool
209
    {
210
        @stream_wrapper_restore('file');
2✔
211

212
        if (is_resource($this->context)) {
2✔
213
            $r = rmdir($path, $this->context);
1✔
214
        } else {
215
            $r = rmdir($path);
1✔
216
        }
217

218
        stream_wrapper_unregister('file');
2✔
219
        stream_wrapper_register('file', self::class);
2✔
220

221
        return $r;
2✔
222
    }
223

224
    /**
225
     * Retrieve the underlying resource.
226
     *
227
     * @param int $cast_as
228
     *
229
     * @return false|resource
230
     * @noinspection PhpUnusedParameterInspection
231
     */
232
    public function stream_cast(int $cast_as)
233
    {
234
        if (is_resource($this->resource)) {
1✔
235
            return $this->resource;
1✔
236
        }
237

238
        return false;
1✔
239
    }
240

241
    /**
242
     * Close a resource.
243
     *
244
     * @noinspection PhpUnused
245
     */
246
    public function stream_close(): void
247
    {
248
        @stream_wrapper_restore('file');
7✔
249

250
        if (is_resource($this->resource)) {
7✔
251
            fclose($this->resource);
7✔
252
        }
253

254
        stream_wrapper_unregister('file');
7✔
255
        stream_wrapper_register('file', self::class);
7✔
256
    }
257

258
    /**
259
     * Test for end-of-file on a file pointer.
260
     *
261
     * @return bool
262
     * @noinspection PhpUnused
263
     */
264
    public function stream_eof(): bool
265
    {
266
        @stream_wrapper_restore('file');
2✔
267

268
        $r = false;
2✔
269
        if (is_resource($this->resource)) {
2✔
270
            $r = feof($this->resource);
2✔
271
        }
272

273
        stream_wrapper_unregister('file');
2✔
274
        stream_wrapper_register('file', self::class);
2✔
275

276
        return $r;
2✔
277
    }
278

279
    /**
280
     * Flush the output
281
     *
282
     * @return bool
283
     * @noinspection PhpUnused
284
     */
285
    public function stream_flush(): bool
286
    {
287
        @stream_wrapper_restore('file');
2✔
288

289
        $r = false;
2✔
290
        if (is_resource($this->resource)) {
2✔
291
            $r = fflush($this->resource);
2✔
292
        }
293

294
        stream_wrapper_unregister('file');
2✔
295
        stream_wrapper_register('file', self::class);
2✔
296

297
        return $r;
2✔
298
    }
299

300
    /**
301
     * Advisory file locking.
302
     *
303
     * @param int $operation
304
     *
305
     * @return bool
306
     * @noinspection PhpUnused
307
     * @noinspection PhpUnusedParameterInspection
308
     */
309
    public function stream_lock(int $operation): bool
310
    {
311
        return false;
1✔
312
    }
313

314
    /**
315
     * Change stream metadata.
316
     *
317
     * @param string                     $path
318
     * @param int                        $option
319
     * @param array<int|null>|string|int $value
320
     *
321
     * @return bool
322
     * @noinspection PhpUnused
323
     */
324
    public function stream_metadata(string $path, int $option, $value): bool
325
    {
326
        @stream_wrapper_restore('file');
7✔
327

328
        $r = false;
7✔
329
        switch ($option) {
330
            case STREAM_META_TOUCH:
7✔
331
                /** @var array<int|null> $value */
332
                /** @phpstan-ignore-next-line */
333
                if (!isset($value[0]) || is_null($value[0])) {
1✔
334
                    $r = touch($path);
1✔
335
                } else {
336
                    $r = touch($path, (int)$value[0], (int)$value[1]);
1✔
337
                }
338
                break;
1✔
339

340
            case STREAM_META_OWNER_NAME:
6✔
341
            case STREAM_META_OWNER:
6✔
342
                if (!is_int($value) && !is_string($value)) {
2✔
343
                    throw new InvalidArgumentException('Parameter #3 is expected to be an `int|string`.');
1✔
344
                }
345
                $r = chown($path, $value);
1✔
346
                break;
1✔
347

348
            case STREAM_META_GROUP_NAME:
4✔
349
            case STREAM_META_GROUP:
4✔
350
                if (!is_int($value) && !is_string($value)) {
2✔
351
                    throw new InvalidArgumentException('Parameter #3 is expected to be an `int|string`.');
1✔
352
                }
353
                $r = chgrp($path, $value);
1✔
354
                break;
1✔
355

356
            case STREAM_META_ACCESS:
2✔
357
                if (!is_int($value)) {
2✔
358
                    throw new InvalidArgumentException('Parameter #3 is expected to be an `int`.');
1✔
359
                }
360
                $r = chmod($path, $value);
1✔
361
                break;
1✔
362
        }
363

364
        stream_wrapper_unregister('file');
4✔
365
        stream_wrapper_register('file', self::class);
4✔
366

367
        return $r;
4✔
368
    }
369

370
    /**
371
     * Open file or URL.
372
     *
373
     * @param string      $path
374
     * @param string      $mode
375
     * @param int         $options
376
     * @param string|null $opened_path
377
     *
378
     * @return bool
379
     * @noinspection PhpUnused
380
     * @noinspection PhpUnusedParameterInspection
381
     */
382
    public function stream_open(string $path, string $mode, int $options, ?string &$opened_path): bool
383
    {
384
        @stream_wrapper_restore('file');
7✔
385

386
        $usePath = $options & STREAM_USE_PATH ? true : false;
7✔
387
        // $reportErrors = $options & STREAM_REPORT_ERRORS ? true : false;
388

389
        // TODO Implement error reporting as well as opened_path.
390

391
        $functionCallMap = Override::getFunctionCallMap($path);
7✔
392

393
        // Replace the global function calls into local function calls.
394
        if (!empty($functionCallMap)) {
7✔
395
            $source = file_get_contents($path, $usePath);
×
396
            if (!is_string($source)) {
×
397
                throw new RuntimeException(sprintf("File `%s` could not be loaded.", $path));
×
398
            }
399
            $source = Override::convert($source, $functionCallMap);
×
400

401
            $this->resource = fopen('php://temp', 'w+');
×
402
            if (is_resource($this->resource)) {
×
403
                fwrite($this->resource, $source);
×
404
                fseek($this->resource, 0);
×
405
            }
406
        } elseif (is_resource($this->context)) {
7✔
407
            $this->resource = fopen($path, $mode, $usePath, $this->context);
6✔
408
        } else {
409
            $this->resource = fopen($path, $mode, $usePath);
2✔
410
        }
411

412
        stream_wrapper_unregister('file');
7✔
413
        stream_wrapper_register('file', self::class);
7✔
414

415
        return is_resource($this->resource) ? true : false;
7✔
416
    }
417

418
    /**
419
     * Read from stream.
420
     *
421
     * @param int                $count
422
     * @psalm-param positive-int $count
423
     *
424
     * @return string
425
     * @noinspection PhpUnused
426
     */
427
    public function stream_read(int $count): string
428
    {
429
        @stream_wrapper_restore('file');
2✔
430

431
        $r = false;
2✔
432
        if (is_resource($this->resource)) {
2✔
433
            $r = fgets($this->resource, $count);
2✔
434
        }
435

436
        stream_wrapper_unregister('file');
2✔
437
        stream_wrapper_register('file', self::class);
2✔
438

439
        if (!is_string($r)) {
2✔
440
            return '';
×
441
        }
442

443
        return $r;
2✔
444
    }
445

446
    /**
447
     * Seek to specific location in a stream.
448
     *
449
     * @param int $offset
450
     * @param int $whence
451
     *
452
     * @return bool
453
     * @noinspection PhpUnused
454
     */
455
    public function stream_seek(int $offset, int $whence = SEEK_SET): bool
456
    {
457
        @stream_wrapper_restore('file');
1✔
458

459
        $r = -1;
1✔
460
        if (is_resource($this->resource)) {
1✔
461
            $r = fseek($this->resource, $offset, $whence);
1✔
462
        }
463

464
        stream_wrapper_unregister('file');
1✔
465
        stream_wrapper_register('file', self::class);
1✔
466

467
        return $r < 0 ? false : true;
1✔
468
    }
469

470
    /**
471
     * Change stream options.
472
     *
473
     * @param int      $option
474
     * @param int      $arg1
475
     * @param int|null $arg2
476
     *
477
     * @return bool|int
478
     * @noinspection PhpUnused
479
     */
480
    public function stream_set_option(int $option, int $arg1, ?int $arg2)
481
    {
482
        @stream_wrapper_restore('file');
4✔
483

484
        $r = false;
4✔
485
        switch ($option) {
486
            case STREAM_OPTION_BLOCKING:
4✔
487
                if (is_resource($this->resource)) {
1✔
488
                    $r = stream_set_blocking($this->resource, (bool)$arg1);
1✔
489
                }
490
                break;
1✔
491

492
            case STREAM_OPTION_READ_TIMEOUT:
4✔
493
                if (is_null($arg2)) {
2✔
494
                    throw new InvalidArgumentException('Parameter #3 expects int.');
1✔
495
                }
496
                if (is_resource($this->resource)) {
1✔
497
                    $r = stream_set_timeout($this->resource, $arg1, $arg2);
1✔
498
                }
499
                break;
1✔
500

501
            case STREAM_OPTION_WRITE_BUFFER:
3✔
502
                switch ($arg1) {
503
                    case STREAM_BUFFER_NONE:
1✔
504
                        if (is_resource($this->resource)) {
1✔
505
                            $r = stream_set_write_buffer($this->resource, 0);
1✔
506
                        }
507
                        break;
1✔
508

509
                    case STREAM_BUFFER_FULL:
1✔
510
                        if (is_resource($this->resource) && is_int($arg2)) {
1✔
511
                            $r = stream_set_write_buffer($this->resource, $arg2);
1✔
512
                        }
513
                        break;
1✔
514
                }
515
                break;
1✔
516
        }
517

518
        stream_wrapper_unregister('file');
3✔
519
        stream_wrapper_register('file', self::class);
3✔
520

521
        return $r;
3✔
522
    }
523

524
    /**
525
     * Retrieve information about a file resource.
526
     *
527
     * @return array<int|string, int>
528
     * @noinspection PhpUnused
529
     */
530
    public function stream_stat(): array
531
    {
532
        @stream_wrapper_restore('file');
2✔
533

534
        $r = [];
2✔
535
        if (is_resource($this->resource)) {
2✔
536
            $r = fstat($this->resource);
2✔
537
            if (!is_array($r)) {
2✔
538
                $r = [];
×
539
            }
540
        }
541

542
        stream_wrapper_unregister('file');
2✔
543
        stream_wrapper_register('file', self::class);
2✔
544

545
        return $r;
2✔
546
    }
547

548
    /**
549
     * Retrieve the current position of a stream.
550
     *
551
     * @return int
552
     * @noinspection PhpUnused
553
     */
554
    public function stream_tell(): int
555
    {
556
        @stream_wrapper_restore('file');
1✔
557

558
        $r = -1;
1✔
559
        if (is_resource($this->resource)) {
1✔
560
            $r = fseek($this->resource, 0, SEEK_CUR);
1✔
561
        }
562

563
        stream_wrapper_unregister('file');
1✔
564
        stream_wrapper_register('file', self::class);
1✔
565

566
        return $r;
1✔
567
    }
568

569
    /**
570
     * Truncate stream.
571
     *
572
     * @param int                $new_size
573
     * @psalm-param positive-int $new_size
574
     *
575
     * @return bool
576
     * @noinspection PhpUnused
577
     */
578
    public function stream_truncate(int $new_size): bool
579
    {
580
        @stream_wrapper_restore('file');
1✔
581

582
        $r = false;
1✔
583
        if (is_resource($this->resource)) {
1✔
584
            $r = ftruncate($this->resource, $new_size);
1✔
585
        }
586

587
        stream_wrapper_unregister('file');
1✔
588
        stream_wrapper_register('file', self::class);
1✔
589

590
        return $r;
1✔
591
    }
592

593
    /**
594
     * Write to stream.
595
     *
596
     * @param string $data
597
     *
598
     * @return int|false
599
     * @noinspection PhpUnused
600
     */
601
    public function stream_write(string $data)
602
    {
603
        @stream_wrapper_restore('file');
1✔
604

605
        $r = false;
1✔
606
        if (is_resource($this->resource)) {
1✔
607
            $r = fwrite($this->resource, $data);
1✔
608
        }
609

610
        stream_wrapper_unregister('file');
1✔
611
        stream_wrapper_register('file', self::class);
1✔
612

613
        return $r;
1✔
614
    }
615

616
    /**
617
     * Delete a file.
618
     *
619
     * @param string $path
620
     *
621
     * @return bool
622
     */
623
    public function unlink(string $path): bool
624
    {
625
        @stream_wrapper_restore('file');
1✔
626

627
        $r = unlink($path);
1✔
628

629
        stream_wrapper_unregister('file');
1✔
630
        stream_wrapper_register('file', self::class);
1✔
631

632
        return $r;
1✔
633
    }
634

635
    /**
636
     * Retrieve information about a file.
637
     *
638
     * @param string $path
639
     * @param int    $flags
640
     *
641
     * @return array<int|string, int>|false
642
     * @noinspection PhpUnused
643
     */
644
    public function url_stat(string $path, int $flags)
645
    {
646
        @stream_wrapper_restore('file');
1✔
647

648
        $urlStatLink = $flags & STREAM_URL_STAT_LINK ? true : false;
1✔
649
        $urlStatQuiet = $flags & STREAM_URL_STAT_QUIET ? true : false;
1✔
650

651
        if ($urlStatLink) {
1✔
652
            $r = $urlStatQuiet ? @lstat($path) : lstat($path);
1✔
653
        } else {
654
            $r = $urlStatQuiet ? @stat($path) : stat($path);
1✔
655
        }
656

657
        stream_wrapper_unregister('file');
1✔
658
        stream_wrapper_register('file', self::class);
1✔
659

660
        return $r;
1✔
661
    }
662
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc