]> git.p6c8.net - jirafeau.git/commitdiff
[FEATURE] Support diffent types of file hashing
authorJerome Jutteau <jerome@jutteau.fr>
Wed, 4 Dec 2019 20:03:35 +0000 (21:03 +0100)
committerJerome Jutteau <jerome@jutteau.fr>
Wed, 4 Dec 2019 21:34:30 +0000 (22:34 +0100)
Useful to avoid hash efforts on large files.

ref #206

Signed-off-by: Jerome Jutteau <jerome@jutteau.fr>
README.md
lib/config.original.php
lib/functions.php
script.php

index 8e6fe31c93b4ee4cec2d829bc01fd185168b31bd..615c3ea2df19fcc4a2d6b99a0a11db2a063b5376 100644 (file)
--- a/README.md
+++ b/README.md
@@ -334,9 +334,11 @@ If someone use his/her delete link or an admin cleans expired links, this will d
 
 When the counter falls to zero, the file is destroyed.
 
+In order to know if a newly uploaded file already exist, Jirafeau will hash the file using md5 by default but other methods are available (see `file_hash` documentation in `lib/config.original.php`).
+
 ### What is the difference between "delete link" and "delete file and links" in admin interface?
 
-As explained in the previous question, files with the same md5 hash are not duplicated and a reference counter stores the number of links pointing to a single file.
+As explained in the previous question, files with the same hash are not duplicated and a reference counter stores the number of links pointing to a single file.
 So:
 - The button "delete link" will delete the reference to the file but might not destroy the file.
 - The button "delete file and links" will delete all references pointing to the file and will destroy the file.
index 7b1d4ec8e4135003ec149bff8884cb17a4aaad77..2fe91fdd3e619852b8fc0e339013b37d0d54eea7 100644 (file)
@@ -147,6 +147,16 @@ $cfg['maximal_upload_size'] = 0;
  */
 $cfg['proxy_ip'] = array();
 
+/* File hash
+ * In order to make file deduplication work, files can be hashed through different methods.
+ * By default, files are hashed through md5 but other methods are available.
+ * Possible values are 'md5' and 'md5_outside'.
+ * With 'md5' option, the whole file is hashed through md5. This is the default.
+ * With 'md5_outside', md5 is used to hash the first part of the file, the last part of the file
+ * and the file's size. This method is fast for large files but cannot be perfect.
+ */
+$cfg['file_hash'] = 'md5';
+
 /* Required flag to test if the installation is already installed
  * or needs to start the installation script
  */
index 349274546feb7ee851d46b5f80ae16db85c18635..4e227967475973466a0c186fcbf616aeeaecf559 100644 (file)
@@ -319,6 +319,48 @@ function jirafeau_delete_file($hash)
     return $count;
 }
 
+
+/** hash file's content
+ * @param $method hash method, see 'file_hash' option. 'md5' or 'md5_outside'.
+ * @param $file_path file to hash
+ * @returns hash string
+ */
+function jirafeau_hash_file($method, $file_path)
+{
+    switch ($method) {
+        case 'md5_outside':
+            return jirafeau_md5_outside($file_path);
+        case 'md5':
+            return md5_file($file_path);
+    }
+    return md5_file($file_path);
+}
+
+/** hash part of file: start, end and size.
+ * This is a partial file hash, faster but weaker.
+ * @param $file_path file to hash
+ * @returns hash string
+ */
+function jirafeau_md5_outside($file_path)
+{
+    $size = filesize($file_path);
+    if ($size === false) {
+        $size = 0;
+    }
+    $handle = fopen($file_path, "r");
+    if ($handle === false) {
+        return false;
+    }
+    $first = fread($handle, 64);
+    if ($first === false) {
+        return false;
+    }
+    fseek($handle, $size < 64 ? 0 : $size - 64);
+    $last = fread($handle, 64);
+    fclose($handle);
+    return md5($first . $last . $size);
+}
+
 /**
  * handles an uploaded file
  * @param $file the file struct given by $_FILE[]
@@ -333,7 +375,7 @@ function jirafeau_delete_file($hash)
  *   'link' => the link name of the uploaded file
  *   'delete_link' => the link code to delete file
  */
-function jirafeau_upload($file, $one_time_download, $key, $time, $ip, $crypt, $link_name_length)
+function jirafeau_upload($file, $one_time_download, $key, $time, $ip, $crypt, $link_name_length, $file_hash_method)
 {
     if (empty($file['tmp_name']) || !is_uploaded_file($file['tmp_name'])) {
         return (array(
@@ -361,7 +403,7 @@ function jirafeau_upload($file, $one_time_download, $key, $time, $ip, $crypt, $l
     }
 
     /* file informations */
-    $hash = md5_file($file['tmp_name']);
+    $hash = jirafeau_hash_file($file_hash_method, $file['tmp_name']);
     $name = str_replace(NL, '', trim($file['name']));
     $mime_type = $file['type'];
     $size = $file['size'];
@@ -893,7 +935,7 @@ function jirafeau_async_push($ref, $data, $code, $max_file_size)
   * @param $link_name_length link name length
   * @return a string containing the download reference followed by a delete code or the string 'Error'
   */
-function jirafeau_async_end($ref, $code, $crypt, $link_name_length)
+function jirafeau_async_end($ref, $code, $crypt, $link_name_length, $file_hash_method)
 {
     /* Get async infos. */
     $a = jirafeau_get_async_ref($ref);
@@ -917,7 +959,7 @@ function jirafeau_async_end($ref, $code, $crypt, $link_name_length)
         }
     }
 
-    $hash = md5_file($p);
+    $hash = jirafeau_hash_file($file_hash_method, $p);
     $size = filesize($p);
     $np = s2p($hash);
     $delete_link_code = jirafeau_gen_random(5);
index 13a88b88624332efa25a62cd2b30c3d0a10d2d96..5fe60e2c4829a02000c36ec2006d7418c40c25bd 100644 (file)
@@ -127,9 +127,10 @@ if (isset($_FILES['file']) && is_writable(VAR_FILES)
     }
 
     $res = jirafeau_upload($_FILES['file'],
-                            isset($_POST['one_time_download']),
-                            $key, $time, get_ip_address($cfg),
-                            $cfg['enable_crypt'], $cfg['link_name_length']);
+                           isset($_POST['one_time_download']),
+                           $key, $time, get_ip_address($cfg),
+                           $cfg['enable_crypt'], $cfg['link_name_length'],
+                           $cfg['file_hash']);
 
     if (empty($res) || $res['error']['has_error']) {
         echo 'Error 6 ' . $res['error']['why'];
@@ -466,7 +467,7 @@ elseif (isset($_GET['end_async'])) {
         || !isset($_POST['code'])) {
         echo 'Error 24';
     } else {
-        echo jirafeau_async_end($_POST['ref'], $_POST['code'], $cfg['enable_crypt'], $cfg['link_name_length']);
+        echo jirafeau_async_end($_POST['ref'], $_POST['code'], $cfg['enable_crypt'], $cfg['link_name_length'], $cfg['file_hash']);
     }
 } else {
     echo 'Error 25';

patrick-canterino.de