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

valkyrjaio / valkyrja / 13049807881

30 Jan 2025 09:53AM UTC coverage: 47.589% (-0.03%) from 47.621%
13049807881

push

github

MelechMizrachi
PHP CS Fixer: Style fixes.

18 of 18 new or added lines in 5 files covered. (100.0%)

301 existing lines in 19 files now uncovered.

5201 of 10929 relevant lines covered (47.59%)

18.77 hits per line

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

97.5
/src/Valkyrja/Http/Message/Stream/Stream.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of the Valkyrja Framework package.
7
 *
8
 * (c) Melech Mizrachi <melechmizrachi@gmail.com>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13

14
namespace Valkyrja\Http\Message\Stream;
15

16
use Throwable;
17
use Valkyrja\Http\Message\Stream\Contract\Stream as Contract;
18
use Valkyrja\Http\Message\Stream\Enum\Mode;
19
use Valkyrja\Http\Message\Stream\Enum\ModeTranslation;
20
use Valkyrja\Http\Message\Stream\Enum\PhpWrapper;
21
use Valkyrja\Http\Message\Stream\Exception\InvalidLengthException;
22
use Valkyrja\Http\Message\Stream\Exception\InvalidStreamException;
23

24
use function fclose;
25
use function feof;
26
use function fread;
27
use function fseek;
28
use function fstat;
29
use function ftell;
30
use function fwrite;
31
use function stream_get_contents;
32
use function stream_get_meta_data;
33

34
use const SEEK_SET;
35

36
/**
37
 * Class Stream.
38
 *
39
 * @author Melech Mizrachi
40
 */
41
class Stream implements Contract
42
{
43
    use StreamHelpers;
44

45
    /**
46
     * StreamImpl constructor.
47
     *
48
     * @param PhpWrapper|string $stream          The stream
49
     * @param Mode              $mode            [optional] The mode
50
     * @param ModeTranslation   $modeTranslation [optional] The mode translation
51
     *
52
     * @throws InvalidStreamException
53
     */
54
    public function __construct(
55
        protected PhpWrapper|string $stream = PhpWrapper::temp,
56
        protected Mode $mode = Mode::WRITE_READ,
57
        protected ModeTranslation $modeTranslation = ModeTranslation::BINARY_SAFE
58
    ) {
59
        $this->setStream($stream, $mode, $modeTranslation);
542✔
60
    }
61

62
    /**
63
     * @inheritDoc
64
     */
65
    public function isSeekable(): bool
66
    {
67
        // If there is no stream
68
        if ($this->isInvalidStream()) {
132✔
69
            // Don't do anything
70
            return false;
8✔
71
        }
72

73
        return (bool) $this->getMetadata('seekable');
130✔
74
    }
75

76
    /**
77
     * @inheritDoc
78
     */
79
    public function seek(int $offset, int $whence = SEEK_SET): void
80
    {
81
        $this->verifyStream();
126✔
82
        $this->verifySeekable();
126✔
83

84
        /** @var resource $stream */
85
        $stream = $this->resource;
124✔
86

87
        // Get the results of the seek attempt
88
        $result = $this->seekStream($stream, $offset, $whence);
124✔
89

90
        $this->verifySeekResult($result);
124✔
91
    }
92

93
    /**
94
     * @inheritDoc
95
     */
96
    public function rewind(): void
97
    {
98
        $this->seek(0);
120✔
99
    }
100

101
    /**
102
     * @inheritDoc
103
     */
104
    public function isReadable(): bool
105
    {
106
        // If there is no stream
107
        if ($this->isInvalidStream()) {
104✔
108
            // It's not readable
109
            return false;
10✔
110
        }
111

112
        // Get the stream's mode
113
        /** @var string|null $mode */
114
        $mode = $this->getMetadata('mode');
102✔
115

116
        return $this->isModeReadable((string) $mode);
102✔
117
    }
118

119
    /**
120
     * @inheritDoc
121
     */
122
    public function read(int $length): string
123
    {
124
        if ($length < 0) {
20✔
125
            throw new InvalidLengthException("Invalid length of $length provided. Length must be greater than 0");
×
126
        }
127

128
        /** @var int<1, max> $length */
129
        $this->verifyStream();
20✔
130
        $this->verifyReadable();
18✔
131

132
        /** @var resource $stream */
133
        $stream = $this->resource;
16✔
134

135
        // Read the stream
136
        $result = $this->readFromStream($stream, $length);
16✔
137

138
        $this->verifyReadResult($result);
16✔
139

140
        /** @var string $result */
141

142
        return $result;
14✔
143
    }
144

145
    /**
146
     * @inheritDoc
147
     */
148
    public function isWritable(): bool
149
    {
150
        // If there is no stream
151
        if ($this->isInvalidStream()) {
146✔
152
            // The stream is definitely not writable
153
            return false;
6✔
154
        }
155

156
        // Get the stream's mode
157
        /** @var string|null $mode */
158
        $mode = $this->getMetadata('mode');
146✔
159

160
        return $this->isModeWriteable((string) $mode);
146✔
161
    }
162

163
    /**
164
     * @inheritDoc
165
     */
166
    public function write(string $string): int
167
    {
168
        $this->verifyStream();
146✔
169
        $this->verifyWritable();
144✔
170

171
        /** @var resource $stream */
172
        $stream = $this->resource;
142✔
173

174
        // Attempt to write to the stream
175
        $result = $this->writeToStream($stream, $string);
142✔
176

177
        $this->verifyWriteResult($result);
142✔
178

179
        /** @var int $result */
180

181
        return $result;
140✔
182
    }
183

184
    /**
185
     * @inheritDoc
186
     */
187
    public function __toString(): string
188
    {
189
        // If the stream is not readable
190
        if (! $this->isReadable()) {
18✔
191
            // Return an empty string
192
            return '';
2✔
193
        }
194

195
        try {
196
            // Rewind the stream to the start
197
            $this->rewind();
18✔
198

199
            // Get the stream's contents
200
            return $this->getContents();
18✔
201
        } // On a runtime exception
202
        catch (Throwable) {
2✔
203
            // Return a string
204
            return '';
2✔
205
        }
206
    }
207

208
    /**
209
     * @inheritDoc
210
     */
211
    public function close(): void
212
    {
213
        // If there is no stream
214
        if ($this->isInvalidStream()) {
16✔
215
            // Don't do anything
216
            return;
2✔
217
        }
218

219
        // Detach the stream
220
        /** @var resource $resource */
221
        $resource = $this->detach();
14✔
222

223
        // Close the stream
224
        $this->closeStream($resource);
14✔
225
    }
226

227
    /**
228
     * @inheritDoc
229
     */
230
    public function detach()
231
    {
232
        $resource = $this->resource ?? null;
40✔
233

234
        $this->resource = null;
40✔
235

236
        return $resource;
40✔
237
    }
238

239
    /**
240
     * @inheritDoc
241
     */
242
    public function getSize(): int|null
243
    {
244
        // If the stream isn't set
245
        if ($this->isInvalidStream()) {
4✔
246
            // Return without attempting to get the fstat
247
            return null;
2✔
248
        }
249

250
        /** @var resource $stream */
251
        $stream = $this->resource;
4✔
252

253
        // Get the stream's fstat
254
        $fstat = fstat($stream);
4✔
255

256
        if ($fstat === false) {
4✔
UNCOV
257
            return null;
×
258
        }
259

260
        return $fstat['size'];
4✔
261
    }
262

263
    /**
264
     * @inheritDoc
265
     */
266
    public function tell(): int
267
    {
268
        $this->verifyStream();
8✔
269

270
        /** @var resource $stream */
271
        $stream = $this->resource;
6✔
272

273
        // Get the tell for the stream
274
        $result = $this->tellStream($stream);
6✔
275

276
        $this->verifyTellResult($result);
6✔
277

278
        /** @var int $result */
279

280
        return $result;
4✔
281
    }
282

283
    /**
284
     * @inheritDoc
285
     */
286
    public function eof(): bool
287
    {
288
        // If there is no stream
289
        if ($this->isInvalidStream()) {
16✔
290
            // Don't do anything
291
            return true;
2✔
292
        }
293

294
        /** @var resource $stream */
295
        $stream = $this->resource;
16✔
296

297
        return feof($stream);
16✔
298
    }
299

300
    /**
301
     * @inheritDoc
302
     */
303
    public function getContents(): string
304
    {
305
        $this->verifyReadable();
86✔
306

307
        /** @var resource $stream */
308
        $stream = $this->resource;
84✔
309

310
        // Get the stream contents
311
        $result = $this->getStreamContents($stream);
84✔
312

313
        $this->verifyReadResult($result);
84✔
314

315
        /** @var string $result */
316

317
        return $result;
80✔
318
    }
319

320
    /**
321
     * @inheritDoc
322
     */
323
    public function getMetadata(string|null $key = null): mixed
324
    {
325
        // Ensure the stream is valid
326
        if ($this->isInvalidStream()) {
184✔
327
            return null;
6✔
328
        }
329

330
        /** @var resource $stream */
331
        $stream = $this->resource;
184✔
332

333
        // If no key was specified
334
        if ($key === null) {
184✔
335
            // Return all the meta data
336
            return $this->getStreamMetadata($stream);
4✔
337
        }
338

339
        // Get the meta data
340
        $metadata = $this->getStreamMetadata($stream);
184✔
341

342
        return $metadata[$key] ?? null;
184✔
343
    }
344

345
    // public function __clone()
346
    // {
347
    //     $this->rewind();
348
    //
349
    //     $contents = $this->getContents();
350
    //
351
    //     $this->setStream($this->stream, $this->mode, $this->modeTranslation);
352
    //
353
    //     if ($this->isWritable()) {
354
    //         $this->write($contents);
355
    //         $this->rewind();
356
    //     }
357
    // }
358

359
    /**
360
     * Seek the stream resource.
361
     *
362
     * @param resource $stream
363
     * @param int      $offset
364
     * @param int      $whence
365
     *
366
     * @return int
367
     */
368
    protected function seekStream($stream, int $offset, int $whence = SEEK_SET): int
369
    {
370
        // Get the results of the seek attempt
371
        return fseek($stream, $offset, $whence);
122✔
372
    }
373

374
    /**
375
     * Tell the stream resource.
376
     *
377
     * @param resource $stream
378
     *
379
     * @return int|false
380
     */
381
    protected function tellStream($stream): int|false
382
    {
383
        // Get the tell for the stream
384
        return ftell($stream);
4✔
385
    }
386

387
    /**
388
     * Write to a stream.
389
     *
390
     * @param resource $stream The stream
391
     */
392
    protected function writeToStream($stream, string $data): int|false
393
    {
394
        return fwrite($stream, $data);
140✔
395
    }
396

397
    /**
398
     * Read from stream.
399
     *
400
     * @param resource    $stream The stream
401
     * @param int<1, max> $length The length
402
     */
403
    protected function readFromStream($stream, int $length): string|false
404
    {
405
        return fread($stream, $length);
14✔
406
    }
407

408
    /**
409
     * Get a stream's metadata.
410
     *
411
     * @param resource $stream The stream
412
     *
413
     * @return array{blocked: bool, crypto?: array{cipher_bits: int, cipher_name: string, cipher_version: string, protocol: string}, eof: bool, mediatype?: string, mode: string, seekable: bool, stream_type: string, timed_out: bool, unread_bytes: int, uri: string, wrapper_data: mixed, wrapper_type: string}
414
     */
415
    protected function getStreamMetadata($stream): array
416
    {
417
        return stream_get_meta_data($stream);
184✔
418
    }
419

420
    /**
421
     * Get a stream's contents.
422
     *
423
     * @param resource $stream The stream
424
     *
425
     * @return string|false
426
     */
427
    protected function getStreamContents($stream): string|false
428
    {
429
        return stream_get_contents($stream);
80✔
430
    }
431

432
    /**
433
     * Close a stream.
434
     *
435
     * @param resource $stream The stream
436
     *
437
     * @return bool
438
     */
439
    protected function closeStream($stream): bool
440
    {
441
        return fclose($stream);
14✔
442
    }
443
}
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