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
+
10
+
11
+ /**
12
+ * Provides a simple way to create file downloads in PHP
13
+ */
14
+ class FileDownload
15
+ {
16
+ /**
17
+ * The pointer to the file to download
18
+ *
19
+ * @var resource
20
+ */
21
+ private $ filePointer ;
22
+
23
+
24
+
25
+ /**
26
+ * Constructs a new file download
27
+ *
28
+ * @param resource $filePointer
29
+ *
30
+ * @throws InvalidArgumentException
31
+ */
32
+ public function __construct ($ filePointer )
33
+ {
34
+ if (!is_resource ($ filePointer ))
35
+ {
36
+ throw new InvalidArgumentException ("You must pass a file pointer to the ctor " );
37
+ }
38
+
39
+ $ this ->filePointer = $ filePointer ;
40
+ }
41
+
42
+
43
+
44
+ /**
45
+ * Sends the download to the browser
46
+ *
47
+ * @param string $filename
48
+ *
49
+ * @throws \RuntimeException is thrown, if the headers are already sent
50
+ */
51
+ public function sendDownload ($ filename )
52
+ {
53
+ if (headers_sent ())
54
+ {
55
+ throw new \RuntimeException ("Cannot send file to the browser, since the headers were already sent. " );
56
+ }
57
+
58
+ header ("Pragma: public " );
59
+ header ("Expires: 0 " );
60
+ header ("Cache-Control: must-revalidate, post-check=0, pre-check=0 " );
61
+ header ("Cache-Control: private " , false );
62
+ header ("Content-Type: {$ this ->getMimeType ($ filename )}" );
63
+ header ("Content-Disposition: attachment; filename= \"{$ filename }\"; " );
64
+ header ("Content-Transfer-Encoding: binary " );
65
+ header ("Content-Length: {$ this ->getFileSize ()}" );
66
+
67
+ @ob_clean ();
68
+
69
+ rewind ($ this ->filePointer );
70
+ fpassthru ($ this ->filePointer );
71
+ }
72
+
73
+
74
+
75
+ /**
76
+ * Returns the mime type of a file name
77
+ *
78
+ * @param string $fileName
79
+ *
80
+ * @return string
81
+ */
82
+ private function getMimeType ($ fileName )
83
+ {
84
+ switch (pathinfo ($ fileName , PATHINFO_EXTENSION ))
85
+ {
86
+ case "pdf " : return "application/pdf " ;
87
+ case "exe " : return "application/octet-stream " ;
88
+ case "zip " : return "application/zip " ;
89
+ case "doc " : return "application/msword " ;
90
+ case "xls " : return "application/vnd.ms-excel " ;
91
+ case "ppt " : return "application/vnd.ms-powerpoint " ;
92
+ case "gif " : return "image/gif " ;
93
+ case "png " : return "image/png " ;
94
+ case "jpeg " :
95
+ case "jpg " : return "image/jpg " ;
96
+ default : return "application/force-download " ;
97
+ }
98
+ }
99
+
100
+
101
+
102
+ /**
103
+ * Returns the file size of the file
104
+ *
105
+ * @return int
106
+ */
107
+ private function getFileSize ()
108
+ {
109
+ $ stat = fstat ($ this ->filePointer );
110
+ return $ stat ['size ' ];
111
+ }
112
+
113
+
114
+
115
+ /**
116
+ * Creates a new file download from a file path
117
+ *
118
+ * @static
119
+ *
120
+ * @param string $filePath
121
+ *
122
+ * @throws \InvalidArgumentException is thrown, if the given file does not exist or is not readable
123
+ *
124
+ * @return FileDownload
125
+ */
126
+ public static function createFromFilePath ($ filePath )
127
+ {
128
+ if (!is_file ($ filePath ))
129
+ {
130
+ throw new \InvalidArgumentException ("File does not exist " );
131
+ }
132
+ else if (!is_readable ($ filePath ))
133
+ {
134
+ throw new \InvalidArgumentException ("File to download is not readable. " );
135
+ }
136
+
137
+ return new FileDownload (fopen ($ filePath , "rb " ));
138
+ }
139
+
140
+
141
+
142
+ /**
143
+ * Creates a new file download helper with a given content
144
+ *
145
+ * @static
146
+ *
147
+ * @param string $content the file content
148
+ *
149
+ * @return FileDownload
150
+ */
151
+ public static function createFromString ($ content )
152
+ {
153
+ $ file = tmpfile ();
154
+ fwrite ($ file , $ content );
155
+
156
+ return new FileDownload ($ file );
157
+ }
158
+ }
0 commit comments