|
| 1 | +<?php |
| 2 | +/* |
| 3 | + * Copyright 2007-2013 Charles du Jeu - Abstrium SAS <team (at) pyd.io> |
| 4 | + * This file is part of Pydio. |
| 5 | + * |
| 6 | + * Pydio is free software: you can redistribute it and/or modify |
| 7 | + * it under the terms of the GNU Affero General Public License as published by |
| 8 | + * the Free Software Foundation, either version 3 of the License, or |
| 9 | + * (at your option) any later version. |
| 10 | + * |
| 11 | + * Pydio is distributed in the hope that it will be useful, |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | + * GNU Affero General Public License for more details. |
| 15 | + * |
| 16 | + * You should have received a copy of the GNU Affero General Public License |
| 17 | + * along with Pydio. If not, see <http://www.gnu.org/licenses/>. |
| 18 | + * |
| 19 | + * The latest code can be found at <http://pyd.io/>. |
| 20 | + */ |
| 21 | + |
| 22 | +defined('AJXP_EXEC') or die('Access not allowed'); |
| 23 | + |
| 24 | +/** |
| 25 | + * Plugin to compress to TAR or TAR.GZ or TAR.BZ2... He can also extract your archives |
| 26 | + * @package AjaXplorer_Plugins |
| 27 | + * @subpackage Action |
| 28 | + */ |
| 29 | +class PluginCompression extends AJXP_Plugin |
| 30 | +{ |
| 31 | + /** |
| 32 | + * @param String $action |
| 33 | + * @param Array $httpVars |
| 34 | + * @param Array $fileVars |
| 35 | + * @throws Exception |
| 36 | + */ |
| 37 | + public function receiveAction($action, $httpVars, $fileVars) |
| 38 | + { |
| 39 | + //TODO : DESTROY THE PROGRESS FILE AT THE END OF THE PROCESS + POSSIBILITY TO CANCEL COMPRESS TO HAVE JUST THE TAR FILE |
| 40 | + //VAR CREATION OUTSIDE OF ALL CONDITIONS, THEY ARE MUST HAVE VAR !! |
| 41 | + $messages = ConfService::getMessages(); |
| 42 | + $repository = ConfService::getRepository(); |
| 43 | + $userSelection = new UserSelection($repository, $httpVars); |
| 44 | + $nodes = $userSelection->buildNodes(); |
| 45 | + $currentDirPath = AJXP_Utils::safeDirname($userSelection->getUniqueNode()->getPath()); |
| 46 | + $currentDirPath = rtrim($currentDirPath, "/") . "/"; |
| 47 | + $currentDirUrl = $userSelection->currentBaseUrl().$currentDirPath; |
| 48 | + if (empty($httpVars["compression_id"])) { |
| 49 | + $compressionId = sha1(rand()); |
| 50 | + $httpVars["compression_id"] = $compressionId; |
| 51 | + } else { |
| 52 | + $compressionId = $httpVars["compression_id"]; |
| 53 | + } |
| 54 | + $progressCompressionFileName = $this->getPluginCacheDir(false, true) . DIRECTORY_SEPARATOR . "progressCompressionID-" . $compressionId . ".txt"; |
| 55 | + if (empty($httpVars["extraction_id"])) { |
| 56 | + $extractId = sha1(rand()); |
| 57 | + $httpVars["extraction_id"] = $extractId; |
| 58 | + } else { |
| 59 | + $extractId = $httpVars["extraction_id"]; |
| 60 | + } |
| 61 | + $progressExtractFileName = $this->getPluginCacheDir(false, true) . DIRECTORY_SEPARATOR . "progressExtractID-" . $extractId . ".txt"; |
| 62 | + if ($action == "compression") { |
| 63 | + $archiveName = AJXP_Utils::sanitize(AJXP_Utils::decodeSecureMagic($httpVars["archiveName"]), AJXP_SANITIZE_FILENAME); |
| 64 | + $archiveFormat = $httpVars["type_archive"]; |
| 65 | + $tabTypeArchive = [".tar", ".tar.gz", ".tar.bz2"]; |
| 66 | + $acceptedExtension = false; |
| 67 | + foreach ($tabTypeArchive as $extensionArchive) { |
| 68 | + if ($extensionArchive == $archiveFormat) { |
| 69 | + $acceptedExtension = true; |
| 70 | + break; |
| 71 | + } |
| 72 | + } |
| 73 | + if ($acceptedExtension == false) { |
| 74 | + throw new AJXP_Exception($messages["compression.16"]); |
| 75 | + } |
| 76 | + $typeArchive = $httpVars["type_archive"]; |
| 77 | + //if we can run in background we do it |
| 78 | + if (ConfService::backgroundActionsSupported() && !ConfService::currentContextIsCommandLine()) { |
| 79 | + $archivePath = $currentDirPath.$archiveName; |
| 80 | + file_put_contents($progressCompressionFileName, $messages["compression.5"]); |
| 81 | + AJXP_Controller::applyActionInBackground($repository->getId(), "compression", $httpVars); |
| 82 | + AJXP_XMLWriter::header(); |
| 83 | + AJXP_XMLWriter::triggerBgAction("check_compression_status", array( |
| 84 | + "repository_id" => $repository->getId(), |
| 85 | + "compression_id" => $compressionId, |
| 86 | + "archive_path" => SystemTextEncoding::toUTF8($archivePath) |
| 87 | + ), $messages["compression.5"], true, 4); |
| 88 | + AJXP_XMLWriter::close(); |
| 89 | + return null; |
| 90 | + } else { |
| 91 | + $maxAuthorizedSize = 4294967296; |
| 92 | + $currentDirUrlLength = strlen($currentDirUrl); |
| 93 | + $tabFolders = []; |
| 94 | + $tabAllRecursiveFiles = []; |
| 95 | + $tabFilesNames = []; |
| 96 | + foreach ($nodes as $node) { |
| 97 | + $nodeUrl = $node->getUrl(); |
| 98 | + if (is_file($nodeUrl) && filesize($nodeUrl) < $maxAuthorizedSize) { |
| 99 | + array_push($tabAllRecursiveFiles, $nodeUrl); |
| 100 | + array_push($tabFilesNames, substr($nodeUrl, $currentDirUrlLength)); |
| 101 | + } |
| 102 | + if (is_dir($nodeUrl)) { |
| 103 | + array_push($tabFolders, $nodeUrl); |
| 104 | + } |
| 105 | + } |
| 106 | + //DO A FOREACH OR IT'S GONNA HAVE SOME SAMES FILES NAMES |
| 107 | + foreach ($tabFolders as $value) { |
| 108 | + $dossiers = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($value)); |
| 109 | + foreach ($dossiers as $file) { |
| 110 | + if ($file->isDir()) { |
| 111 | + continue; |
| 112 | + } |
| 113 | + array_push($tabAllRecursiveFiles, $file->getPathname()); |
| 114 | + array_push($tabFilesNames, substr($file->getPathname(), $currentDirUrlLength)); |
| 115 | + } |
| 116 | + } |
| 117 | + try { |
| 118 | + $tmpArchiveName = tempnam(AJXP_Utils::getAjxpTmpDir(), "tar-compression") . ".tar"; |
| 119 | + $archive = new PharData($tmpArchiveName); |
| 120 | + } catch (Exception $e) { |
| 121 | + throw $e; |
| 122 | + } |
| 123 | + $counterCompression = 0; |
| 124 | + //THE TWO ARRAY ARE MERGED FOR THE FOREACH LOOP |
| 125 | + $tabAllFiles = array_combine($tabAllRecursiveFiles, $tabFilesNames); |
| 126 | + foreach ($tabAllFiles as $fullPath => $fileName) { |
| 127 | + try { |
| 128 | + $archive->addFile(AJXP_MetaStreamWrapper::getRealFSReference($fullPath), $fileName); |
| 129 | + $counterCompression++; |
| 130 | + file_put_contents($progressCompressionFileName, sprintf($messages["compression.6"], ($counterCompression / count($tabAllFiles)) * 100 . " %")); |
| 131 | + } catch (Exception $e) { |
| 132 | + unlink($tmpArchiveName); |
| 133 | + throw $e; |
| 134 | + } |
| 135 | + } |
| 136 | + $finalArchive = $tmpArchiveName; |
| 137 | + if ($typeArchive != ".tar") { |
| 138 | + $archiveTypeCompress = substr(strrchr($typeArchive, "."), 1); |
| 139 | + file_put_contents($progressCompressionFileName, sprintf($messages["compression.7"], strtoupper($archiveTypeCompress))); |
| 140 | + if ($archiveTypeCompress == "gz") { |
| 141 | + $archive->compress(Phar::GZ); |
| 142 | + } elseif ($archiveTypeCompress == "bz2") { |
| 143 | + $archive->compress(Phar::BZ2); |
| 144 | + } |
| 145 | + $finalArchive = $tmpArchiveName . "." . $archiveTypeCompress; |
| 146 | + } |
| 147 | + $destArchive = AJXP_MetaStreamWrapper::getRealFSReference($currentDirUrl . $archiveName); |
| 148 | + rename($finalArchive, $destArchive); |
| 149 | + AJXP_Controller::applyHook("node.before_create", array($destArchive, filesize($destArchive))); |
| 150 | + if (file_exists($tmpArchiveName)) { |
| 151 | + unlink($tmpArchiveName); |
| 152 | + unlink(substr($tmpArchiveName, 0, -4)); |
| 153 | + } |
| 154 | + $newNode = new AJXP_Node($currentDirUrl . $archiveName); |
| 155 | + AJXP_Controller::applyHook("node.change", array(null, $newNode, false)); |
| 156 | + file_put_contents($progressCompressionFileName, "SUCCESS"); |
| 157 | + } |
| 158 | + } |
| 159 | + elseif ($action == "check_compression_status") { |
| 160 | + $archivePath = AJXP_Utils::decodeSecureMagic($httpVars["archive_path"]); |
| 161 | + $progressCompression = file_get_contents($progressCompressionFileName); |
| 162 | + if ($progressCompression != "SUCCESS") { |
| 163 | + AJXP_XMLWriter::header(); |
| 164 | + AJXP_XMLWriter::triggerBgAction("check_compression_status", array( |
| 165 | + "repository_id" => $repository->getId(), |
| 166 | + "compression_id" => $compressionId, |
| 167 | + "archive_path" => SystemTextEncoding::toUTF8($archivePath) |
| 168 | + ), $progressCompression, true, 3); |
| 169 | + AJXP_XMLWriter::close(); |
| 170 | + } else { |
| 171 | + $newNode = new AJXP_Node($userSelection->currentBaseUrl() . $archivePath); |
| 172 | + $nodesDiffs = array("ADD" => array($newNode), "REMOVE" => array(), "UPDATE" => array()); |
| 173 | + AJXP_Controller::applyHook("node.change", array(null, $newNode, false)); |
| 174 | + AJXP_XMLWriter::header(); |
| 175 | + AJXP_XMLWriter::sendMessage($messages["compression.8"], null); |
| 176 | + AJXP_XMLWriter::writeNodesDiff($nodesDiffs, false); |
| 177 | + AJXP_XMLWriter::close(); |
| 178 | + unlink($progressCompressionFileName); |
| 179 | + } |
| 180 | + } |
| 181 | + elseif ($action == "extraction") { |
| 182 | + $fileArchive = AJXP_Utils::sanitize(AJXP_Utils::decodeSecureMagic($httpVars["file"]), AJXP_SANITIZE_DIRNAME); |
| 183 | + $fileArchive = substr(strrchr($fileArchive, DIRECTORY_SEPARATOR), 1); |
| 184 | + $authorizedExtension = ["tar" => 4, "gz" => 7, "bz2" => 8]; |
| 185 | + $acceptedArchive = false; |
| 186 | + $extensionLength = 0; |
| 187 | + $counterExtract = 0; |
| 188 | + $currentAllPydioPath = $currentDirUrl . $fileArchive; |
| 189 | + $pharCurrentAllPydioPath = "phar://" . AJXP_MetaStreamWrapper::getRealFSReference($currentAllPydioPath); |
| 190 | + $pathInfoCurrentAllPydioPath = pathinfo($currentAllPydioPath)["extension"]; |
| 191 | + //WE TAKE ONLY TAR, TAR.GZ AND TAR.BZ2 ARCHIVES |
| 192 | + foreach ($authorizedExtension as $extension => $strlenExtension) { |
| 193 | + if ($pathInfoCurrentAllPydioPath == $extension) { |
| 194 | + $acceptedArchive = true; |
| 195 | + $extensionLength = $strlenExtension; |
| 196 | + break; |
| 197 | + } |
| 198 | + } |
| 199 | + if ($acceptedArchive == false) { |
| 200 | + throw new AJXP_Exception($messages["compression.15"]); |
| 201 | + } |
| 202 | + $onlyFileName = substr($fileArchive, 0, -$extensionLength); |
| 203 | + $lastPosOnlyFileName = strrpos($onlyFileName, "-"); |
| 204 | + $tmpOnlyFileName = substr($onlyFileName, 0, $lastPosOnlyFileName); |
| 205 | + $counterDuplicate = substr($onlyFileName, $lastPosOnlyFileName + 1); |
| 206 | + if ($lastPosOnlyFileName == false) { |
| 207 | + $tmpOnlyFileName = $onlyFileName; |
| 208 | + $counterDuplicate = 1; |
| 209 | + } |
| 210 | + while (file_exists($currentDirUrl . $onlyFileName)) { |
| 211 | + $onlyFileName = $tmpOnlyFileName . "-" . $counterDuplicate; |
| 212 | + $counterDuplicate++; |
| 213 | + } |
| 214 | + if (ConfService::backgroundActionsSupported() && !ConfService::currentContextIsCommandLine()) { |
| 215 | + file_put_contents($progressExtractFileName, $messages["compression.12"]); |
| 216 | + AJXP_Controller::applyActionInBackground($repository->getId(), "extraction", $httpVars); |
| 217 | + AJXP_XMLWriter::header(); |
| 218 | + AJXP_XMLWriter::triggerBgAction("check_extraction_status", array( |
| 219 | + "repository_id" => $repository->getId(), |
| 220 | + "extraction_id" => $extractId, |
| 221 | + "currentDirUrl" => $currentDirUrl, |
| 222 | + "onlyFileName" => $onlyFileName |
| 223 | + ), $messages["compression.12"], true, 3); |
| 224 | + AJXP_XMLWriter::close(); |
| 225 | + return null; |
| 226 | + } |
| 227 | + mkdir($currentDirUrl . $onlyFileName, 0777, true); |
| 228 | + chmod(AJXP_MetaStreamWrapper::getRealFSReference($currentDirUrl . $onlyFileName), 0777); |
| 229 | + try { |
| 230 | + $archive = new PharData(AJXP_MetaStreamWrapper::getRealFSReference($currentAllPydioPath)); |
| 231 | + $fichiersArchive = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($pharCurrentAllPydioPath)); |
| 232 | + foreach ($fichiersArchive as $file) { |
| 233 | + $fileGetPathName = $file->getPathname(); |
| 234 | + if($file->isDir()) { |
| 235 | + continue; |
| 236 | + } |
| 237 | + $fileNameInArchive = substr(strstr($fileGetPathName, $fileArchive), strlen($fileArchive) + 1); |
| 238 | + var_dump($currentDirUrl . $onlyFileName . DIRECTORY_SEPARATOR . $fileNameInArchive); |
| 239 | + $archive->extractTo(AJXP_MetaStreamWrapper::getRealFSReference($currentDirUrl . $onlyFileName), $fileNameInArchive, false); |
| 240 | + $newNode = new AJXP_Node($currentDirUrl . $onlyFileName . DIRECTORY_SEPARATOR . $fileNameInArchive); |
| 241 | + AJXP_Controller::applyHook("node.change", array(null, $newNode, false)); |
| 242 | + $counterExtract++; |
| 243 | + file_put_contents($progressExtractFileName, sprintf($messages["compression.12"], ($counterExtract / $archive->count()) * 100 . " %")); |
| 244 | + } |
| 245 | + } catch (Exception $e) { |
| 246 | + throw new AJXP_Exception($e); |
| 247 | + } |
| 248 | + file_put_contents($progressExtractFileName, "SUCCESS"); |
| 249 | + } |
| 250 | + elseif ($action == "check_extraction_status") { |
| 251 | + $currentDirUrl = $httpVars["currentDirUrl"]; |
| 252 | + $onlyFileName = $httpVars["onlyFileName"]; |
| 253 | + $progressExtract = file_get_contents($progressExtractFileName); |
| 254 | + if ($progressExtract != "SUCCESS") { |
| 255 | + AJXP_XMLWriter::header(); |
| 256 | + AJXP_XMLWriter::triggerBgAction("check_extraction_status", array( |
| 257 | + "repository_id" => $repository->getId(), |
| 258 | + "extraction_id" => $extractId, |
| 259 | + "currentDirUrl" => $currentDirUrl, |
| 260 | + "onlyFileName" => $onlyFileName |
| 261 | + ), $progressExtract, true, 3); |
| 262 | + AJXP_XMLWriter::close(); |
| 263 | + } else { |
| 264 | + $newNode = new AJXP_Node($currentDirUrl . $onlyFileName); |
| 265 | + $nodesDiffs = array("ADD" => array($newNode), "REMOVE" => array(), "UPDATE" => array()); |
| 266 | + AJXP_Controller::applyHook("node.change", array(null, $newNode, false)); |
| 267 | + AJXP_XMLWriter::header(); |
| 268 | + AJXP_XMLWriter::sendMessage(sprintf($messages["compression.14"], $onlyFileName), null); |
| 269 | + AJXP_XMLWriter::writeNodesDiff($nodesDiffs, false); |
| 270 | + AJXP_XMLWriter::close(); |
| 271 | + if (file_exists($progressExtractFileName)) { |
| 272 | + unlink($progressExtractFileName); |
| 273 | + } |
| 274 | + } |
| 275 | + } |
| 276 | + } |
| 277 | +} |
0 commit comments