From 57ed890b73da8e2ff3ad5a3f209d47b5c9bd71ed Mon Sep 17 00:00:00 2001 From: lmarcouiller Date: Wed, 23 Feb 2022 12:28:37 +0100 Subject: [PATCH] NEW : dol_uncompress new extensions --- htdocs/core/lib/files.lib.php | 120 +++++++++++++++++++++------------- 1 file changed, 76 insertions(+), 44 deletions(-) diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 60382cc4906..86c740c4f44 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -2083,65 +2083,97 @@ function dol_compress_file($inputfile, $outputfile, $mode = "gz", &$errorstring */ function dol_uncompress($inputfile, $outputdir) { - global $conf, $langs; + global $conf, $langs, $db; - 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); + include_once DOL_DOCUMENT_ROOT."/core/class/utils.class.php"; + $utils = new Utils($db); + $fileinfo = pathinfo($inputfile); + 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, '/^((?!\.\.).)*$/'); + // 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 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 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 ($fileinfo["extension"] == "gz" || $fileinfo["extension"] == "bz2") { + $extension = pathinfo($fileinfo["filename"], PATHINFO_EXTENSION); + if ($extension == "tar") { + $cmd = "tar -C ".$outputdir." -xvf ".$fileinfo["dirname"]."/".$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"; + } else { + return array('error'=>'ErrFileExtension'); + } + $cmd = $program." -dc ".$fileinfo["dirname"]."/".$fileinfo["basename"]; + $outputfilename = $outputdir."/".$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'); }