]> BookStack Code Mirror - bookstack/blob - app/Http/RangeSupportedStream.php
Range requests: Extracted stream output handling to new class
[bookstack] / app / Http / RangeSupportedStream.php
1 <?php
2
3 namespace BookStack\Http;
4
5 use BookStack\Util\WebSafeMimeSniffer;
6 use Symfony\Component\HttpFoundation\HeaderBag;
7
8 class RangeSupportedStream
9 {
10     protected string $sniffContent;
11
12     public function __construct(
13         protected $stream,
14         protected int $fileSize,
15         protected HeaderBag $requestHeaders,
16     ) {
17     }
18
19     /**
20      * Sniff a mime type from the stream.
21      */
22     public function sniffMime(): string
23     {
24         $offset = min(2000, $this->fileSize);
25         $this->sniffContent = fread($this->stream, $offset);
26
27         return (new WebSafeMimeSniffer())->sniff($this->sniffContent);
28     }
29
30     /**
31      * Output the current stream to stdout before closing out the stream.
32      */
33     public function outputAndClose(): void
34     {
35         // End & flush the output buffer, if we're in one, otherwise we still use memory.
36         // Output buffer may or may not exist depending on PHP `output_buffering` setting.
37         // Ignore in testing since output buffers are used to gather a response.
38         if (!empty(ob_get_status()) && !app()->runningUnitTests()) {
39             ob_end_clean();
40         }
41
42         $outStream = fopen('php://output', 'w');
43         $offset = 0;
44
45         if (!empty($this->sniffContent)) {
46             fwrite($outStream, $this->sniffContent);
47             $offset = strlen($this->sniffContent);
48         }
49
50         $toWrite = $this->fileSize - $offset;
51         stream_copy_to_stream($this->stream, $outStream, $toWrite);
52         fpassthru($this->stream);
53
54         fclose($this->stream);
55         fclose($outStream);
56     }
57 }