Skip to content
This repository was archived by the owner on Nov 25, 2020. It is now read-only.

Commit 0389ee0

Browse files
committed
Updated for new PluginCompression file.
Adapted for new class layout, varible and method names, etc. Also added additional check on exec command return code that should catch and warn on any failed compression or extraction.
1 parent f1201ca commit 0389ee0

File tree

1 file changed

+173
-54
lines changed

1 file changed

+173
-54
lines changed

core/src/plugins/action.compression/PluginCompression.php

Lines changed: 173 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,33 @@ class PluginCompression extends Plugin
6060
* @throws \Pydio\Core\Exception\ActionNotFoundException
6161
* @throws \Pydio\Core\Exception\AuthRequiredException
6262
*/
63+
64+
// Multi-platform function taken from stackoverflow
65+
// http://stackoverflow.com/questions/12424787/how-to-check-if-a-shell-command-exists-from-php
66+
// Check that a command exists on the system for use with exec
67+
public function command_exists ($command)
68+
{
69+
$whereIsCommand = (PHP_OS == 'WINNT') ? 'where' : 'which';
70+
$process = proc_open(
71+
"$whereIsCommand $command",
72+
array(
73+
0 => array("pipe", "r"), //STDIN
74+
1 => array("pipe", "w"), //STDOUT
75+
2 => array("pipe", "w"), //STDERR
76+
),
77+
$pipes
78+
);
79+
if ($process !== false) {
80+
$stdout = stream_get_contents($pipes[1]);
81+
$stderr = stream_get_contents($pipes[2]);
82+
fclose($pipes[1]);
83+
fclose($pipes[2]);
84+
proc_close($process);
85+
return $stdout != '';
86+
}
87+
return false;
88+
}
89+
6390
public function receiveAction(\Psr\Http\Message\ServerRequestInterface &$requestInterface, \Psr\Http\Message\ResponseInterface &$responseInterface)
6491
{
6592
/** @var \Pydio\Core\Model\ContextInterface $ctx */
@@ -78,9 +105,9 @@ public function receiveAction(\Psr\Http\Message\ServerRequestInterface &$request
78105
$responseInterface = $responseInterface->withBody($serializableStream);
79106

80107
switch ($requestInterface->getAttribute("action")) {
81-
108+
82109
case "compression":
83-
110+
84111
$archiveName = InputFilter::decodeSecureMagic($httpVars["archive_name"], InputFilter::SANITIZE_FILENAME);
85112
$archiveFormat = $httpVars["type_archive"];
86113
$tabTypeArchive = array(".tar", ".tar.gz", ".tar.bz2");
@@ -140,51 +167,107 @@ public function receiveAction(\Psr\Http\Message\ServerRequestInterface &$request
140167
$postMessageStatus($messages["compression.17"], Task::STATUS_FAILED);
141168
throw new PydioException($messages["compression.17"]);
142169
}
143-
try {
144-
$tmpArchiveName = tempnam(ApplicationState::getAjxpTmpDir(), "tar-compression") . ".tar";
145-
$archive = new PharData($tmpArchiveName);
146-
} catch (Exception $e) {
147-
$postMessageStatus($e->getMessage(), Task::STATUS_FAILED);
148-
throw $e;
149-
}
150-
$counterCompression = 0;
151-
//THE TWO ARRAY ARE MERGED FOR THE FOREACH LOOP
152-
$tabAllFiles = array_combine($tabAllRecursiveFiles, $tabFilesNames);
153-
foreach ($tabAllFiles as $fullPath => $fileName) {
170+
// Builds a shell command that changes to the workspace location in the filesystem, and then
171+
// compresses with tar and any parallel compression utilities that are installed.
172+
if ($this->command_exists("tar")) {
173+
$FileNames = array();
174+
$FolderNames = array();
175+
foreach ($nodes as $node) {
176+
$nodeUrl = $node->getUrl();
177+
if (is_file($nodeUrl) && filesize($nodeUrl) < $maxAuthorizedSize) {
178+
array_push($FileNames, escapeshellarg(substr($nodeUrl, $currentDirUrlLength)));
179+
}
180+
if (is_dir($nodeUrl)) {
181+
array_push($FolderNames, escapeshellarg(substr($nodeUrl, $currentDirUrlLength)));
182+
}
183+
}
184+
if ($archiveFormat == ".tar.gz") {
185+
if ($this->command_exists("pigz")) {
186+
$tarCommand = "tar -I pigz -cf ";
187+
} else {
188+
$tarCommand = "tar -czf ";
189+
}
190+
} elseif ($archiveFormat == ".tar.bz2") {
191+
if ($this->command_exists("lbzip2")) {
192+
$tarCommand = "tar -I lbzip2 -cf ";
193+
} elseif ($this->command_exists("pbzip2")) {
194+
$tarCommand = "tar -I pbzip2 -cf ";
195+
} else {
196+
$tarCommand = "tar -cjf ";
197+
}
198+
} elseif ($archiveFormat == ".tar") {
199+
$tarCommand = "tar -cf ";
200+
} else {
201+
file_put_contents($progressCompressionFileName, "Error : " . $messages["compression.15"]);
202+
throw new PydioException($messages["compression.15"]);
203+
}
204+
$changeDirCommand = "cd " . MetaStreamWrapper::getRealFSReference($currentDirUrl) . " && ";
205+
$compressCommand = $changeDirCommand . $tarCommand . escapeshellarg($archiveName) . " " . implode(" ", $FolderNames) . " " . implode(" ", $FileNames);
206+
$cmdExitCode = 0;
207+
$cmdOutput = '';
208+
exec($compressCommand, $cmdOutput, $cmdExitCode);
209+
if ($cmdExitCode > 0) {
210+
file_put_contents($progressCompressionFileName, "Error : " . $messages["compression.15"]);
211+
throw new PydioException($messages["compression.15"]);
212+
}
213+
} else {
214+
// If tar command is not found, compress with PHP Phar instead
154215
try {
155-
$archive->addFile(MetaStreamWrapper::getRealFSReference($fullPath), $fileName);
156-
$counterCompression++;
157-
$percent = round(($counterCompression / count($tabAllFiles)) * 100, 0, PHP_ROUND_HALF_DOWN);
158-
$postMessageStatus(sprintf($messages["compression.6"], $percent . " %"), Task::STATUS_RUNNING, $percent);
216+
$tmpArchiveName = tempnam(ApplicationState::getAjxpTmpDir(), "tar-compression") . ".tar";
217+
$archive = new PharData($tmpArchiveName);
159218
} catch (Exception $e) {
160-
unlink($tmpArchiveName);
161219
$postMessageStatus($e->getMessage(), Task::STATUS_FAILED);
162220
throw $e;
163221
}
164-
}
165-
$finalArchive = $tmpArchiveName;
166-
if ($typeArchive != ".tar") {
167-
$archiveTypeCompress = substr(strrchr($typeArchive, "."), 1);
168-
$postMessageStatus(sprintf($messages["compression.7"], strtoupper($archiveTypeCompress)), Task::STATUS_RUNNING);
169-
if ($archiveTypeCompress == "gz") {
170-
$archive->compress(Phar::GZ);
171-
} elseif ($archiveTypeCompress == "bz2") {
172-
$archive->compress(Phar::BZ2);
222+
$counterCompression = 0;
223+
//THE TWO ARRAY ARE MERGED FOR THE FOREACH LOOP
224+
$tabAllFiles = array_combine($tabAllRecursiveFiles, $tabFilesNames);
225+
foreach ($tabAllFiles as $fullPath => $fileName) {
226+
try {
227+
$archive->addFile(MetaStreamWrapper::getRealFSReference($fullPath), $fileName);
228+
$counterCompression++;
229+
$percent = round(($counterCompression / count($tabAllFiles)) * 100, 0, PHP_ROUND_HALF_DOWN);
230+
$postMessageStatus(sprintf($messages["compression.6"], $percent . " %"), Task::STATUS_RUNNING, $percent);
231+
} catch (Exception $e) {
232+
unlink($tmpArchiveName);
233+
$postMessageStatus($e->getMessage(), Task::STATUS_FAILED);
234+
throw $e;
235+
}
236+
}
237+
$finalArchive = $tmpArchiveName;
238+
if ($typeArchive != ".tar") {
239+
$archiveTypeCompress = substr(strrchr($typeArchive, "."), 1);
240+
$postMessageStatus(sprintf($messages["compression.7"], strtoupper($archiveTypeCompress)), Task::STATUS_RUNNING);
241+
if ($archiveTypeCompress == "gz") {
242+
$archive->compress(Phar::GZ);
243+
} elseif ($archiveTypeCompress == "bz2") {
244+
$archive->compress(Phar::BZ2);
245+
}
246+
$finalArchive = $tmpArchiveName . "." . $archiveTypeCompress;
173247
}
174-
$finalArchive = $tmpArchiveName . "." . $archiveTypeCompress;
175-
}
248+
249+
$newNode = new AJXP_Node($currentDirUrl . $archiveName);
250+
$destArchive = $newNode->getRealFile();
251+
rename($finalArchive, $destArchive);
252+
Controller::applyHook("node.before_create", array($newNode, filesize($destArchive)));
253+
254+
if (file_exists($tmpArchiveName)) {
255+
unlink($tmpArchiveName);
256+
unlink(substr($tmpArchiveName, 0, -4));
257+
}
258+
Controller::applyHook("node.change", array(null, $newNode, false), true);
259+
$postMessageStatus("Finished", Task::STATUS_COMPLETE);
260+
break;
261+
262+
// End of Phar compression section
263+
}
176264

177265
$newNode = new AJXP_Node($currentDirUrl . $archiveName);
178266
$destArchive = $newNode->getRealFile();
179-
rename($finalArchive, $destArchive);
180267
Controller::applyHook("node.before_create", array($newNode, filesize($destArchive)));
181-
if (file_exists($tmpArchiveName)) {
182-
unlink($tmpArchiveName);
183-
unlink(substr($tmpArchiveName, 0, -4));
184-
}
185268
Controller::applyHook("node.change", array(null, $newNode, false), true);
186269
$postMessageStatus("Finished", Task::STATUS_COMPLETE);
187-
270+
188271
break;
189272

190273
case "extraction":
@@ -238,29 +321,65 @@ public function receiveAction(\Psr\Http\Message\ServerRequestInterface &$request
238321

239322
mkdir($currentDirUrl . $onlyFileName, 0777, true);
240323
chmod(MetaStreamWrapper::getRealFSReference($currentDirUrl . $onlyFileName), 0777);
241-
try {
242-
$archive = new PharData(MetaStreamWrapper::getRealFSReference($currentAllPydioPath));
243-
$fichiersArchive = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($pharCurrentAllPydioPath));
244-
foreach ($fichiersArchive as $file) {
245-
$fileGetPathName = $file->getPathname();
246-
if ($file->isDir()) {
247-
continue;
324+
325+
// Builds a command that will use any parallel extraction utilities installed to extract an archive file though tar.
326+
if ($this->command_exists("tar")) {
327+
if ($pathInfoCurrentAllPydioPath == "gz") {
328+
if ($this->command_exists("pigz")) {
329+
$tarCommand = "tar -I pigz -xf ";
330+
} else {
331+
$tarCommand = "tar -xzf ";
248332
}
249-
$fileNameInArchive = substr(strstr($fileGetPathName, $fileArchive), strlen($fileArchive) + 1);
250-
try {
251-
$archive->extractTo(MetaStreamWrapper::getRealFSReference($currentDirUrl . $onlyFileName), $fileNameInArchive, false);
252-
} catch (Exception $e) {
253-
$postMessageStatus($e->getMessage(), Task::STATUS_FAILED);
254-
throw new PydioException($e);
333+
} elseif ($pathInfoCurrentAllPydioPath == "bz2") {
334+
if ($this->command_exists("lbzip2")) {
335+
$tarCommand = "tar -I lbzip2 -xf ";
336+
} elseif ($this->command_exists("pbzip2")) {
337+
$tarCommand = "tar -I pbzip2 -xf ";
338+
} else {
339+
$tarCommand = "tar -xjf ";
340+
}
341+
} elseif ($pathInfoCurrentAllPydioPath == "tar") {
342+
$tarCommand = "tar -xf ";
343+
} else {
344+
file_put_contents($progressExtractFileName, "Error : " . $messages["compression.15"]);
345+
throw new PydioException($messages["compression.15"]);
346+
}
347+
$extractCommand = $tarCommand . escapeshellarg(MetaStreamWrapper::getRealFSReference($currentDirUrl . $fileArchive)) . " -C " . escapeshellarg(MetaStreamWrapper::getRealFSReference($currentDirUrl . $onlyFileName));
348+
$cmdExitCode = 0;
349+
$cmdOutput = '';
350+
exec($extractCommand, $cmdOutput, $cmdExitCode);
351+
if ($cmdExitCode > 0) {
352+
file_put_contents($progressExtractFileName, "Error : " . $messages["compression.15"]);
353+
throw new PydioException($messages["compression.15"]);
354+
}
355+
} else {
356+
// If tar command is not found, extract using PHP Phar instead
357+
try {
358+
$archive = new PharData(MetaStreamWrapper::getRealFSReference($currentAllPydioPath));
359+
$fichiersArchive = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($pharCurrentAllPydioPath));
360+
foreach ($fichiersArchive as $file) {
361+
$fileGetPathName = $file->getPathname();
362+
if ($file->isDir()) {
363+
continue;
364+
}
365+
$fileNameInArchive = substr(strstr($fileGetPathName, $fileArchive), strlen($fileArchive) + 1);
366+
try {
367+
$archive->extractTo(MetaStreamWrapper::getRealFSReference($currentDirUrl . $onlyFileName), $fileNameInArchive, false);
368+
} catch (Exception $e) {
369+
$postMessageStatus($e->getMessage(), Task::STATUS_FAILED);
370+
throw new PydioException($e);
371+
}
372+
$counterExtract++;
373+
$progress = round(($counterExtract / $archive->count()) * 100, 0, PHP_ROUND_HALF_DOWN);
374+
$postMessageStatus(sprintf($messages["compression.13"], $progress . "%"), Task::STATUS_RUNNING, $progress);
255375
}
256-
$counterExtract++;
257-
$progress = round(($counterExtract / $archive->count()) * 100, 0, PHP_ROUND_HALF_DOWN);
258-
$postMessageStatus(sprintf($messages["compression.13"], $progress . "%"), Task::STATUS_RUNNING, $progress);
376+
} catch (Exception $e) {
377+
$postMessageStatus($e->getMessage(), Task::STATUS_FAILED);
378+
throw new PydioException($e);
259379
}
260-
} catch (Exception $e) {
261-
$postMessageStatus($e->getMessage(), Task::STATUS_FAILED);
262-
throw new PydioException($e);
380+
// End of Phar extraction section
263381
}
382+
264383
$postMessageStatus("Done", Task::STATUS_COMPLETE, 100);
265384
$newNode = new AJXP_Node($currentDirUrl . $onlyFileName);
266385
$nodesDiff = new NodesDiff();

0 commit comments

Comments
 (0)