diff --git a/core/src/plugins/action.powerfs/class.PowerFSController.php b/core/src/plugins/action.powerfs/class.PowerFSController.php index 609a496577..42089ba51a 100644 --- a/core/src/plugins/action.powerfs/class.PowerFSController.php +++ b/core/src/plugins/action.powerfs/class.PowerFSController.php @@ -112,6 +112,9 @@ public function switchAction($action, $httpVars, $fileVars) case "compress" : case "precompress" : + $zipper = $this->getFilteredOption("ZIPPER"); + AJXP_Logger::debug(__CLASS__,__FUNCTION__,"Selected Zipper " . $zipper); + $archiveName = AJXP_Utils::sanitize(AJXP_Utils::decodeSecureMagic($httpVars["archive_name"]), AJXP_SANITIZE_FILENAME); if (!ConfService::currentContextIsCommandLine() && ConfService::backgroundActionsSupported()) { $opeId = substr(md5(time()),0,10); @@ -133,82 +136,510 @@ public function switchAction($action, $httpVars, $fileVars) session_write_close(); exit(); } - - $rootDir = fsAccessWrapper::getRealFSReference($urlBase) . $dir; - $percentFile = $rootDir."/.zip_operation_".$httpVars["ope_id"]; - $compressLocally = ($action == "compress" ? true : false); - // List all files - $todo = array(); - $args = array(); - $replaceSearch = array($rootDir, "\\"); - $replaceReplace = array("", "/"); - foreach ($selection->getFiles() as $selectionFile) { - $baseFile = $selectionFile; - $args[] = escapeshellarg(substr($selectionFile, strlen($dir)+($dir=="/"?0:1))); - $selectionFile = fsAccessWrapper::getRealFSReference($urlBase.$selectionFile); - $todo[] = ltrim(str_replace($replaceSearch, $replaceReplace, $selectionFile), "/"); - if (is_dir($selectionFile)) { - $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($selectionFile), RecursiveIteratorIterator::SELF_FIRST); - foreach ($objects as $name => $object) { - $todo[] = str_replace($replaceSearch, $replaceReplace, $name); - } - } - if(trim($baseFile, "/") == ""){ - // ROOT IS SELECTED, FIX IT - $args = array(escapeshellarg(basename($rootDir))); - $rootDir = dirname($rootDir); - break; - } - } - $cmdSeparator = ((PHP_OS == "WIN32" || PHP_OS == "WINNT" || PHP_OS == "Windows")? "&" : ";"); - //$archiveName = SystemTextEncoding::fromUTF8($httpVars["archive_name"]); - if (!$compressLocally) { - $archiveName = AJXP_Utils::getAjxpTmpDir()."/".$httpVars["ope_id"]."_".$archiveName; - } - chdir($rootDir); - $cmd = $this->getFilteredOption("ZIP_PATH")." -r ".escapeshellarg($archiveName)." ".implode(" ", $args); - $fsDriver = AJXP_PluginsService::getInstance()->getUniqueActivePluginForType("access"); - $c = $fsDriver->getConfigs(); - if ((!isSet($c["SHOW_HIDDEN_FILES"]) || $c["SHOW_HIDDEN_FILES"] == false) && stripos(PHP_OS, "win") === false) { - $cmd .= " -x .\*"; - } - $cmd .= " ".$cmdSeparator." echo ZIP_FINISHED"; - $proc = popen($cmd, "r"); - $toks = array(); - $handled = array(); - $finishedEchoed = false; - while (!feof($proc)) { - set_time_limit (20); - $results = fgets($proc, 256); - if (strlen($results) == 0) { - } else { - $tok = strtok($results, "\n"); - while ($tok !== false) { - $toks[] = $tok; - if ($tok == "ZIP_FINISHED") { - $finishedEchoed = true; - } else { - $test = preg_match('/(\w+): (.*) \(([^\(]+)\) \(([^\(]+)\)/', $tok, $matches); - if ($test !== false) { - $handled[] = $matches[2]; - } - } - $tok = strtok("\n"); - } - if($finishedEchoed) $percent = 100; - else $percent = min( round(count($handled) / count($todo) * 100), 100); - file_put_contents($percentFile, $percent); - } - // avoid a busy wait - if($percent < 100) usleep(1); - } - pclose($proc); - file_put_contents($percentFile, 100); + + if ($zipper == "zip") + $this->compress_zip($action, $httpVars, $fileVars, $dir, $selection, $urlBase); + else if ($zipper != "") + $this->compress_general($action, $httpVars, $fileVars, $dir, $selection, $urlBase, $zipper); + else + AJXP_Logger::logAction(__CLASS__,__FUNCTION__,"Not a valid ZIP tool found."); break; default: break; } + } - } + public function compress_general ($action, $httpVars, $fileVars, $dir, $selection, $urlBase, $zipper) + { + $rootDir = fsAccessWrapper::getRealFSReference($urlBase) . $dir; + $percentFile = $rootDir."/.zip_operation_".$httpVars["ope_id"]; + $compressLocally = ($action == "compress" ? true : false); + // List all files + $args = array(); + foreach ($selection->getFiles() as $selectionFile) { + $baseFile = $selectionFile; + $args[] = escapeshellarg(substr($selectionFile, strlen($dir)+($dir=="/"?0:1))); + $selectionFile = fsAccessWrapper::getRealFSReference($urlBase.$selectionFile); + + if(trim($baseFile, "/") == ""){ + // ROOT IS SELECTED, FIX IT + $args = array(escapeshellarg(basename($rootDir))); + $rootDir = dirname($rootDir); + break; + } + } + $files = ""; // Getting list of all files and writing them in file + foreach ($args as &$value) + { + $valuef = $rootDir."\\".str_replace("\"","",$value); + if (is_dir($valuef)) + $files = $files . $this->read_dir_recursive($valuef, $rootDir); + else if (substr($value, 0, 5) != ".axp.") + $files = $files . str_replace("\"","",$value) . "\r\n"; + } + $files = substr($files, 0, strlen($files) - 2); + + //Setting file names + $cmdSeparator = ((PHP_OS == "WIN32" || PHP_OS == "WINNT" || PHP_OS == "Windows")? "&" : ";"); + $archiveName = AJXP_Utils::sanitize(AJXP_Utils::decodeSecureMagic($httpVars["archive_name"]), AJXP_SANITIZE_FILENAME); + $filesname = ".axp.".$httpVars["archive_name"].".files.txt"; + $logfile = ".axp.".$httpVars["archive_name"].".processed.txt"; + $clioutputfile = $rootDir."\\.axp.".$httpVars["archive_name"].".cli_output.log"; + $clierrorfile = $rootDir."\\.axp.".$httpVars["archive_name"].".cli_error.log"; + if (!$compressLocally) { + $archiveName = AJXP_Utils::getAjxpTmpDir()."\\".$httpVars["ope_id"]."_".$archiveName; + $filesname = ".axp.".$httpVars["ope_id"]."_".$httpVars["archive_name"].".files.txt"; + $logfile = ".axp.".$httpVars["ope_id"]."_".$httpVars["archive_name"].".processed.txt"; + $clioutputfile = AJXP_Utils::getAjxpTmpDir()."\\".$httpVars["ope_id"]."_".$httpVars["archive_name"].".cli_output.log"; + $clierrorfile = AJXP_Utils::getAjxpTmpDir()."\\".$httpVars["ope_id"]."_".$httpVars["archive_name"].".cli_error.log"; + } + $zipspeedfile = AJXP_Utils::getAjxpTmpDir() . "\\" . "AJXP_zip_avgspeed.txt"; + AJXP_Logger::debug(__CLASS__,__FUNCTION__,"Files \r\n" . $archiveName . "\r\n" . $filesname . "\r\n" . $logfile . "\r\n" . $clioutputfile . "\r\n" . $clierrorfile . "\r\n" . $zipspeedfile); + + //Changing root dir + //AJXP_Logger::debug(__CLASS__,__FUNCTION__,getcwd()); + chdir($rootDir); + AJXP_Logger::debug(__CLASS__,__FUNCTION__,getcwd()); + + // Setting parameters + $zip_exe = $this->getFilteredOption("ZIPPER_MAN"); + if($this->getFilteredOption("ZIPPER_PATH") != "")//Setting ZIPPER_PATH + { + $zip_path = $this->getFilteredOption("ZIPPER_PATH"); + if (substr($zip_path, -1) != "\\" || substr($zip_path, -1) != "/") $zip_path = $zip_path . "\\"; + } + else + $zip_path = ""; + if($this->getFilteredOption("MAX_EXE_TIME") != 0)//Setting max execution time + set_time_limit (intval($this->getFilteredOption("MAX_EXE_TIME"))); + else + set_time_limit (1400); + if($this->getFilteredOption("MAX_ZIP_TIME") != 0)//Setting zip time + $max_zip_time = intval($this->getFilteredOption("MAX_ZIP_TIME")); + else + $max_zip_time = 1200; + if($this->getFilteredOption("MAX_ZIP_TIME_FILE") != 0)//Setting zip time file + $max_zip_time_file = intval($this->getFilteredOption("MAX_ZIP_TIME_FILE")); + else + $max_zip_time_file = 120; + if($this->getFilteredOption("ZIPPER_MONITOR_PAUSE") != 0)//Setting ZIPPER_MONITOR_PAUSE + $monitor_pause = intval($this->getFilteredOption("ZIPPER_MONITOR_PAUSE")) * 1000; + else + $monitor_pause = 500000; + if($this->getFilteredOption("ZIPPER_MONITOR_RECOG_PATTERN") != "")//Setting ZIPPER_MONITOR_RECOG_AFFECTS + $recogpattern = $this->getFilteredOption("ZIPPER_MONITOR_RECOG_PATTERN"); + else + $recogpattern = "%file%"; + if($this->getFilteredOption("ZIPPER_MONITOR_RECOG_AFFECTS") == "end")//Setting ZIPPER_MONITOR_RECOG_AFFECTS + $fproc_regoc_at_zipstart = false; + else + $fproc_regoc_at_zipstart = true; + if($this->getFilteredOption("ZIPPER_MONITOR_SUCCESS_STATEMENT") != "")//Setting ZIPPER_MONITOR_RECOG_AFFECTS + $zipsuccess_statement = $this->getFilteredOption("ZIPPER_MONITOR_SUCCESS_STATEMENT"); + else + $zipsuccess_statement = "#none#"; + + // Preparing and executing CLI + file_put_contents($filesname, $files); + if (file_exists($clioutputfile)) unlink($clioutputfile); + $descriptorspec = array( + 0 => array("pipe", "r"), // stdin is a pipe that the child will read from + 1 => array("file", $clioutputfile, "a"), // stdout is a pipe that the child will write to + 2 => array("file", $clierrorfile, "a") // stderr is a file to write to + ); + $oopt = array('bypass_shell' => true); + + switch ($zipper){ + case "zip2" : + //$cmd = $zip_path . "zip -r ".escapeshellarg($archiveName)." ".implode(" ", $args); + $cmd = $zip_path . "zip -r ".escapeshellarg($archiveName)." ". "\"" . str_replace("\r\n", "\" \"", $files) . "\""; + if (PHP_OS != "WIN32" && PHP_OS != "WINNT" && PHP_OS != "Windows") { + $fsDriver = AJXP_PluginsService::getInstance()->getUniqueActivePluginForType("access"); + $c = $fsDriver->getConfigs(); + if (!isSet($c["SHOW_HIDDEN_FILES"]) || $c["SHOW_HIDDEN_FILES"] == false) { + $cmd .= " -x .\*"; + } + } + break; + case "winrar" : + $cmd = $zip_path . "winrar a -afzip -ibck -logf=" . escapeshellarg($logfile) . " " . escapeshellarg($archiveName) . " @" . escapeshellarg($filesname); + break; + case "7zip" : + $cmd = $zip_path . "7z a -tzip ".escapeshellarg($archiveName)." @" . escapeshellarg($filesname); + break; + case "other" : + $zip_exe = str_replace("%archive%", escapeshellarg($archiveName), $zip_exe); + $zip_exe = str_replace("%files%", "\"" . implode("\" \"", $args) . "\"" , $zip_exe); + $zip_exe = str_replace("%listfile%", escapeshellarg($filesname), $zip_exe); + $zip_exe = str_replace("%outputfile%", escapeshellarg($logfile), $zip_exe); + $cmd = $zip_path . $zip_exe; + break; + default: + break; + } + AJXP_Logger::debug(__CLASS__,__FUNCTION__,"Executing zip command"); + AJXP_Logger::debug(__CLASS__,__FUNCTION__,$cmd); + $proc = proc_open($cmd, $descriptorspec, $pipes, $rootDir, null, $oopt); + + // Preparing progress check and getting information on files while ZIP is running to save time + $toks = array(); + $handled = array(); + $finishedEchoed = false; + + $files_name = array(); + $files_size = array(); + $files_fnd = array(); + $files_totalsize = 0; + + $files_name = explode("\r\n",$files); + AJXP_Logger::debug(__CLASS__,__FUNCTION__,"Counting files " . count($files_name)); + foreach ($files_name as &$fle) + { + if (file_exists($fle)) + { + $files_size[] = filesize($fle); + $files_totalsize = $files_totalsize + $files_size[count($files_size) - 1]; + } + else + $files_size[] = 0; + $files_fnd[] = false; + } + AJXP_Logger::debug(__CLASS__,__FUNCTION__,"Totalsize MB " . $files_totalsize / 1000000); + $linesarr = array(); + $linescnt = count($linesarr); + $fprocessed = 0; + + $maxwaiting = 10 * 10; //Waiting for zipper to start + for ($l = 0; $l <= $maxwaiting; $l++) + { + $stat = proc_get_status($proc); + if (!$stat['running']) + usleep(100000); + else + $l = $maxwaiting + 1; + } + $filetime = 0; + $kill_proc = false; + $zipstart = time(); + $zipstartfile = time(); + $percent = 0; + $zipcomplete = false; + $zipOK = -1; + $zipstat = 0; + $fprocessed_delta = 0; + $fprocessed_cnt = 0; + $cliout = ""; + + //select & configure monitoring process + switch ($zipper){ + case "winrar" : + if ($this->getFilteredOption("ZIPPER_MONITOR") == "fileoutput") + $monproc = "fileoutput"; + else if ($this->getFilteredOption("ZIPPER_MONITOR") == "avgspeed") + $monproc = "avgspeed"; + else { + $monproc = "fileoutput"; + AJXP_Logger::logAction(__CLASS__,__FUNCTION__,"Not a valid monitoring process was set, setting to fileoutput"); + } + $recogpattern = "/%file%/"; + $zipOK = 0; + $fproc_regoc_at_zipstart = true; + break; + case "7zip" : + $monproc = "avgspeed"; + $zipsuccess_statement = "Everything is Ok"; + $zipOK = 0; + break; + case "zip2" : + if ($this->getFilteredOption("ZIPPER_MONITOR") == "clioutput") + $monproc = "clioutput"; + else if ($this->getFilteredOption("ZIPPER_MONITOR") == "avgspeed") + $monproc = "avgspeed"; + else { + $monproc = "clioutput"; + AJXP_Logger::logAction(__CLASS__,__FUNCTION__,"Not a valid monitoring process was set, setting to clioutput"); + } + $recogpattern = '/(\w+): (%file%) \(([^\(]+)\) \(([^\(]+)\)/'; + $zipOK = 0; + break; + case "other" : + $monproc = $this->getFilteredOption("ZIPPER_MONITOR"); + if ($zipsuccess_statement != "#none#") + $zipOK = 0; + break; + default: + $monproc = "avgspeed"; + AJXP_Logger::logAction(__CLASS__,__FUNCTION__,"Applying default zip monitor"); + break; + } + AJXP_Logger::debug(__CLASS__,__FUNCTION__,"Selected monitor " . $monproc); + + // Monitoring progress + if (is_resource($proc)) + { + switch ($monproc){ + case "clioutput" : + case "fileoutput" : + if ($monproc == "clioutput") + $moninputfile = $clioutputfile; + else if ($monproc == "fileoutput") + $moninputfile = $logfile; + else + $moninputfile = ""; + while (!$zipcomplete && !$kill_proc) + { + if (file_exists($moninputfile)) + { + $linesarr = explode("\r\n",file_get_contents($moninputfile)); + if ($linescnt != count($linesarr)) // Has a new line been added + { + for ($i = 0; $i <= count($files_name) - 1 ; $i++) // Check all files to be in the zip + { + //AJXP_Logger::debug(__CLASS__,__FUNCTION__,"Current file " . $files_name[$i]); + if ($files_fnd[$i] == false) + { + $patt = str_replace("%file%", str_replace("\\", "\\\\", $files_name[$i]), $recogpattern); + //AJXP_Logger::debug(__CLASS__,__FUNCTION__,"Pattern " . $patt); + foreach ($linesarr as &$str2) // If file matches a should file, mark it as found, add the size, calc percent and restart max zip file time + { + $obj = str_replace("/", "\\", $str2); + $test = preg_match($patt, $obj); + //AJXP_Logger::debug(__CLASS__,__FUNCTION__," Comp " . $obj); + //AJXP_Logger::debug(__CLASS__,__FUNCTION__," Resu " . $test); + if($fproc_regoc_at_zipstart) $fprocessed_delta = $files_size[$i] / 2; + + if ($test == 1) + { + $fprocessed = $fprocessed + $files_size[$i]; + $percent = round(($fprocessed - $fprocessed_delta) / $files_totalsize * 100); + file_put_contents($percentFile, $percent); + $zipstartfile = time(); + $files_fnd[$i] = true; + $fprocessed_cnt++; + //AJXP_Logger::debug(__CLASS__,__FUNCTION__,"File found " . $files_name[$i]); + } + } + } + } + $linescnt = count($linesarr); + } + + if ($fprocessed_cnt >= count($files_name)) + { + $zipcomplete = true; + AJXP_Logger::debug(__CLASS__,__FUNCTION__,"All found files compressed! Setting 100%"); + } + } + $stat = proc_get_status($proc); // Checking wether the process is running or has completed + if (!$stat['running']) { if ($zipstat == 0) + { $zipstat = 1; AJXP_Logger::debug(__CLASS__,__FUNCTION__,"Process end detected");} + else + { $zipcomplete = true; AJXP_Logger::debug(__CLASS__,__FUNCTION__,"Setting ZIP Complete true");}} + if (file_exists($clioutputfile)) $cliout = file_get_contents($clioutputfile); // Checking success statement in command line output + if (strpos($cliout, $zipsuccess_statement) > 1) {$zipcomplete = true; $zipOK = 1;} + if (time() - $zipstart > $max_zip_time) $kill_proc = true; // Maximum exe time reached + if (time() - $zipstartfile > $max_zip_time_file) // Max execution time per file + { + AJXP_Logger::logAction(__CLASS__,__FUNCTION__,"Abort due logfile has not changed in longer time."); + $kill_proc = true; + } + + if(!$zipcomplete) usleep($monitor_pause); + } + //AJXP_Logger::debug(__CLASS__,__FUNCTION__,$fprocessed_cnt); + //AJXP_Logger::debug(__CLASS__,__FUNCTION__,count($files_name)); + if ($fprocessed_cnt == count($files_name)) + $zipOK = 1; + break; + case "avgspeed" : + $zipspeed = 0; + $zipwaiting = false; + $zipspeeda = array(1, 25); //seconds per MB + if (file_exists($zipspeedfile)) $zipspeeda = explode("#",file_get_contents($zipspeedfile)); + $zipspeed = ( ((int)$zipspeeda[1]) / ((int)$zipspeeda[0]) ); + AJXP_Logger::debug(__CLASS__,__FUNCTION__,"AvgSpeed MB/s " . $zipspeed); + if (((int)$zipspeeda[0]) > 10000) + { + AJXP_Logger::logAction(__CLASS__,__FUNCTION__,"Reducing speed average values to avoid stack overflow"); + $zipspeeda[0] = ((int)( (int)$zipspeeda[0] / 100 )); + $zipspeeda[1] = ((int)( (int)$zipspeeda[1] / 100 )); + } + + while (!$zipcomplete && !$kill_proc) + { + $percent = round((time() - $zipstart) * $zipspeed / ($files_totalsize / 1000000) * 100); + if ($percent <= 98) + file_put_contents($percentFile, $percent); + else if (!$zipwaiting) + { + file_put_contents($percentFile, 98); + AJXP_Logger::debug(__CLASS__,__FUNCTION__,"Waiting for success statement ... 98% is reached"); + $zipwaiting = true; + } + + $stat = proc_get_status($proc); // Checking wether the process is running or has completed + if (!$stat['running']) { if ($zipstat == 0) $zipstat = 1; else $zipcomplete = true;} + if (file_exists($moninputfile)) $cliout = file_get_contents($moninputfile); // Checking success statement in command line output + if (strpos($cliout, $zipsuccess_statement) > 1) {$zipcomplete = true; $zipOK = 1;} + if (time() - $zipstart > $max_zip_time) $kill_proc = true; // Maximum exe time reached + + if(!$zipcomplete) usleep($monitor_pause); + } + $zipend = time(); + file_put_contents($zipspeedfile, ($zipspeeda[0] + $zipend - $zipstart) . "#" . ((int)( ($files_totalsize / 1000000) + $zipspeeda[1]))); + if (file_exists($moninputfile)) + if (strpos(file_get_contents($moninputfile), $zipsuccess_statement) > 1) + $zipOK = 1; + break; + default: + AJXP_Logger::logAction(__CLASS__,__FUNCTION__,"Cannot find appropiate monitoring process"); + break; + + } + } + else + { + AJXP_Logger::logAction(__CLASS__,__FUNCTION__,"Zip Process could not be started."); + file_put_contents($percentFile, 100); + } + + if ($kill_proc) // Terminate in case of errors + { + AJXP_Logger::logAction(__CLASS__,__FUNCTION__,"Zip process should be terminated due to an error. Terminating process ..."); + proc_terminate($proc); + } + $maxwaiting = 30 * 10; // Waiting x seconds to give process time to quit + for ($k = 0; $k <= $maxwaiting; $k++) + { + $stat = proc_get_status($proc); + if ($stat['running'] && k == $maxwaiting) // Termintate in case of still running + { + AJXP_Logger::logAction(__CLASS__,__FUNCTION__,"Zip process still running after ".$maxwaiting."s. Terminating process ..."); + proc_terminate($proc); + } + if ($stat['running']) + usleep(100000); + else + $k = $maxwaiting + 1; + } + file_put_contents($percentFile, 100); + AJXP_Logger::debug(__CLASS__,__FUNCTION__,"Closing Proc"); + proc_close ($proc); + + if (file_exists($filesname)) unlink($filesname); + if (file_exists($logfile)) unlink($logfile); + if (file_exists($clioutputfile)) unlink($clioutputfile); + if (file_exists($clierrorfile)) // Logging errors of cli + { + $fcontent = file_get_contents($clierrorfile); + unlink($clierrorfile); + if (strlen($fcontent) > 2) AJXP_Logger::logAction(__CLASS__,__FUNCTION__,"Command Line Error " . $fcontent); + } + if ($zipOK == 0) // Checking success statement + AJXP_Logger::logAction(__CLASS__,__FUNCTION__,"No expected success statement found. ZIP has probable errors."); + + file_put_contents($percentFile, 100); // Ending monitoring process by writing 100% in percentfile + AJXP_Logger::debug(__CLASS__,__FUNCTION__,"Final end compressing function"); + } + + public function compress_zip($action, $httpVars, $fileVars, $dir, $selection, $urlBase) + { + $rootDir = fsAccessWrapper::getRealFSReference($urlBase) . $dir; + $percentFile = $rootDir."/.zip_operation_".$httpVars["ope_id"]; + $compressLocally = ($action == "compress" ? true : false); + // List all files + $todo = array(); + $args = array(); + $replaceSearch = array($rootDir, "\\"); + $replaceReplace = array("", "/"); + foreach ($selection->getFiles() as $selectionFile) { + $baseFile = $selectionFile; + $args[] = escapeshellarg(substr($selectionFile, strlen($dir)+($dir=="/"?0:1))); + $selectionFile = fsAccessWrapper::getRealFSReference($urlBase.$selectionFile); + $todo[] = ltrim(str_replace($replaceSearch, $replaceReplace, $selectionFile), "/"); + if (is_dir($selectionFile)) { + $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($selectionFile), RecursiveIteratorIterator::SELF_FIRST); + foreach ($objects as $name => $object) { + $todo[] = str_replace($replaceSearch, $replaceReplace, $name); + } + } + if(trim($baseFile, "/") == ""){ + // ROOT IS SELECTED, FIX IT + $args = array(escapeshellarg(basename($rootDir))); + $rootDir = dirname($rootDir); + break; + } + } + $cmdSeparator = ((PHP_OS == "WIN32" || PHP_OS == "WINNT" || PHP_OS == "Windows")? "&" : ";"); + //$archiveName = SystemTextEncoding::fromUTF8($httpVars["archive_name"]); + if (!$compressLocally) { + $archiveName = AJXP_Utils::getAjxpTmpDir()."/".$httpVars["ope_id"]."_".$archiveName; + } + chdir($rootDir); + $cmd = $this->getFilteredOption("ZIPPER_PATH")."zip -r ".escapeshellarg($archiveName)." ".implode(" ", $args); + $fsDriver = AJXP_PluginsService::getInstance()->getUniqueActivePluginForType("access"); + $c = $fsDriver->getConfigs(); + if ((!isSet($c["SHOW_HIDDEN_FILES"]) || $c["SHOW_HIDDEN_FILES"] == false) && stripos(PHP_OS, "win") === false) { + $cmd .= " -x .\*"; + } + $cmd .= " ".$cmdSeparator." echo ZIP_FINISHED"; + $proc = popen($cmd, "r"); + $toks = array(); + $handled = array(); + $finishedEchoed = false; + if($this->getFilteredOption("MAX_ZIP_TIME") != 0)//Setting zip time + $max_zip_time = (int)$this->getFilteredOption("MAX_ZIP_TIME"); + else + $max_zip_time = 120; + while (!feof($proc)) { + set_time_limit ($max_zip_time); + $results = fgets($proc, 256); + if (strlen($results) == 0) { + } else { + $tok = strtok($results, "\n"); + while ($tok !== false) { + $toks[] = $tok; + if ($tok == "ZIP_FINISHED") { + $finishedEchoed = true; + } else { + $test = preg_match('/(\w+): (.*) \(([^\(]+)\) \(([^\(]+)\)/', $tok, $matches); + if ($test !== false) { + $handled[] = $matches[2]; + } + } + $tok = strtok("\n"); + } + if($finishedEchoed) $percent = 100; + else $percent = min( round(count($handled) / count($todo) * 100), 100); + file_put_contents($percentFile, $percent); + } + // avoid a busy wait + if($percent < 100) usleep(1); + } + pclose($proc); + file_put_contents($percentFile, 100); + } + + public function read_dir_recursive($dir, $rootdir) + { + $handle = opendir($dir); + $filesr = ""; + + while ($arg = readdir($handle)) + { + $val = $dir."\\".$arg; + if ($arg != "." && $arg != "..") + { + if (is_dir($val)) + $filesr = $filesr . $this->read_dir_recursive($val, $rootdir); + else if (strpos($val, ".axp.") === false) + $filesr = $filesr . substr($val, strlen($rootdir) + 1) . "\r\n"; + } + } + + closedir($handle); + + return $filesr; + } } diff --git a/core/src/plugins/action.powerfs/manifest.xml b/core/src/plugins/action.powerfs/manifest.xml index dc2127e192..76d48b60f6 100644 --- a/core/src/plugins/action.powerfs/manifest.xml +++ b/core/src/plugins/action.powerfs/manifest.xml @@ -8,8 +8,27 @@ - + + + + + + + + + + + diff --git a/core/src/plugins/action.powerfs/plugin_doc.html b/core/src/plugins/action.powerfs/plugin_doc.html index ec82e6af8a..d2e5aecd5c 100644 --- a/core/src/plugins/action.powerfs/plugin_doc.html +++ b/core/src/plugins/action.powerfs/plugin_doc.html @@ -1 +1,47 @@ -

This plugin will delegate various time/memory-consuming actions to the underlying filesystem.

For the moment only the ZIP delegation is implemented. It requires the presence of the "zip" utilitary in the system path. Tested on both Linux and windows. If active, the "compress" action, as well as the "download folder" action, will trigger a background action monitoring the current percent of the ZIP operation. This allows the compression of huge amount of data. \ No newline at end of file +

This plugin will delegate various time/memory-consuming actions to the underlying filesystem.

For the moment only the ZIP delegation is implemented. It requires the presence of the "zip" utilitary. Tested on both Linux and windows. If active, the "compress" action, as well as the "download folder" action, will trigger a background action monitoring the current percent of the ZIP operation. This allows the compression of huge amount of data.

The following paragraphs describe the setting possibilities in detail.

+ +

Compression tool

+ +

Tool

+

The tool of the compression can be selected. Default is the zip tool. If other is selected, a not manual tool can be configured in the next field.

+ +

Other execution file

+

Execution file of other tool with options: %archive% will be replace by archive name, %files% by list of files to compress, %listfile% by the name of the file containing files to compress and %outputfile% by the output file of the zipper.

+ +

Path

+

Path to the tool, if not in PATH variable.

+ +

Max file zip time (seconds)

+

Maximum time, which is given to process one file to zip. Only supported by CLI output and File as output monitor.

+ +

Max zip time (seconds)

+

Maximum time, which is given until the zip process will be stopped.

+ + +

Progress monitoring

+ +

Tool

+

Select the monitoring process, not available for zip (1st edition), CLI output available for zip (2nd edition), File as output available for WinRAR and Average speed always works.

+

If a manual zip tool is selected, the tool has to be check by the user, which monitor process is appropiate. If a standard tool is selected it will be checked whether the selected tool is appropiate and if not the best monitor will be used.

+ +

Pause between checks (milliseconds)

+

Pause between each progress checking activity of the monitor. Reduces the load of the php process to the CPU.

+ +

Recognition pattern

+

Pattern to be fullfilled, when file is successfully processed by the zip tool. %file% will be replaced by the filename to be searched. When the pattern is fullfilled the size of the file will be used to calculate the progress in relation to the total size of the file, which should be zipped.

+

This setting will be overwritten by the appropiate value for the standard tool and monitor type. It should by used with a manual tool and has to be a regular expression.

+ +

Recognition is when

+

When does the recognition pattern return true, at the beginning or at the end of the zipping process of the current file.

+

This setting will be overwritten by the appropiate value for the standard tool and monitor type. It should by used with a manual tool.

+ +

Success statement

+

String which is in the output, when Zip process was successful, like 'Everything is Ok' for 7-zip.

+

This setting will be overwritten by the appropiate value for the standard tool and monitor type. It should by used with a manual tool.

+ + +

General options

+ +

Max CLI exe time (seconds)

+

Maximum time, after which the cmd line process is stopped. Ensures that not uncompleted zip processes are running on the server forever. If a process is ended this way, the result will probably be errors.

+