浏览代码

Merge pull request #20164 from Hystepik/develop#3

NEW dol_uncompress() supports extensions (.gz, .bz2, .zstd). Only .zip was supported before.
Laurent Destailleur 3 年之前
父节点
当前提交
000ab8ce5f
共有 1 个文件被更改,包括 83 次插入46 次删除
  1. 83 46
      htdocs/core/lib/files.lib.php

+ 83 - 46
htdocs/core/lib/files.lib.php

@@ -2083,65 +2083,102 @@ function dol_compress_file($inputfile, $outputfile, $mode = "gz", &$errorstring
  */
 function dol_uncompress($inputfile, $outputdir)
 {
-	global $conf, $langs;
-
-	if (defined('ODTPHP_PATHTOPCLZIP') && empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_UNCOMPRESS)) {
-		dol_syslog("Constant ODTPHP_PATHTOPCLZIP for pclzip library is set to ".ODTPHP_PATHTOPCLZIP.", so we use Pclzip to unzip into ".$outputdir);
-		include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
-		$archive = new PclZip($inputfile);
-
-		// Extract into outputdir, but only files that match the regex '/^((?!\.\.).)*$/' that means "does not include .."
-		$result = $archive->extract(PCLZIP_OPT_PATH, $outputdir, PCLZIP_OPT_BY_PREG, '/^((?!\.\.).)*$/');
+	global $conf, $langs, $db;
+
+	$fileinfo = pathinfo($inputfile);
+	$fileinfo["extension"] = strtolower($fileinfo["extension"]);
+	
+	if ($fileinfo["extension"] == "zip") {
+		if (defined('ODTPHP_PATHTOPCLZIP') && empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_UNCOMPRESS)) {
+			dol_syslog("Constant ODTPHP_PATHTOPCLZIP for pclzip library is set to ".ODTPHP_PATHTOPCLZIP.", so we use Pclzip to unzip into ".$outputdir);
+			include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
+			$archive = new PclZip($inputfile);
+
+			// Extract into outputdir, but only files that match the regex '/^((?!\.\.).)*$/' that means "does not include .."
+			$result = $archive->extract(PCLZIP_OPT_PATH, $outputdir, PCLZIP_OPT_BY_PREG, '/^((?!\.\.).)*$/');
+
+			if (!is_array($result) && $result <= 0) {
+				return array('error'=>$archive->errorInfo(true));
+			} else {
+				$ok = 1;
+				$errmsg = '';
+				// Loop on each file to check result for unzipping file
+				foreach ($result as $key => $val) {
+					if ($val['status'] == 'path_creation_fail') {
+						$langs->load("errors");
+						$ok = 0;
+						$errmsg = $langs->trans("ErrorFailToCreateDir", $val['filename']);
+						break;
+					}
+				}
 
-		if (!is_array($result) && $result <= 0) {
-			return array('error'=>$archive->errorInfo(true));
-		} else {
-			$ok = 1;
-			$errmsg = '';
-			// Loop on each file to check result for unzipping file
-			foreach ($result as $key => $val) {
-				if ($val['status'] == 'path_creation_fail') {
-					$langs->load("errors");
-					$ok = 0;
-					$errmsg = $langs->trans("ErrorFailToCreateDir", $val['filename']);
-					break;
+				if ($ok) {
+					return array();
+				} else {
+					return array('error'=>$errmsg);
 				}
 			}
+		}
 
-			if ($ok) {
+		if (class_exists('ZipArchive')) {	// Must install php-zip to have it
+			dol_syslog("Class ZipArchive is set so we unzip using ZipArchive to unzip into ".$outputdir);
+			$zip = new ZipArchive;
+			$res = $zip->open($inputfile);
+			if ($res === true) {
+				//$zip->extractTo($outputdir.'/');
+				// We must extract one file at time so we can check that file name does not contains '..' to avoid transversal path of zip built for example using
+				// python3 path_traversal_archiver.py <Created_file_name> test.zip -l 10 -p tmp/
+				// with -l is the range of dot to go back in path.
+				// and path_traversal_archiver.py found at https://github.com/Alamot/code-snippets/blob/master/path_traversal/path_traversal_archiver.py
+				for ($i = 0; $i < $zip->numFiles; $i++) {
+					if (preg_match('/\.\./', $zip->getNameIndex($i))) {
+						dol_syslog("Warning: Try to unzip a file with a transversal path ".$zip->getNameIndex($i), LOG_WARNING);
+						continue; // Discard the file
+					}
+					$zip->extractTo($outputdir.'/', array($zip->getNameIndex($i)));
+				}
+
+				$zip->close();
 				return array();
 			} else {
-				return array('error'=>$errmsg);
+				return array('error'=>'ErrUnzipFails');
 			}
 		}
-	}
-
-	if (class_exists('ZipArchive')) {	// Must install php-zip to have it
-		dol_syslog("Class ZipArchive is set so we unzip using ZipArchive to unzip into ".$outputdir);
-		$zip = new ZipArchive;
-		$res = $zip->open($inputfile);
-		if ($res === true) {
-			//$zip->extractTo($outputdir.'/');
-			// We must extract one file at time so we can check that file name does not contains '..' to avoid transversal path of zip built for example using
-			// python3 path_traversal_archiver.py <Created_file_name> test.zip -l 10 -p tmp/
-			// with -l is the range of dot to go back in path.
-			// and path_traversal_archiver.py found at https://github.com/Alamot/code-snippets/blob/master/path_traversal/path_traversal_archiver.py
-			for ($i = 0; $i < $zip->numFiles; $i++) {
-				if (preg_match('/\.\./', $zip->getNameIndex($i))) {
-					dol_syslog("Warning: Try to unzip a file with a transversal path ".$zip->getNameIndex($i), LOG_WARNING);
-					continue; // Discard the file
-				}
-				$zip->extractTo($outputdir.'/', array($zip->getNameIndex($i)));
-			}
 
-			$zip->close();
-			return array();
+		return array('error'=>'ErrNoZipEngine');
+	} elseif (in_array($fileinfo["extension"], array('gz', 'bz2', 'zst'))) {
+		include_once DOL_DOCUMENT_ROOT."/core/class/utils.class.php";
+		$utils = new Utils($db);
+	
+		$extension = strtolower(pathinfo($fileinfo["filename"], PATHINFO_EXTENSION));
+		if ($extension == "tar") {
+			$cmd = 'tar -C '.escapeshellcmd(dol_sanitizePathName($outputdir)).' -xvf '.escapeshellcmd(dol_sanitizePathName($fileinfo["dirname"]).'/'.dol_sanitizeFileName($fileinfo["basename"]));
+			$resarray = $utils->executeCLI($cmd, $outputdir);
 		} else {
-			return array('error'=>'ErrUnzipFails');
+			$program = "";
+			if ($fileinfo["extension"] == "gz") {
+				$program = 'gzip';
+			} elseif ($fileinfo["extension"] == "bz2") {
+				$program = 'bzip2';
+			} elseif ($fileinfo["extension"] == "zst") {
+				$program = 'zstd';
+			} else {
+				return array('error'=>'ErrFileExtension');
+			}
+			$cmd = $program.' -dc '.escapeshellcmd(dol_sanitizePathName($fileinfo["dirname"]).'/'.dol_sanitizeFileName($fileinfo["basename"]));
+			$outputfilename = escapeshellcmd(dol_sanitizePathName($outputdir).'/'.dol_sanitizeFileName($fileinfo["filename"]));
+			$resarray = $utils->executeCLI($cmd, $outputfilename, 0, $outputfilename);
+			if ($resarray["output"] == 2) {
+				$resarray["error"] = "ErrFilePermOrFileNotFound";
+			}
+			if ($resarray["output"] == 1) {
+				$resarray["error"] = "Error";
+			}
 		}
+		return $resarray["output"] != 0 ? $resarray["error"] : array();
 	}
 
-	return array('error'=>'ErrNoZipEngine');
+	return array('error'=>'ErrFileExtension');
 }