@@ -60,6 +60,33 @@ class PluginCompression extends Plugin
60
60
* @throws \Pydio\Core\Exception\ActionNotFoundException
61
61
* @throws \Pydio\Core\Exception\AuthRequiredException
62
62
*/
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
+
63
90
public function receiveAction (\Psr \Http \Message \ServerRequestInterface &$ requestInterface , \Psr \Http \Message \ResponseInterface &$ responseInterface )
64
91
{
65
92
/** @var \Pydio\Core\Model\ContextInterface $ctx */
@@ -78,9 +105,9 @@ public function receiveAction(\Psr\Http\Message\ServerRequestInterface &$request
78
105
$ responseInterface = $ responseInterface ->withBody ($ serializableStream );
79
106
80
107
switch ($ requestInterface ->getAttribute ("action " )) {
81
-
108
+
82
109
case "compression " :
83
-
110
+
84
111
$ archiveName = InputFilter::decodeSecureMagic ($ httpVars ["archive_name " ], InputFilter::SANITIZE_FILENAME );
85
112
$ archiveFormat = $ httpVars ["type_archive " ];
86
113
$ tabTypeArchive = array (".tar " , ".tar.gz " , ".tar.bz2 " );
@@ -140,51 +167,107 @@ public function receiveAction(\Psr\Http\Message\ServerRequestInterface &$request
140
167
$ postMessageStatus ($ messages ["compression.17 " ], Task::STATUS_FAILED );
141
168
throw new PydioException ($ messages ["compression.17 " ]);
142
169
}
143
- try {
144
- $ tmpArchiveName = tempnam (ApplicationState::getTemporaryFolder (), "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
154
215
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 );
159
218
} catch (Exception $ e ) {
160
- unlink ($ tmpArchiveName );
161
219
$ postMessageStatus ($ e ->getMessage (), Task::STATUS_FAILED );
162
220
throw $ e ;
163
221
}
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 ;
173
247
}
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
+ }
176
264
177
265
$ newNode = new AJXP_Node ($ currentDirUrl . $ archiveName );
178
266
$ destArchive = $ newNode ->getRealFile ();
179
- rename ($ finalArchive , $ destArchive );
180
267
Controller::applyHook ("node.before_create " , array ($ newNode , filesize ($ destArchive )));
181
- if (file_exists ($ tmpArchiveName )) {
182
- unlink ($ tmpArchiveName );
183
- unlink (substr ($ tmpArchiveName , 0 , -4 ));
184
- }
185
268
Controller::applyHook ("node.change " , array (null , $ newNode , false ), true );
186
269
$ postMessageStatus ("Finished " , Task::STATUS_COMPLETE );
187
-
270
+
188
271
break ;
189
272
190
273
case "extraction " :
@@ -238,29 +321,65 @@ public function receiveAction(\Psr\Http\Message\ServerRequestInterface &$request
238
321
239
322
mkdir ($ currentDirUrl . $ onlyFileName , 0777 , true );
240
323
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 " ;
248
332
}
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 );
255
375
}
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 );
259
379
}
260
- } catch (Exception $ e ) {
261
- $ postMessageStatus ($ e ->getMessage (), Task::STATUS_FAILED );
262
- throw new PydioException ($ e );
380
+ // End of Phar extraction section
263
381
}
382
+
264
383
$ postMessageStatus ("Done " , Task::STATUS_COMPLETE , 100 );
265
384
$ newNode = new AJXP_Node ($ currentDirUrl . $ onlyFileName );
266
385
$ nodesDiff = new NodesDiff ();
0 commit comments