Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
FileDownload
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 6
156
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 sendDownload
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
12
 getMimeType
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 getFileSize
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 createFromFilePath
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 createFromString
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Provides the possibility to easily create file downloads in PHP
4 *
5 * @author Jannik Zschiesche <hello@apfelbox.net>
6 * @version 1.0
7 * @license MIT
8 */
9
10namespace Apfelbox\FileDownload;
11
12use Skyzyx\Components\Mimetypes\Mimetypes;
13
14/**
15 * Provides a simple way to create file downloads in PHP
16 */
17class FileDownload
18{
19    /**
20     * The pointer to the file to download
21     *
22     * @var resource
23     */
24    private $filePointer;
25
26
27
28    /**
29     * Constructs a new file download
30     *
31     * @param resource $filePointer
32     *
33     * @throws \InvalidArgumentException
34     */
35    public function __construct ($filePointer)
36    {
37        if (!is_resource($filePointer))
38        {
39            throw new \InvalidArgumentException("You must pass a file pointer to the ctor");
40        }
41
42        $this->filePointer = $filePointer;
43    }
44
45
46
47    /**
48     * Sends the download to the browser
49     *
50     * @param string $filename
51     * @param bool $forceDownload
52     *
53     * @throws \RuntimeException is thrown, if the headers are already sent
54     */
55    public function sendDownload ($filename, $forceDownload = true)
56    {
57        if (headers_sent())
58        {
59            throw new \RuntimeException("Cannot send file to the browser, since the headers were already sent.");
60        }
61
62        header("Pragma: public");
63        header("Expires: 0");
64        header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
65        header("Cache-Control: private", false);
66        header("Content-Type: {$this->getMimeType($filename)}");
67
68        if ($forceDownload)
69        {
70            header("Content-Disposition: attachment; filename=\"{$filename}\";" );
71        }
72        else
73        {
74            header("Content-Disposition: filename=\"{$filename}\";" );
75        }
76
77        header("Content-Transfer-Encoding: binary");
78        header("Content-Length: {$this->getFileSize()}");
79
80        @ob_clean();
81
82        rewind($this->filePointer);
83        fpassthru($this->filePointer);
84    }
85
86
87
88    /**
89     * Returns the mime type of a file name
90     *
91     * @param string $fileName
92     *
93     * @return string
94     */
95    private function getMimeType ($fileName)
96    {
97        $fileExtension  = pathinfo($fileName, PATHINFO_EXTENSION);
98        $mimeTypeHelper = Mimetypes::getInstance();
99        $mimeType       = $mimeTypeHelper->fromExtension($fileExtension);
100
101        return !is_null($mimeType) ? $mimeType : "application/force-download";
102    }
103
104
105
106    /**
107     * Returns the file size of the file
108     *
109     * @return int
110     */
111    private function getFileSize ()
112    {
113        $stat = fstat($this->filePointer);
114        return $stat['size'];
115    }
116
117
118
119    /**
120     * Creates a new file download from a file path
121     *
122     * @static
123     *
124     * @param string $filePath
125     *
126     * @throws \InvalidArgumentException is thrown, if the given file does not exist or is not readable
127     *
128     * @return FileDownload
129     */
130    public static function createFromFilePath ($filePath)
131    {
132        if (!is_file($filePath))
133        {
134            throw new \InvalidArgumentException("File does not exist");
135        }
136        else if (!is_readable($filePath))
137        {
138            throw new \InvalidArgumentException("File to download is not readable.");
139        }
140
141        return new FileDownload(fopen($filePath, "rb"));
142    }
143
144
145
146    /**
147     * Creates a new file download helper with a given content
148     *
149     * @static
150     *
151     * @param string $content the file content
152     *
153     * @return FileDownload
154     */
155    public static function createFromString ($content)
156    {
157        $file = tmpfile();
158        fwrite($file, $content);
159
160        return new FileDownload($file);
161    }
162}