]> BookStack Code Mirror - bookstack/blob - app/Http/Responses/DownloadResponseFactory.php
ec742fc47370818f833695807e0be574f4b72e93
[bookstack] / app / Http / Responses / DownloadResponseFactory.php
1 <?php
2
3 namespace BookStack\Http\Responses;
4
5 use BookStack\Util\WebSafeMimeSniffer;
6 use Illuminate\Http\Request;
7 use Illuminate\Http\Response;
8 use Symfony\Component\HttpFoundation\StreamedResponse;
9
10 class DownloadResponseFactory
11 {
12     protected Request $request;
13
14     public function __construct(Request $request)
15     {
16         $this->request = $request;
17     }
18
19     /**
20      * Create a response that directly forces a download in the browser.
21      */
22     public function directly(string $content, string $fileName): Response
23     {
24         return response()->make($content, 200, $this->getHeaders($fileName));
25     }
26
27     /**
28      * Create a response that forces a download, from a given stream of content.
29      */
30     public function streamedDirectly($stream, string $fileName): StreamedResponse
31     {
32         return response()->stream(function () use ($stream) {
33
34             // End & flush the output buffer, if we're in one, otherwise we still use memory.
35             // Output buffer may or may not exist depending on PHP `output_buffering` setting.
36             // Ignore in testing since output buffers are used to gather a response.
37             if (!empty(ob_get_status()) && !app()->runningUnitTests()) {
38                 ob_end_clean();
39             }
40
41             fpassthru($stream);
42             fclose($stream);
43         }, 200, $this->getHeaders($fileName));
44     }
45
46     /**
47      * Create a file download response that provides the file with a content-type
48      * correct for the file, in a way so the browser can show the content in browser,
49      * for a given content stream.
50      */
51     public function streamedInline($stream, string $fileName): StreamedResponse
52     {
53         $sniffContent = fread($stream, 2000);
54         $mime = (new WebSafeMimeSniffer())->sniff($sniffContent);
55
56         return response()->stream(function () use ($sniffContent, $stream) {
57             echo $sniffContent;
58             fpassthru($stream);
59             fclose($stream);
60         }, 200, $this->getHeaders($fileName, $mime));
61     }
62
63     /**
64      * Get the common headers to provide for a download response.
65      */
66     protected function getHeaders(string $fileName, string $mime = 'application/octet-stream'): array
67     {
68         $disposition = ($mime === 'application/octet-stream') ? 'attachment' : 'inline';
69         $downloadName = str_replace('"', '', $fileName);
70
71         return [
72             'Content-Type'           => $mime,
73             'Content-Disposition'    => "{$disposition}; filename=\"{$downloadName}\"",
74             'X-Content-Type-Options' => 'nosniff',
75         ];
76     }
77 }