diff options
-rw-r--r-- | application/Utils.php | 89 | ||||
-rw-r--r-- | index.php | 32 | ||||
-rw-r--r-- | tests/UtilsTest.php | 80 | ||||
-rw-r--r-- | tpl/vintage/import.html | 2 |
4 files changed, 172 insertions, 31 deletions
diff --git a/application/Utils.php b/application/Utils.php index d6e06610..3ef2a7e2 100644 --- a/application/Utils.php +++ b/application/Utils.php | |||
@@ -345,3 +345,92 @@ function format_date($date, $time = true, $intl = true) | |||
345 | 345 | ||
346 | return $formatter->format($date); | 346 | return $formatter->format($date); |
347 | } | 347 | } |
348 | |||
349 | /** | ||
350 | * Check if the input is an integer, no matter its real type. | ||
351 | * | ||
352 | * PHP is a bit messy regarding this: | ||
353 | * - is_int returns false if the input is a string | ||
354 | * - ctype_digit returns false if the input is an integer or negative | ||
355 | * | ||
356 | * @param mixed $input value | ||
357 | * | ||
358 | * @return bool true if the input is an integer, false otherwise | ||
359 | */ | ||
360 | function is_integer_mixed($input) | ||
361 | { | ||
362 | if (is_array($input) || is_bool($input) || is_object($input)) { | ||
363 | return false; | ||
364 | } | ||
365 | $input = strval($input); | ||
366 | return ctype_digit($input) || (startsWith($input, '-') && ctype_digit(substr($input, 1))); | ||
367 | } | ||
368 | |||
369 | /** | ||
370 | * Convert post_max_size/upload_max_filesize (e.g. '16M') parameters to bytes. | ||
371 | * | ||
372 | * @param string $val Size expressed in string. | ||
373 | * | ||
374 | * @return int Size expressed in bytes. | ||
375 | */ | ||
376 | function return_bytes($val) | ||
377 | { | ||
378 | if (is_integer_mixed($val) || $val === '0' || empty($val)) { | ||
379 | return $val; | ||
380 | } | ||
381 | $val = trim($val); | ||
382 | $last = strtolower($val[strlen($val)-1]); | ||
383 | $val = intval(substr($val, 0, -1)); | ||
384 | switch($last) { | ||
385 | case 'g': $val *= 1024; | ||
386 | case 'm': $val *= 1024; | ||
387 | case 'k': $val *= 1024; | ||
388 | } | ||
389 | return $val; | ||
390 | } | ||
391 | |||
392 | /** | ||
393 | * Return a human readable size from bytes. | ||
394 | * | ||
395 | * @param int $bytes value | ||
396 | * | ||
397 | * @return string Human readable size | ||
398 | */ | ||
399 | function human_bytes($bytes) | ||
400 | { | ||
401 | if ($bytes === '') { | ||
402 | return t('Setting not set'); | ||
403 | } | ||
404 | if (! is_integer_mixed($bytes)) { | ||
405 | return $bytes; | ||
406 | } | ||
407 | $bytes = intval($bytes); | ||
408 | if ($bytes === 0) { | ||
409 | return t('Unlimited'); | ||
410 | } | ||
411 | |||
412 | $units = [t('B'), t('kiB'), t('MiB'), t('GiB')]; | ||
413 | for ($i = 0; $i < count($units) && $bytes >= 1024; ++$i) { | ||
414 | $bytes /= 1024; | ||
415 | } | ||
416 | |||
417 | return $bytes . $units[$i]; | ||
418 | } | ||
419 | |||
420 | /** | ||
421 | * Try to determine max file size for uploads (POST). | ||
422 | * Returns an integer (in bytes) | ||
423 | * | ||
424 | * @param mixed $limitPost post_max_size PHP setting | ||
425 | * @param mixed $limitUpload upload_max_filesize PHP setting | ||
426 | * | ||
427 | * @return int max upload file size in bytes. | ||
428 | */ | ||
429 | function get_max_upload_size($limitPost, $limitUpload) | ||
430 | { | ||
431 | $size1 = return_bytes($limitPost); | ||
432 | $size2 = return_bytes($limitUpload); | ||
433 | // Return the smaller of two: | ||
434 | $maxsize = min($size1, $size2); | ||
435 | return human_bytes($maxsize); | ||
436 | } | ||
@@ -473,34 +473,6 @@ if (isset($_POST['login'])) | |||
473 | } | 473 | } |
474 | 474 | ||
475 | // ------------------------------------------------------------------------------------------ | 475 | // ------------------------------------------------------------------------------------------ |
476 | // Misc utility functions: | ||
477 | |||
478 | // Convert post_max_size/upload_max_filesize (e.g. '16M') parameters to bytes. | ||
479 | function return_bytes($val) | ||
480 | { | ||
481 | $val = trim($val); $last=strtolower($val[strlen($val)-1]); | ||
482 | switch($last) | ||
483 | { | ||
484 | case 'g': $val *= 1024; | ||
485 | case 'm': $val *= 1024; | ||
486 | case 'k': $val *= 1024; | ||
487 | } | ||
488 | return $val; | ||
489 | } | ||
490 | |||
491 | // Try to determine max file size for uploads (POST). | ||
492 | // Returns an integer (in bytes) | ||
493 | function getMaxFileSize() | ||
494 | { | ||
495 | $size1 = return_bytes(ini_get('post_max_size')); | ||
496 | $size2 = return_bytes(ini_get('upload_max_filesize')); | ||
497 | // Return the smaller of two: | ||
498 | $maxsize = min($size1,$size2); | ||
499 | // FIXME: Then convert back to readable notations ? (e.g. 2M instead of 2000000) | ||
500 | return $maxsize; | ||
501 | } | ||
502 | |||
503 | // ------------------------------------------------------------------------------------------ | ||
504 | // Token management for XSRF protection | 476 | // Token management for XSRF protection |
505 | // Token should be used in any form which acts on data (create,update,delete,import...). | 477 | // Token should be used in any form which acts on data (create,update,delete,import...). |
506 | if (!isset($_SESSION['tokens'])) $_SESSION['tokens']=array(); // Token are attached to the session. | 478 | if (!isset($_SESSION['tokens'])) $_SESSION['tokens']=array(); // Token are attached to the session. |
@@ -1517,7 +1489,7 @@ function renderPage($conf, $pluginManager, $LINKSDB) | |||
1517 | 1489 | ||
1518 | if (! isset($_POST['token']) || ! isset($_FILES['filetoupload'])) { | 1490 | if (! isset($_POST['token']) || ! isset($_FILES['filetoupload'])) { |
1519 | // Show import dialog | 1491 | // Show import dialog |
1520 | $PAGE->assign('maxfilesize', getMaxFileSize()); | 1492 | $PAGE->assign('maxfilesize', get_max_upload_size(ini_get('post_max_size'), ini_get('upload_max_filesize'))); |
1521 | $PAGE->renderPage('import'); | 1493 | $PAGE->renderPage('import'); |
1522 | exit; | 1494 | exit; |
1523 | } | 1495 | } |
@@ -1527,7 +1499,7 @@ function renderPage($conf, $pluginManager, $LINKSDB) | |||
1527 | // The file is too big or some form field may be missing. | 1499 | // The file is too big or some form field may be missing. |
1528 | echo '<script>alert("The file you are trying to upload is probably' | 1500 | echo '<script>alert("The file you are trying to upload is probably' |
1529 | .' bigger than what this webserver can accept (' | 1501 | .' bigger than what this webserver can accept (' |
1530 | .getMaxFileSize().' bytes).' | 1502 | .get_max_upload_size(ini_get('post_max_size'), ini_get('upload_max_filesize')).').' |
1531 | .' Please upload in smaller chunks.");document.location=\'?do=' | 1503 | .' Please upload in smaller chunks.");document.location=\'?do=' |
1532 | .Router::$PAGE_IMPORT .'\';</script>'; | 1504 | .Router::$PAGE_IMPORT .'\';</script>'; |
1533 | exit; | 1505 | exit; |
diff --git a/tests/UtilsTest.php b/tests/UtilsTest.php index e70cc1ae..e5ff01e6 100644 --- a/tests/UtilsTest.php +++ b/tests/UtilsTest.php | |||
@@ -4,6 +4,7 @@ | |||
4 | */ | 4 | */ |
5 | 5 | ||
6 | require_once 'application/Utils.php'; | 6 | require_once 'application/Utils.php'; |
7 | require_once 'application/Languages.php'; | ||
7 | require_once 'tests/utils/ReferenceSessionIdHashes.php'; | 8 | require_once 'tests/utils/ReferenceSessionIdHashes.php'; |
8 | 9 | ||
9 | // Initialize reference data before PHPUnit starts a session | 10 | // Initialize reference data before PHPUnit starts a session |
@@ -326,4 +327,83 @@ class UtilsTest extends PHPUnit_Framework_TestCase | |||
326 | $this->assertFalse(format_date([])); | 327 | $this->assertFalse(format_date([])); |
327 | $this->assertFalse(format_date(null)); | 328 | $this->assertFalse(format_date(null)); |
328 | } | 329 | } |
330 | |||
331 | /** | ||
332 | * Test is_integer_mixed with valid values | ||
333 | */ | ||
334 | public function testIsIntegerMixedValid() | ||
335 | { | ||
336 | $this->assertTrue(is_integer_mixed(12)); | ||
337 | $this->assertTrue(is_integer_mixed('12')); | ||
338 | $this->assertTrue(is_integer_mixed(-12)); | ||
339 | $this->assertTrue(is_integer_mixed('-12')); | ||
340 | $this->assertTrue(is_integer_mixed(0)); | ||
341 | $this->assertTrue(is_integer_mixed('0')); | ||
342 | $this->assertTrue(is_integer_mixed(0x0a)); | ||
343 | } | ||
344 | |||
345 | /** | ||
346 | * Test is_integer_mixed with invalid values | ||
347 | */ | ||
348 | public function testIsIntegerMixedInvalid() | ||
349 | { | ||
350 | $this->assertFalse(is_integer_mixed(true)); | ||
351 | $this->assertFalse(is_integer_mixed(false)); | ||
352 | $this->assertFalse(is_integer_mixed([])); | ||
353 | $this->assertFalse(is_integer_mixed(['test'])); | ||
354 | $this->assertFalse(is_integer_mixed([12])); | ||
355 | $this->assertFalse(is_integer_mixed(new DateTime())); | ||
356 | $this->assertFalse(is_integer_mixed('0x0a')); | ||
357 | $this->assertFalse(is_integer_mixed('12k')); | ||
358 | $this->assertFalse(is_integer_mixed('k12')); | ||
359 | $this->assertFalse(is_integer_mixed('')); | ||
360 | } | ||
361 | |||
362 | /** | ||
363 | * Test return_bytes | ||
364 | */ | ||
365 | public function testReturnBytes() | ||
366 | { | ||
367 | $this->assertEquals(2 * 1024, return_bytes('2k')); | ||
368 | $this->assertEquals(2 * 1024, return_bytes('2K')); | ||
369 | $this->assertEquals(2 * (pow(1024, 2)), return_bytes('2m')); | ||
370 | $this->assertEquals(2 * (pow(1024, 2)), return_bytes('2M')); | ||
371 | $this->assertEquals(2 * (pow(1024, 3)), return_bytes('2g')); | ||
372 | $this->assertEquals(2 * (pow(1024, 3)), return_bytes('2G')); | ||
373 | $this->assertEquals(374, return_bytes('374')); | ||
374 | $this->assertEquals(374, return_bytes(374)); | ||
375 | $this->assertEquals(0, return_bytes('0')); | ||
376 | $this->assertEquals(0, return_bytes(0)); | ||
377 | $this->assertEquals(-1, return_bytes('-1')); | ||
378 | $this->assertEquals(-1, return_bytes(-1)); | ||
379 | $this->assertEquals('', return_bytes('')); | ||
380 | } | ||
381 | |||
382 | /** | ||
383 | * Test human_bytes | ||
384 | */ | ||
385 | public function testHumanBytes() | ||
386 | { | ||
387 | $this->assertEquals('2kiB', human_bytes(2 * 1024)); | ||
388 | $this->assertEquals('2kiB', human_bytes(strval(2 * 1024))); | ||
389 | $this->assertEquals('2MiB', human_bytes(2 * (pow(1024, 2)))); | ||
390 | $this->assertEquals('2MiB', human_bytes(strval(2 * (pow(1024, 2))))); | ||
391 | $this->assertEquals('2GiB', human_bytes(2 * (pow(1024, 3)))); | ||
392 | $this->assertEquals('2GiB', human_bytes(strval(2 * (pow(1024, 3))))); | ||
393 | $this->assertEquals('374B', human_bytes(374)); | ||
394 | $this->assertEquals('374B', human_bytes('374')); | ||
395 | $this->assertEquals('Unlimited', human_bytes('0')); | ||
396 | $this->assertEquals('Unlimited', human_bytes(0)); | ||
397 | $this->assertEquals('Setting not set', human_bytes('')); | ||
398 | } | ||
399 | |||
400 | /** | ||
401 | * Test get_max_upload_size | ||
402 | */ | ||
403 | public function testGetMaxUploadSize() | ||
404 | { | ||
405 | $this->assertEquals('1MiB', get_max_upload_size(2097152, '1024k')); | ||
406 | $this->assertEquals('1MiB', get_max_upload_size('1m', '2m')); | ||
407 | $this->assertEquals('100B', get_max_upload_size(100, 100)); | ||
408 | } | ||
329 | } | 409 | } |
diff --git a/tpl/vintage/import.html b/tpl/vintage/import.html index 071e1160..bb9e4a56 100644 --- a/tpl/vintage/import.html +++ b/tpl/vintage/import.html | |||
@@ -5,7 +5,7 @@ | |||
5 | <div id="pageheader"> | 5 | <div id="pageheader"> |
6 | {include="page.header"} | 6 | {include="page.header"} |
7 | <div id="uploaddiv"> | 7 | <div id="uploaddiv"> |
8 | Import Netscape HTML bookmarks (as exported from Firefox/Chrome/Opera/Delicious/Diigo...) (Max: {$maxfilesize} bytes). | 8 | Import Netscape HTML bookmarks (as exported from Firefox/Chrome/Opera/Delicious/Diigo...) (Max: {$maxfilesize}). |
9 | <form method="POST" action="?do=import" enctype="multipart/form-data" | 9 | <form method="POST" action="?do=import" enctype="multipart/form-data" |
10 | name="uploadform" id="uploadform"> | 10 | name="uploadform" id="uploadform"> |
11 | <input type="hidden" name="token" value="{$token}"> | 11 | <input type="hidden" name="token" value="{$token}"> |