]> git.p6c8.net - jirafeau.git/blob - lib/functions.php
Fix potential error: do not scan for .tmp files
[jirafeau.git] / lib / functions.php
1 <?php
2 /*
3 * Jirafeau, your web file repository
4 * Copyright (C) 2008 Julien "axolotl" BERNARD <axolotl@magieeternelle.org>
5 * Copyright (C) 2012 Jerome Jutteau <j.jutteau@gmail.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20 /**
21 * transforms a php.ini string representing a value in an integer
22 * @param $value the value from php.ini
23 * @returns an integer for this value
24 */
25 function jirafeau_ini_to_bytes ($value)
26 {
27 $modifier = substr ($value, -1);
28 $bytes = substr ($value, 0, -1);
29 switch (strtoupper ($modifier))
30 {
31 case 'P':
32 $bytes *= 1024;
33 case 'T':
34 $bytes *= 1024;
35 case 'G':
36 $bytes *= 1024;
37 case 'M':
38 $bytes *= 1024;
39 case 'K':
40 $bytes *= 1024;
41 default:
42 break;
43 }
44 return $bytes;
45 }
46
47 /**
48 * gets the maximum upload size according to php.ini
49 * @returns the maximum upload size
50 */
51 function
52 jirafeau_get_max_upload_size ()
53 {
54 return min (jirafeau_ini_to_bytes (ini_get ('post_max_size')),
55 jirafeau_ini_to_bytes (ini_get ('upload_max_filesize')));
56 }
57
58 /**
59 * gets a string explaining the error
60 * @param $code the error code
61 * @returns a string explaining the error
62 */
63 function
64 jirafeau_upload_errstr ($code)
65 {
66 switch ($code)
67 {
68 case UPLOAD_ERR_INI_SIZE:
69 case UPLOAD_ERR_FORM_SIZE:
70 return _('Your file exceeds the maximum authorized file size. ');
71 break;
72
73 case UPLOAD_ERR_PARTIAL:
74 case UPLOAD_ERR_NO_FILE:
75 return
76 _
77 ('Your file was not uploaded correctly. You may succeed in retrying. ');
78 break;
79
80 case UPLOAD_ERR_NO_TMP_DIR:
81 case UPLOAD_ERR_CANT_WRITE:
82 case UPLOAD_ERR_EXTENSION:
83 return _('Internal error. You may not succeed in retrying. ');
84 break;
85
86 default:
87 break;
88 }
89 return _('Unknown error. ');
90 }
91
92 /** Remove link and it's file
93 * @param $link the link's name (hash)
94 */
95
96 function
97 jirafeau_delete ($link)
98 {
99 if (!file_exists ( VAR_LINKS . $link))
100 return;
101
102 $content = file (VAR_LINKS . $link);
103 $md5 = trim ($content[5]);
104 unlink (VAR_LINKS . $link);
105
106 $counter = 1;
107 if (file_exists ( VAR_FILES . $md5. '_count'))
108 {
109 $content = file ( VAR_FILES . $md5. '_count');
110 $counter = trim ($content[0]);
111 }
112 $counter--;
113
114 if ($counter >= 1)
115 {
116 $handle = fopen ( VAR_FILES . $md5. '_count', 'w');
117 fwrite ($handle, $counter);
118 fclose ($handle);
119 }
120
121 if ($counter == 0)
122 {
123 if (file_exists (VAR_FILES . $md5))
124 unlink ( VAR_FILES . $md5);
125 if (file_exists (VAR_FILES . $md5 . '_count'))
126 unlink ( VAR_FILES . $md5. '_count');
127 }
128 }
129
130 /**
131 * Delete a file and it's links.
132 */
133 function
134 jirafeau_delete_file ($md5)
135 {
136 $count = 0;
137 $links_dir = scandir (VAR_LINKS);
138
139 foreach ($links_dir as $link)
140 {
141 if (strcmp ($link, '.') == 0 || strcmp ($link, '..') == 0 ||
142 preg_match ('/\.tmp/i', "$link"))
143 continue;
144 /* Read link informations. */
145 $l = jirafeau_get_link ($link);
146 if ($l['md5'] == $md5)
147 {
148 $count++;
149 jirafeau_delete ($link);
150 }
151 }
152
153 if (file_exists (VAR_FILES . $md5 . '_count'))
154 unlink (VAR_FILES . $md5. '_count');
155 if (file_exists (VAR_FILES . $md5))
156 unlink (VAR_FILES . $md5);
157
158 return $count;
159 }
160
161 /**
162 * handles an uploaded file
163 * @param $file the file struct given by $_FILE[]
164 * @param $one_time_download is the file a one time download ?
165 * @param $key if not empty, protect the file with this key
166 * @param $time the time of validity of the file
167 * @param $cfg the current configuration
168 * @param $ip uploader's ip
169 * @returns an array containing some information
170 * 'error' => information on possible errors
171 * 'link' => the link name of the uploaded file
172 * 'delete_link' => the link code to delete file
173 */
174 function
175 jirafeau_upload ($file, $one_time_download, $key, $time, $cfg, $ip)
176 {
177 if (empty ($file['tmp_name']) || !is_uploaded_file ($file['tmp_name']))
178 {
179 return (array(
180 'error' =>
181 array ('has_error' => true,
182 'why' => jirafeau_upload_errstr ($file['error'])),
183 'link' => '',
184 'delete_link' => ''));
185 }
186
187 /* array representing no error */
188 $noerr = array ('has_error' => false, 'why' => '');
189
190 /* file informations */
191 $md5 = md5_file ($file['tmp_name']);
192 $name = trim ($file['name']);
193 $mime_type = $file['type'];
194 $size = $file['size'];
195
196 /* does file already exist ? */
197 $rc = false;
198 if (file_exists ( VAR_FILES . $md5))
199 {
200 $rc = unlink ($file['tmp_name']);
201 }
202 elseif (move_uploaded_file ($file['tmp_name'], VAR_FILES . $md5))
203 {
204 $rc = true;
205 }
206 if (!$rc)
207 {
208 return (array(
209 'error' =>
210 array ('has_error' => true,
211 'why' => _('Internal error during file creation. ')),
212 'link' =>'',
213 'delete_link' => ''));
214 }
215
216 /* increment or create count file */
217 $counter = 0;
218 if (file_exists (VAR_FILES . $md5 . '_count'))
219 {
220 $content = file ( VAR_FILES . $md5. '_count');
221 $counter = trim ($content[0]);
222 }
223 $counter++;
224 $handle = fopen ( VAR_FILES . $md5. '_count', 'w');
225 fwrite ($handle, $counter);
226 fclose ($handle);
227
228 /* Create delete code. */
229 $delete_link_code = 0;
230 for ($i = 0; $i < 8; $i++)
231 $delete_link_code .= dechex (rand (0, 16));
232
233 /* md5 password or empty */
234 $password = '';
235 if (!empty ($key))
236 $password = md5 ($key);
237
238 /* create link file */
239 $link_tmp_name = VAR_LINKS . $md5.rand (0, 10000) . ' .tmp';
240 $handle = fopen ($link_tmp_name, 'w');
241 fwrite ($handle,
242 $name . NL. $mime_type . NL. $size . NL. $password . NL. $time . NL . $md5.
243 NL.($one_time_download ? 'O' : 'R') . NL.date ('U') . NL. $ip . NL.
244 $delete_link_code . NL);
245 fclose ($handle);
246 $md5_link = md5_file ($link_tmp_name);
247 if (!rename ($link_tmp_name, VAR_LINKS . $md5_link))
248 {
249 unlink ($link_tmp_name);
250 $counter--;
251 if ($counter >= 1)
252 {
253 $handle = fopen ( VAR_FILES . $md5. '_count', 'w');
254 fwrite ($handle, $counter);
255 fclose ($handle);
256 }
257 else
258 {
259 unlink ( VAR_FILES . $md5. '_count');
260 unlink ( VAR_FILES . $md5);
261 }
262 return (array(
263 'error' =>
264 array ('has_error' => true,
265 'why' => _('Internal error during file creation. ')),
266 'link' =>'',
267 'delete_link' => ''));
268 }
269 return (array ('error' => $noerr,
270 'link' => $md5_link,
271 'delete_link' => $delete_link_code));
272 }
273
274 /**
275 * tells if a mime-type is viewable in a browser
276 * @param $mime the mime type
277 * @returns a boolean telling if a mime type is viewable
278 */
279 function
280 jirafeau_is_viewable ($mime)
281 {
282 if (!empty ($mime))
283 {
284 /* Actually, verify if mime-type is an image or a text. */
285 $viewable = array ('image', 'text');
286 $decomposed = explode ('/', $mime);
287 return in_array ($decomposed[0], $viewable);
288 }
289 return false;
290 }
291
292
293 // Error handling functions.
294 //! Global array that contains all registered errors.
295 $error_list = array ();
296
297 /**
298 * Adds an error to the list of errors.
299 * @param $title the error's title
300 * @param $description is a human-friendly description of the problem.
301 */
302 function
303 add_error ($title, $description)
304 {
305 global $error_list;
306 $error_list[] = '<p>' . $title. '<br />' . $description. '</p>';
307 }
308
309 /**
310 * Informs whether any error has been registered yet.
311 * @return true if there are errors.
312 */
313 function
314 has_error ()
315 {
316 global $error_list;
317 return !empty ($error_list);
318 }
319
320 /**
321 * Displays all the errors.
322 */
323 function
324 show_errors ()
325 {
326 if (has_error ())
327 {
328 global $error_list;
329 echo '<div class="error">';
330 foreach ($error_list as $error)
331 {
332 echo $error;
333 }
334 echo '</div>';
335 }
336 }
337
338 /**
339 * Read link informations
340 * @return array containing informations.
341 */
342 function
343 jirafeau_get_link ($hash)
344 {
345 $out = array ();
346 $link = VAR_LINKS . $hash;
347
348 if (!file_exists ($link))
349 return $out;
350
351 $c = file ($link);
352 $out['file_name'] = trim ($c[0]);
353 $out['mime_type'] = trim ($c[1]);
354 $out['file_size'] = trim ($c[2]);
355 $out['key'] = trim ($c[3], NL);
356 $out['time'] = trim ($c[4]);
357 $out['md5'] = trim ($c[5]);
358 $out['onetime'] = trim ($c[6]);
359 $out['upload_date'] = trim ($c[7]);
360 $out['ip'] = trim ($c[8]);
361 $out['link_code'] = trim ($c[9]);
362
363 return $out;
364 }
365
366 function
367 jirafeau_human_size ($octets)
368 {
369 $u = array ('B', 'KB', 'MB', 'GB', 'TB');
370 $o = max ($octets, 0);
371 $p = min (floor (($o ? log ($o) : 0) / log (1024)), count ($u) - 1);
372 $o /= pow (1024, $p);
373 return round ($o, 1) . $u[$p];
374 }
375
376 /**
377 * List files in admin interface.
378 */
379 function
380 jirafeau_admin_list ($name, $file_hash, $link_hash)
381 {
382 $links_dir = scandir (VAR_LINKS);
383 echo '<fieldset><legend>';
384 if (!empty ($name))
385 echo $name . ' ';
386 if (!empty ($file_hash))
387 echo $file_hash . ' ';
388 if (!empty ($link_hash))
389 echo $link_hash . ' ';
390 if (empty ($name) && empty ($file_hash) && empty ($link_hash))
391 echo _('List all files');
392 echo '</legend>';
393 echo '<table>';
394 echo '<tr>';
395 echo '<td>' . _('Filename') . '</td>';
396 echo '<td>' . _('Type') . '</td>';
397 echo '<td>' . _('Size') . '</td>';
398 echo '<td>' . _('Expire') . '</td>';
399 echo '<td>' . _('Onetime') . '</td>';
400 echo '<td>' . _('Upload date') . '</td>';
401 echo '<td>' . _('Origin') . '</td>';
402 echo '<td>' . _('Action') . '</td>';
403 echo '</tr>';
404 foreach ($links_dir as $link)
405 {
406 if (strcmp ($link, '.') == 0 || strcmp ($link, '..') == 0 ||
407 preg_match ('/\.tmp/i', "$link"))
408 continue;
409 /* Read link informations. */
410 $l = jirafeau_get_link ($link);
411
412 /* Filter. */
413 if (!empty ($name) && $name != $l['file_name'])
414 continue;
415 if (!empty ($file_hash) && $file_hash != $l['md5'])
416 continue;
417 if (!empty ($link_hash) && $link_hash != $link)
418 continue;
419
420 /* Print link informations. */
421 echo '<tr>';
422 echo '<td>' . $l['file_name'] . '</td>';
423 echo '<td>' . $l['mime_type'] . '</td>';
424 echo '<td>' . jirafeau_human_size ($l['file_size']) . '</td>';
425 echo '<td>' . ($l['time'] == -1 ? '' : strftime ('%c', $l['time'])) .
426 '</td>';
427 echo '<td>' . $l['onetime'] . '</td>';
428 echo '<td>' . strftime ('%c', $l['upload_date']) . '</td>';
429 echo '<td>' . $l['ip'] . '</td>';
430 echo '<td>' .
431 '<form action = "admin.php" method = "post">' .
432 '<input type = "hidden" name = "action" value = "delete_link"/>' .
433 '<input type = "hidden" name = "link" value = "' . $link . '"/>' .
434 '<input type = "submit" value = "' . _('Del link') . '" />' .
435 '</form>' .
436 '<form action = "admin.php" method = "post">' .
437 '<input type = "hidden" name = "action" value = "delete_file"/>' .
438 '<input type = "hidden" name = "md5" value = "' . $l['md5'] . '"/>' .
439 '<input type = "submit" value = "' . _('Del file and links') . '" />' .
440 '</form>' .
441 '</td>';
442 echo '</tr>';
443 }
444 echo '</table></fieldset>';
445 }
446
447 /**
448 * Clean expired files.
449 * @return number of cleaned files.
450 */
451 function
452 jirafeau_admin_clean ()
453 {
454 $c = 0;
455 $links_dir = scandir (VAR_LINKS);
456
457 foreach ($links_dir as $link)
458 {
459 if (strcmp ($link, '.') == 0 || strcmp ($link, '..') == 0 ||
460 preg_match ('/\.tmp/i', "$link"))
461 continue;
462 /* Read link informations. */
463 $l = jirafeau_get_link ($link);
464 if ($l['time'] > 0 && $l['time'] < time () || // expired
465 !file_exists (VAR_FILES . $l['md5']) || // invalid
466 !file_exists (VAR_FILES . $l['md5'] . '_count')) // invalid
467 {
468 jirafeau_delete ($link);
469 $c++;
470 }
471 }
472 return $c;
473 }
474 ?>

patrick-canterino.de