]> git.p6c8.net - jirafeau.git/blob - lib/functions.php
Add option to activate or not preview mode
[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 /**
22 * Transform a string in a path by seperating each letters by a '/'.
23 * @return path finishing with a '/'
24 */
25 function
26 s2p ($s)
27 {
28 $p = '';
29 for ($i = 0; $i < strlen ($s); $i++)
30 $p .= $s{$i} . '/';
31 return $p;
32 }
33
34 function
35 jirafeau_human_size ($octets)
36 {
37 $u = array ('B', 'KB', 'MB', 'GB', 'TB');
38 $o = max ($octets, 0);
39 $p = min (floor (($o ? log ($o) : 0) / log (1024)), count ($u) - 1);
40 $o /= pow (1024, $p);
41 return round ($o, 1) . $u[$p];
42 }
43
44 function
45 jirafeau_clean_rm_link ($link)
46 {
47 $p = s2p ("$link");
48 if (file_exists (VAR_LINKS . $p . $link))
49 unlink (VAR_LINKS . $p . $link);
50 $parse = VAR_LINKS . $p;
51 $scan = array();
52 while (file_exists ($parse)
53 && ($scan = scandir ($parse))
54 && count ($scan) == 2 // '.' and '..' folders => empty.
55 && basename ($parse) != basename (VAR_LINKS))
56 {
57 rmdir ($parse);
58 $parse = substr ($parse, 0, strlen($parse) - strlen(basename ($parse)) - 1);
59 }
60 }
61
62 function
63 jirafeau_clean_rm_file ($md5)
64 {
65 $p = s2p ("$md5");
66 if (file_exists (VAR_FILES . $p . $md5))
67 unlink (VAR_FILES . $p . $md5);
68 if (file_exists (VAR_FILES . $p . $md5 . '_count'))
69 unlink (VAR_FILES . $p . $md5 . '_count');
70 $parse = VAR_FILES . $p;
71 $scan = array();
72 while (file_exists ($parse)
73 && ($scan = scandir ($parse))
74 && count ($scan) == 2 // '.' and '..' folders => empty.
75 && basename ($parse) != basename (VAR_FILES))
76 {
77 rmdir ($parse);
78 $parse = substr ($parse, 0, strlen($parse) - strlen(basename ($parse)) - 1);
79 }
80 }
81
82 /**
83 * transforms a php.ini string representing a value in an integer
84 * @param $value the value from php.ini
85 * @returns an integer for this value
86 */
87 function jirafeau_ini_to_bytes ($value)
88 {
89 $modifier = substr ($value, -1);
90 $bytes = substr ($value, 0, -1);
91 switch (strtoupper ($modifier))
92 {
93 case 'P':
94 $bytes *= 1024;
95 case 'T':
96 $bytes *= 1024;
97 case 'G':
98 $bytes *= 1024;
99 case 'M':
100 $bytes *= 1024;
101 case 'K':
102 $bytes *= 1024;
103 default:
104 break;
105 }
106 return $bytes;
107 }
108
109 /**
110 * gets the maximum upload size according to php.ini
111 * @returns the maximum upload size string
112 */
113 function
114 jirafeau_get_max_upload_size ()
115 {
116 return jirafeau_human_size(
117 min (jirafeau_ini_to_bytes (ini_get ('post_max_size')),
118 jirafeau_ini_to_bytes (ini_get ('upload_max_filesize'))));
119 }
120
121 /**
122 * gets a string explaining the error
123 * @param $code the error code
124 * @returns a string explaining the error
125 */
126 function
127 jirafeau_upload_errstr ($code)
128 {
129 switch ($code)
130 {
131 case UPLOAD_ERR_INI_SIZE:
132 case UPLOAD_ERR_FORM_SIZE:
133 return t('Your file exceeds the maximum authorized file size. ');
134 break;
135
136 case UPLOAD_ERR_PARTIAL:
137 case UPLOAD_ERR_NO_FILE:
138 return
139 t
140 ('Your file was not uploaded correctly. You may succeed in retrying. ');
141 break;
142
143 case UPLOAD_ERR_NO_TMP_DIR:
144 case UPLOAD_ERR_CANT_WRITE:
145 case UPLOAD_ERR_EXTENSION:
146 return t('Internal error. You may not succeed in retrying. ');
147 break;
148
149 default:
150 break;
151 }
152 return t('Unknown error. ');
153 }
154
155 /** Remove link and it's file
156 * @param $link the link's name (hash)
157 */
158
159 function
160 jirafeau_delete_link ($link)
161 {
162 $l = jirafeau_get_link ($link);
163 if (!count ($l))
164 return;
165
166 jirafeau_clean_rm_link ($link);
167
168 $md5 = $l['md5'];
169 $p = s2p ("$md5");
170
171 $counter = 1;
172 if (file_exists (VAR_FILES . $p . $md5. '_count'))
173 {
174 $content = file (VAR_FILES . $p . $md5. '_count');
175 $counter = trim ($content[0]);
176 }
177 $counter--;
178
179 if ($counter >= 1)
180 {
181 $handle = fopen (VAR_FILES . $p . $md5. '_count', 'w');
182 fwrite ($handle, $counter);
183 fclose ($handle);
184 }
185
186 if ($counter == 0)
187 jirafeau_clean_rm_file ($md5);
188 }
189
190 /**
191 * Delete a file and it's links.
192 */
193 function
194 jirafeau_delete_file ($md5)
195 {
196 $count = 0;
197 /* Get all links files. */
198 $stack = array (VAR_LINKS);
199 while (($d = array_shift ($stack)) && $d != NULL)
200 {
201 $dir = scandir ($d);
202
203 foreach ($dir as $node)
204 {
205 if (strcmp ($node, '.') == 0 || strcmp ($node, '..') == 0 ||
206 preg_match ('/\.tmp/i', "$node"))
207 continue;
208
209 if (is_dir ($d . $node))
210 {
211 /* Push new found directory. */
212 $stack[] = $d . $node . '/';
213 }
214 elseif (is_file ($d . $node))
215 {
216 /* Read link informations. */
217 $l = jirafeau_get_link (basename ($node));
218 if (!count ($l))
219 continue;
220 if ($l['md5'] == $md5)
221 {
222 $count++;
223 jirafeau_delete_link ($node);
224 }
225 }
226 }
227 }
228 jirafeau_clean_rm_file ($md5);
229 return $count;
230 }
231
232 /**
233 * handles an uploaded file
234 * @param $file the file struct given by $_FILE[]
235 * @param $one_time_download is the file a one time download ?
236 * @param $key if not empty, protect the file with this key
237 * @param $time the time of validity of the file
238 * @param $ip uploader's ip
239 * @returns an array containing some information
240 * 'error' => information on possible errors
241 * 'link' => the link name of the uploaded file
242 * 'delete_link' => the link code to delete file
243 */
244 function
245 jirafeau_upload ($file, $one_time_download, $key, $time, $ip)
246 {
247 if (empty ($file['tmp_name']) || !is_uploaded_file ($file['tmp_name']))
248 {
249 return (array(
250 'error' =>
251 array ('has_error' => true,
252 'why' => jirafeau_upload_errstr ($file['error'])),
253 'link' => '',
254 'delete_link' => ''));
255 }
256
257 /* array representing no error */
258 $noerr = array ('has_error' => false, 'why' => '');
259
260 /* file informations */
261 $md5 = md5_file ($file['tmp_name']);
262 $name = trim ($file['name']);
263 $mime_type = $file['type'];
264 $size = $file['size'];
265
266 /* does file already exist ? */
267 $rc = false;
268 $p = s2p ("$md5");
269 if (file_exists (VAR_FILES . $p . $md5))
270 {
271 $rc = unlink ($file['tmp_name']);
272 }
273 elseif ((file_exists (VAR_FILES . $p) || @mkdir (VAR_FILES . $p, 0755, true))
274 && move_uploaded_file ($file['tmp_name'], VAR_FILES . $p . $md5))
275 {
276 $rc = true;
277 }
278 if (!$rc)
279 {
280 return (array(
281 'error' =>
282 array ('has_error' => true,
283 'why' => t('Internal error during file creation.')),
284 'link' =>'',
285 'delete_link' => ''));
286 }
287
288 /* increment or create count file */
289 $counter = 0;
290 if (file_exists (VAR_FILES . $p . $md5 . '_count'))
291 {
292 $content = file (VAR_FILES . $p . $md5. '_count');
293 $counter = trim ($content[0]);
294 }
295 $counter++;
296 $handle = fopen (VAR_FILES . $p . $md5. '_count', 'w');
297 fwrite ($handle, $counter);
298 fclose ($handle);
299
300 /* Create delete code. */
301 $delete_link_code = 0;
302 for ($i = 0; $i < 8; $i++)
303 $delete_link_code .= dechex (rand (0, 16));
304
305 /* md5 password or empty */
306 $password = '';
307 if (!empty ($key))
308 $password = md5 ($key);
309
310 /* create link file */
311 $link_tmp_name = VAR_LINKS . $md5 . rand (0, 10000) . ' .tmp';
312 $handle = fopen ($link_tmp_name, 'w');
313 fwrite ($handle,
314 $name . NL. $mime_type . NL. $size . NL. $password . NL. $time .
315 NL . $md5. NL . ($one_time_download ? 'O' : 'R') . NL.date ('U') .
316 NL. $ip . NL. $delete_link_code . NL);
317 fclose ($handle);
318 $md5_link = md5_file ($link_tmp_name);
319 $l = s2p ("$md5_link");
320 if (!@mkdir (VAR_LINKS . $l, 0755, true) ||
321 !rename ($link_tmp_name, VAR_LINKS . $l . $md5_link))
322 {
323 if (file_exists ($link_tmp_name))
324 unlink ($link_tmp_name);
325
326 $counter--;
327 if ($counter >= 1)
328 {
329 $handle = fopen (VAR_FILES . $p . $md5. '_count', 'w');
330 fwrite ($handle, $counter);
331 fclose ($handle);
332 }
333 else
334 {
335 jirafeau_clean_rm_file ($md5_link);
336 }
337 return (array(
338 'error' =>
339 array ('has_error' => true,
340 'why' => t('Internal error during file creation. ')),
341 'link' =>'',
342 'delete_link' => ''));
343 }
344 return (array ('error' => $noerr,
345 'link' => $md5_link,
346 'delete_link' => $delete_link_code));
347 }
348
349 /**
350 * tells if a mime-type is viewable in a browser
351 * @param $mime the mime type
352 * @returns a boolean telling if a mime type is viewable
353 */
354 function
355 jirafeau_is_viewable ($mime)
356 {
357 if (!empty ($mime))
358 {
359 /* Actually, verify if mime-type is an image or a text. */
360 $viewable = array ('image', 'text');
361 $decomposed = explode ('/', $mime);
362 return in_array ($decomposed[0], $viewable);
363 }
364 return false;
365 }
366
367
368 // Error handling functions.
369 //! Global array that contains all registered errors.
370 $error_list = array ();
371
372 /**
373 * Adds an error to the list of errors.
374 * @param $title the error's title
375 * @param $description is a human-friendly description of the problem.
376 */
377 function
378 add_error ($title, $description)
379 {
380 global $error_list;
381 $error_list[] = '<p>' . $title. '<br />' . $description. '</p>';
382 }
383
384 /**
385 * Informs whether any error has been registered yet.
386 * @return true if there are errors.
387 */
388 function
389 has_error ()
390 {
391 global $error_list;
392 return !empty ($error_list);
393 }
394
395 /**
396 * Displays all the errors.
397 */
398 function
399 show_errors ()
400 {
401 if (has_error ())
402 {
403 global $error_list;
404 echo '<div class="error">';
405 foreach ($error_list as $error)
406 {
407 echo $error;
408 }
409 echo '</div>';
410 }
411 }
412
413 /**
414 * Read link informations
415 * @return array containing informations.
416 */
417 function
418 jirafeau_get_link ($hash)
419 {
420 $out = array ();
421 $link = VAR_LINKS . s2p ("$hash") . $hash;
422
423 if (!file_exists ($link))
424 return $out;
425
426 $c = file ($link);
427 $out['file_name'] = trim ($c[0]);
428 $out['mime_type'] = trim ($c[1]);
429 $out['file_size'] = trim ($c[2]);
430 $out['key'] = trim ($c[3], NL);
431 $out['time'] = trim ($c[4]);
432 $out['md5'] = trim ($c[5]);
433 $out['onetime'] = trim ($c[6]);
434 $out['upload_date'] = trim ($c[7]);
435 $out['ip'] = trim ($c[8]);
436 $out['link_code'] = trim ($c[9]);
437
438 return $out;
439 }
440
441 /**
442 * List files in admin interface.
443 */
444 function
445 jirafeau_admin_list ($name, $file_hash, $link_hash)
446 {
447 echo '<fieldset><legend>';
448 if (!empty ($name))
449 echo t('Filename') . ": $name ";
450 if (!empty ($file_hash))
451 echo t('file') . ": $file_hash ";
452 if (!empty ($link_hash))
453 echo t('link') . ": $link_hash ";
454 if (empty ($name) && empty ($file_hash) && empty ($link_hash))
455 echo t('List all files');
456 echo '</legend>';
457 echo '<table>';
458 echo '<tr>';
459 echo '<td>' . t('Filename') . '</td>';
460 echo '<td>' . t('Type') . '</td>';
461 echo '<td>' . t('Size') . '</td>';
462 echo '<td>' . t('Expire') . '</td>';
463 echo '<td>' . t('Onetime') . '</td>';
464 echo '<td>' . t('Upload date') . '</td>';
465 echo '<td>' . t('Origin') . '</td>';
466 echo '<td>' . t('Action') . '</td>';
467 echo '</tr>';
468
469 /* Get all links files. */
470 $stack = array (VAR_LINKS);
471 while (($d = array_shift ($stack)) && $d != NULL)
472 {
473 $dir = scandir ($d);
474 foreach ($dir as $node)
475 {
476 if (strcmp ($node, '.') == 0 || strcmp ($node, '..') == 0 ||
477 preg_match ('/\.tmp/i', "$node"))
478 continue;
479 if (is_dir ($d . $node))
480 {
481 /* Push new found directory. */
482 $stack[] = $d . $node . '/';
483 }
484 elseif (is_file ($d . $node))
485 {
486 /* Read link informations. */
487 $l = jirafeau_get_link ($node);
488 if (!count ($l))
489 continue;
490
491 /* Filter. */
492 if (!empty ($name) && !preg_match ("/$name/i", $l['file_name']))
493 continue;
494 if (!empty ($file_hash) && $file_hash != $l['md5'])
495 continue;
496 if (!empty ($link_hash) && $link_hash != $node)
497 continue;
498 /* Print link informations. */
499 echo '<tr>';
500 echo '<td>' .
501 '<form action = "admin.php" method = "post">' .
502 '<input type = "hidden" name = "action" value = "download"/>' .
503 '<input type = "hidden" name = "link" value = "' . $node . '"/>' .
504 '<input type = "submit" value = "' . $l['file_name'] . '" />' .
505 '</form>';
506 echo '</td>';
507 echo '<td>' . $l['mime_type'] . '</td>';
508 echo '<td>' . jirafeau_human_size ($l['file_size']) . '</td>';
509 echo '<td>' . ($l['time'] == -1 ? '' : strftime ('%c', $l['time'])) .
510 '</td>';
511 echo '<td>' . $l['onetime'] . '</td>';
512 echo '<td>' . strftime ('%c', $l['upload_date']) . '</td>';
513 echo '<td>' . $l['ip'] . '</td>';
514 echo '<td>' .
515 '<form action = "admin.php" method = "post">' .
516 '<input type = "hidden" name = "action" value = "delete_link"/>' .
517 '<input type = "hidden" name = "link" value = "' . $node . '"/>' .
518 '<input type = "submit" value = "' . t('Del link') . '" />' .
519 '</form>' .
520 '<form action = "admin.php" method = "post">' .
521 '<input type = "hidden" name = "action" value = "delete_file"/>' .
522 '<input type = "hidden" name = "md5" value = "' . $l['md5'] . '"/>' .
523 '<input type = "submit" value = "' . t('Del file and links') . '" />' .
524 '</form>' .
525 '</td>';
526 echo '</tr>';
527 }
528 }
529 }
530 echo '</table></fieldset>';
531 }
532
533 /**
534 * Clean expired files.
535 * @return number of cleaned files.
536 */
537 function
538 jirafeau_admin_clean ()
539 {
540 $count = 0;
541 /* Get all links files. */
542 $stack = array (VAR_LINKS);
543 while (($d = array_shift ($stack)) && $d != NULL)
544 {
545 $dir = scandir ($d);
546
547 foreach ($dir as $node)
548 {
549 if (strcmp ($node, '.') == 0 || strcmp ($node, '..') == 0 ||
550 preg_match ('/\.tmp/i', "$node"))
551 continue;
552
553 if (is_dir ($d . $node))
554 {
555 /* Push new found directory. */
556 $stack[] = $d . $node . '/';
557 }
558 elseif (is_file ($d . $node))
559 {
560 /* Read link informations. */
561 $l = jirafeau_get_link (basename ($node));
562 if (!count ($l))
563 continue;
564 $p = s2p ($l['md5']);
565 if ($l['time'] > 0 && $l['time'] < time () || // expired
566 !file_exists (VAR_FILES . $p . $l['md5']) || // invalid
567 !file_exists (VAR_FILES . $p . $l['md5'] . '_count')) // invalid
568 {
569 jirafeau_delete_link ($node);
570 $count++;
571 }
572 }
573 }
574 }
575 return $count;
576 }
577 ?>

patrick-canterino.de