Closes #678: Issues with filename detection in PlUpload when the username
[platal.git] / classes / plupload.php
1 <?php
2 /***************************************************************************
3 * Copyright (C) 2003-2007 Polytechnique.org *
4 * http://opensource.polytechnique.org/ *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., *
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
20 ***************************************************************************/
21
22 /** Class to store per user and per category files
23 */
24 class PlUpload
25 {
26 private $forlife;
27 private $category;
28 private $file_id;
29
30 private $filename;
31 private $type;
32
33 /** For images
34 */
35 private $x;
36 private $y;
37
38 public function __construct($forlife, $category, $filename = null)
39 {
40 $this->file_id = $filename;
41 $this->category = $category;
42 $this->forlife = $forlife;
43 $this->filename = $this->makeFilename($this->file_id);
44 $this->checkContentType();
45 }
46
47 private function makeFilename($file_id)
48 {
49 global $globals;
50 $filename = $globals->spoolroot . '/spool/uploads/temp/';
51 if (!file_exists($filename)) {
52 if (!mkdir($filename)) {
53 trigger_error('can\'t create upload directory: ' . $filename, E_USER_ERROR);
54 }
55 }
56 $filename .= $this->forlife . '--' . $this->category;
57 if ($file_id) {
58 $filename .= '--' . $file_id;
59 }
60 return $filename;
61 }
62
63 private function checkContentType()
64 {
65 if ($this->exists()) {
66 $this->type = trim(mime_content_type($this->filename));
67 }
68 }
69
70 public function upload(array &$file)
71 {
72 if (!is_uploaded_file($file['tmp_name'])) {
73 return false;
74 } else if (!move_uploaded_file($file['tmp_name'], $this->filename)) {
75 return false;
76 }
77 $this->checkContentType();
78 return true;
79 }
80
81 public function copyFrom($filename)
82 {
83 if (!copy($filename, $this->filename)) {
84 return false;
85 }
86 $this->checkContentType();
87 return true;
88 }
89
90 public function download($url)
91 {
92 if (!$url || @parse_url($url) === false) {
93 trigger_error('malformed URL given', E_USER_NOTICE);
94 return false;
95 }
96 $data = file_get_contents($url);
97 if (!$data) {
98 return false;
99 }
100 if (!file_put_contents($this->filename, $data)) {
101 return false;
102 }
103 $this->checkContentType();
104 return true;
105 }
106
107 static public function &get(array &$file, $forlife, $category, $uniq = false)
108 {
109 $upload = new PlUpload($forlife, $category, $uniq ? null : $file['name']);
110 if (!$upload->upload($file)) {
111 $upload = null;
112 }
113 return $upload;
114 }
115
116 public function rm()
117 {
118 @unlink($this->filename);
119 @clearstatcache();
120 }
121
122 public function rename($fn)
123 {
124 if (!$this->file_id) {
125 return false;
126 }
127 $filename = $this->makeFilename($fn);
128 if (rename($this->filename)) {
129 $this->filename = $filename;
130 $this->file_id = $fn;
131 clearstatcache();
132 return true;
133 }
134 return false;
135 }
136
137 public function exists()
138 {
139 return file_exists($this->filename);
140 }
141
142 static public function listRawFiles($forlife = '*', $category = '*', $uniq = false, $basename = false)
143 {
144 global $globals;
145 $filename = $globals->spoolroot . '/spool/uploads/temp/';
146 $filename .= $forlife . '--' . $category;
147 if (!$uniq) {
148 $filename .= '--*';
149 }
150 $files = glob($filename);
151 if ($basename) {
152 $files = array_map('basename', $files);
153 }
154 return $files;
155 }
156
157 static public function listFilenames($forlife = '*', $category = '*')
158 {
159 $files = PlUpload::listRawFiles($forlife, $category, false, true);
160 foreach ($files as &$name) {
161 list($forlife, $cat, $fn) = explode('--', $name, 3);
162 $name = $fn;
163 }
164 return $files;
165 }
166
167 static public function &listFiles($forlife = '*', $category = '*', $uniq = false)
168 {
169 $res = array();
170 $files = PlUpload::listRawFiles($forlife, $category, $uniq, true);
171 foreach ($files as $name) {
172 list($forlife, $cat, $fn) = explode('--', $name, 3);
173 $res[$fn] = new PlUpload($forlife, $cat, $fn);
174 }
175 return $res;
176 }
177
178 static public function clear($user = '*', $category = '*', $uniq = false)
179 {
180 $files = PlUpload::listRawFiles($user, $category, $uniq, false);
181 array_map('unlink', $files);
182 }
183
184 public function contentType()
185 {
186 return $this->type;
187 }
188
189 public function isType($type, $subtype = null)
190 {
191 list($mytype, $mysubtype) = explode('/', $this->type);
192 if ($mytype != $type || ($subtype && $mysubtype != $subtype)) {
193 return false;
194 }
195 return true;
196 }
197
198 public function imageInfo()
199 {
200 static $map;
201 if (!isset($map)) {
202 $tmpmap = array (IMG_GIF => 'gif', IMG_JPG => 'jpeg', IMG_PNG => 'png', IMG_WBMP => 'bmp', IMG_XPM => 'xpm');
203 $map = array();
204 $supported = imagetypes();
205 foreach ($tmpmap as $type=>$mime) {
206 if ($supported & $type) {
207 $map[$type] = $mime;
208 }
209 }
210 }
211 $array = getimagesize($this->filename);
212 $array[2] = @$map[$array[2]];
213 if (!$array[2]) {
214 trigger_error('unknown image type', E_USER_NOTICE);
215 return null;
216 }
217 return $array;
218 }
219
220 public function resizeImage($max_x = -1, $max_y = -1, $min_x = 0, $min_y = 0, $maxsize = -1)
221 {
222 if (!$this->exists() || strpos($this->type, 'image/') !== 0) {
223 trigger_error('not an image', E_USER_NOTICE);
224 return false;
225 }
226 $image_infos = $this->imageInfo();
227 if (!$image_infos) {
228 trigger_error('invalid image', E_USER_NOTICE);
229 return false;
230 }
231 list($this->x, $this->y, $mimetype) = $image_infos;
232 if ($max_x == -1) {
233 $max_x = $this->x;
234 }
235 if ($max_y == -1) {
236 $max_y = $this->y;
237 }
238 if ($maxsize == -1) {
239 $maxsize = filesize($this->filename);
240 }
241 if (filesize($this->filename) > $maxsize || $this->x > $max_x || $this->y > $max_y
242 || $this->x < $min_x || $this->y < $min_y) {
243 $img = imagecreatefromstring(file_get_contents($this->filename));
244 if (!$img) {
245 trigger_error('too large image, can\'t be resized', E_USER_NOTICE);
246 return false;
247 }
248
249 $nx = $this->x;
250 $ny = $this->y;
251 if ($nx > $max_x) {
252 $ny = intval($ny*$max_x/$nx);
253 $nx = $max_x;
254 }
255 if ($ny > $max_y) {
256 $nx = intval($nx*$max_y/$ny);
257 $ny = $max_y;
258 }
259 if ($nx < $min_x) {
260 $ny = intval($ny*$min_x/$nx);
261 $nx = $min_x;
262 }
263 if ($ny < $min_y) {
264 $nx = intval($nx * $min_y/$ny);
265 $ny = $min_y;
266 }
267
268 $comp = 90;
269 do {
270 $img2 = imagecreatetruecolor($nx, $ny);
271 imagecopyresampled($img2, $img, 0, 0, 0, 0, $nx, $ny, $this->x, $this->y);
272 imagejpeg($img2, $this->filename, $comp);
273 $comp --;
274 clearstatcache();
275 } while (filesize($this->filename) > $maxsize && $comp > 0);
276 $this->type = 'image/jpeg';
277 $this->x = $nx;
278 $this->y = $ny;
279 }
280 return true;
281 }
282
283 public function getContents()
284 {
285 if ($this->exists()) {
286 return file_get_contents($this->filename);
287 }
288 return null;
289 }
290 }
291 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
292 ?>