1
|
|
|
<?php |
|
|
|
|
2
|
|
|
/** |
3
|
|
|
* @package Arastta eCommerce |
4
|
|
|
* @copyright 2015-2017 Arastta Association. All rights reserved. |
5
|
|
|
* @copyright See CREDITS.txt for credits and other copyright notices. |
6
|
|
|
* @license GNU GPL version 3; see LICENSE.txt |
7
|
|
|
* @link https://arastta.org |
8
|
|
|
*/ |
9
|
|
|
|
10
|
|
|
defined('AREXE') or die; |
|
|
|
|
11
|
|
|
/** |
12
|
|
|
* elFinder - file manager for web. |
13
|
|
|
* Core class. |
14
|
|
|
* |
15
|
|
|
* @package elfinder |
16
|
|
|
* @author Dmitry (dio) Levashov |
17
|
|
|
* @author Troex Nevelin |
18
|
|
|
* @author Alexey Sukhotin |
19
|
|
|
**/ |
20
|
|
|
class elFinder { |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* API version number |
24
|
|
|
* |
25
|
|
|
* @var string |
26
|
|
|
**/ |
27
|
|
|
protected $version = '2.0'; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* Storages (root dirs) |
31
|
|
|
* |
32
|
|
|
* @var array |
33
|
|
|
**/ |
34
|
|
|
protected $volumes = array(); |
35
|
|
|
|
36
|
|
|
public static $netDrivers = array(); |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Mounted volumes count |
40
|
|
|
* Required to create unique volume id |
41
|
|
|
* |
42
|
|
|
* @var int |
43
|
|
|
**/ |
44
|
|
|
public static $volumesCnt = 1; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* Default root (storage) |
48
|
|
|
* |
49
|
|
|
* @var elFinderStorageDriver |
50
|
|
|
**/ |
51
|
|
|
protected $default = null; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* Commands and required arguments list |
55
|
|
|
* |
56
|
|
|
* @var array |
57
|
|
|
**/ |
58
|
|
|
protected $commands = array( |
59
|
|
|
'open' => array('target' => false, 'tree' => false, 'init' => false, 'mimes' => false), |
60
|
|
|
'ls' => array('target' => true, 'mimes' => false), |
61
|
|
|
'tree' => array('target' => true), |
62
|
|
|
'parents' => array('target' => true), |
63
|
|
|
'tmb' => array('targets' => true), |
64
|
|
|
'file' => array('target' => true, 'download' => false), |
65
|
|
|
'size' => array('targets' => true), |
66
|
|
|
'mkdir' => array('target' => true, 'name' => true), |
67
|
|
|
'mkfile' => array('target' => true, 'name' => true, 'mimes' => false), |
68
|
|
|
'rm' => array('targets' => true), |
69
|
|
|
'rename' => array('target' => true, 'name' => true, 'mimes' => false), |
70
|
|
|
'duplicate' => array('targets' => true, 'suffix' => false), |
71
|
|
|
'paste' => array('dst' => true, 'targets' => true, 'cut' => false, 'mimes' => false), |
72
|
|
|
'upload' => array('target' => true, 'FILES' => true, 'mimes' => false, 'html' => false), |
73
|
|
|
'get' => array('target' => true), |
74
|
|
|
'put' => array('target' => true, 'content' => '', 'mimes' => false), |
75
|
|
|
'archive' => array('targets' => true, 'type' => true, 'mimes' => false), |
76
|
|
|
'extract' => array('target' => true, 'mimes' => false), |
77
|
|
|
'search' => array('q' => true, 'mimes' => false), |
78
|
|
|
'info' => array('targets' => true), |
79
|
|
|
'dim' => array('target' => true), |
80
|
|
|
'resize' => array('target' => true, 'width' => true, 'height' => true, 'mode' => false, 'x' => false, 'y' => false, 'degree' => false), |
81
|
|
|
'netmount' => array('protocol' => true, 'host' => true, 'path' => false, 'port' => false, 'user' => true, 'pass' => true, 'alias' => false, 'options' => false) |
82
|
|
|
); |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* Commands listeners |
86
|
|
|
* |
87
|
|
|
* @var array |
88
|
|
|
**/ |
89
|
|
|
protected $listeners = array(); |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* script work time for debug |
93
|
|
|
* |
94
|
|
|
* @var string |
95
|
|
|
**/ |
96
|
|
|
protected $time = 0; |
97
|
|
|
/** |
98
|
|
|
* Is elFinder init correctly? |
99
|
|
|
* |
100
|
|
|
* @var bool |
101
|
|
|
**/ |
102
|
|
|
protected $loaded = false; |
103
|
|
|
/** |
104
|
|
|
* Send debug to client? |
105
|
|
|
* |
106
|
|
|
* @var string |
107
|
|
|
**/ |
108
|
|
|
protected $debug = false; |
109
|
|
|
|
110
|
|
|
/** |
111
|
|
|
* session expires timeout |
112
|
|
|
* |
113
|
|
|
* @var int |
114
|
|
|
**/ |
115
|
|
|
protected $timeout = 0; |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* undocumented class variable |
119
|
|
|
* |
120
|
|
|
* @var string |
121
|
|
|
**/ |
122
|
|
|
protected $uploadDebug = ''; |
123
|
|
|
|
124
|
|
|
/** |
125
|
|
|
* Errors from not mounted volumes |
126
|
|
|
* |
127
|
|
|
* @var array |
128
|
|
|
**/ |
129
|
|
|
public $mountErrors = array(); |
130
|
|
|
|
131
|
|
|
// Errors messages |
132
|
|
|
const ERROR_UNKNOWN = 'errUnknown'; |
133
|
|
|
const ERROR_UNKNOWN_CMD = 'errUnknownCmd'; |
134
|
|
|
const ERROR_CONF = 'errConf'; |
135
|
|
|
const ERROR_CONF_NO_JSON = 'errJSON'; |
136
|
|
|
const ERROR_CONF_NO_VOL = 'errNoVolumes'; |
137
|
|
|
const ERROR_INV_PARAMS = 'errCmdParams'; |
138
|
|
|
const ERROR_OPEN = 'errOpen'; |
139
|
|
|
const ERROR_DIR_NOT_FOUND = 'errFolderNotFound'; |
140
|
|
|
const ERROR_FILE_NOT_FOUND = 'errFileNotFound'; // 'File not found.' |
141
|
|
|
const ERROR_TRGDIR_NOT_FOUND = 'errTrgFolderNotFound'; // 'Target folder "$1" not found.' |
142
|
|
|
const ERROR_NOT_DIR = 'errNotFolder'; |
143
|
|
|
const ERROR_NOT_FILE = 'errNotFile'; |
144
|
|
|
const ERROR_PERM_DENIED = 'errPerm'; |
145
|
|
|
const ERROR_LOCKED = 'errLocked'; // '"$1" is locked and can not be renamed, moved or removed.' |
146
|
|
|
const ERROR_EXISTS = 'errExists'; // 'File named "$1" already exists.' |
147
|
|
|
const ERROR_INVALID_NAME = 'errInvName'; // 'Invalid file name.' |
148
|
|
|
const ERROR_MKDIR = 'errMkdir'; |
149
|
|
|
const ERROR_MKFILE = 'errMkfile'; |
150
|
|
|
const ERROR_RENAME = 'errRename'; |
151
|
|
|
const ERROR_COPY = 'errCopy'; |
152
|
|
|
const ERROR_MOVE = 'errMove'; |
153
|
|
|
const ERROR_COPY_FROM = 'errCopyFrom'; |
154
|
|
|
const ERROR_COPY_TO = 'errCopyTo'; |
155
|
|
|
const ERROR_COPY_ITSELF = 'errCopyInItself'; |
156
|
|
|
const ERROR_REPLACE = 'errReplace'; // 'Unable to replace "$1".' |
157
|
|
|
const ERROR_RM = 'errRm'; // 'Unable to remove "$1".' |
158
|
|
|
const ERROR_RM_SRC = 'errRmSrc'; // 'Unable remove source file(s)' |
159
|
|
|
const ERROR_UPLOAD = 'errUpload'; // 'Upload error.' |
160
|
|
|
const ERROR_UPLOAD_FILE = 'errUploadFile'; // 'Unable to upload "$1".' |
161
|
|
|
const ERROR_UPLOAD_NO_FILES = 'errUploadNoFiles'; // 'No files found for upload.' |
162
|
|
|
const ERROR_UPLOAD_TOTAL_SIZE = 'errUploadTotalSize'; // 'Data exceeds the maximum allowed size.' |
163
|
|
|
const ERROR_UPLOAD_FILE_SIZE = 'errUploadFileSize'; // 'File exceeds maximum allowed size.' |
164
|
|
|
const ERROR_UPLOAD_FILE_MIME = 'errUploadMime'; // 'File type not allowed.' |
165
|
|
|
const ERROR_UPLOAD_TRANSFER = 'errUploadTransfer'; // '"$1" transfer error.' |
166
|
|
|
// const ERROR_ACCESS_DENIED = 'errAccess'; |
167
|
|
|
const ERROR_NOT_REPLACE = 'errNotReplace'; // Object "$1" already exists at this location and can not be replaced with object of another type. |
168
|
|
|
const ERROR_SAVE = 'errSave'; |
169
|
|
|
const ERROR_EXTRACT = 'errExtract'; |
170
|
|
|
const ERROR_ARCHIVE = 'errArchive'; |
171
|
|
|
const ERROR_NOT_ARCHIVE = 'errNoArchive'; |
172
|
|
|
const ERROR_ARCHIVE_TYPE = 'errArcType'; |
173
|
|
|
const ERROR_ARC_SYMLINKS = 'errArcSymlinks'; |
174
|
|
|
const ERROR_ARC_MAXSIZE = 'errArcMaxSize'; |
175
|
|
|
const ERROR_RESIZE = 'errResize'; |
176
|
|
|
const ERROR_UNSUPPORT_TYPE = 'errUsupportType'; |
177
|
|
|
const ERROR_NOT_UTF8_CONTENT = 'errNotUTF8Content'; |
178
|
|
|
const ERROR_NETMOUNT = 'errNetMount'; |
179
|
|
|
const ERROR_NETMOUNT_NO_DRIVER = 'errNetMountNoDriver'; |
180
|
|
|
const ERROR_NETMOUNT_FAILED = 'errNetMountFailed'; |
181
|
|
|
|
182
|
|
|
const ERROR_SESSION_EXPIRES = 'errSessionExpires'; |
183
|
|
|
|
184
|
|
|
const ERROR_CREATING_TEMP_DIR = 'errCreatingTempDir'; |
185
|
|
|
const ERROR_FTP_DOWNLOAD_FILE = 'errFtpDownloadFile'; |
186
|
|
|
const ERROR_FTP_UPLOAD_FILE = 'errFtpUploadFile'; |
187
|
|
|
const ERROR_FTP_MKDIR = 'errFtpMkdir'; |
188
|
|
|
const ERROR_ARCHIVE_EXEC = 'errArchiveExec'; |
189
|
|
|
const ERROR_EXTRACT_EXEC = 'errExtractExec'; |
190
|
|
|
|
191
|
|
|
/** |
192
|
|
|
* Constructor |
193
|
|
|
* |
194
|
|
|
* @param array elFinder and roots configurations |
195
|
|
|
* @return void |
|
|
|
|
196
|
|
|
* @author Dmitry (dio) Levashov |
197
|
|
|
**/ |
198
|
|
|
public function __construct($opts) { |
199
|
|
|
if (session_id() == '') { |
200
|
|
|
session_start(); |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
$this->time = $this->utime(); |
|
|
|
|
204
|
|
|
$this->debug = (isset($opts['debug']) && $opts['debug'] ? true : false); |
|
|
|
|
205
|
|
|
$this->timeout = (isset($opts['timeout']) ? $opts['timeout'] : 0); |
206
|
|
|
|
207
|
|
|
setlocale(LC_ALL, !empty($opts['locale']) ? $opts['locale'] : 'en_US.UTF-8'); |
208
|
|
|
|
209
|
|
|
// bind events listeners |
210
|
|
|
if (!empty($opts['bind']) && is_array($opts['bind'])) { |
211
|
|
|
foreach ($opts['bind'] as $cmd => $handler) { |
212
|
|
|
$this->bind($cmd, $handler); |
213
|
|
|
} |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
if (!isset($opts['roots']) || !is_array($opts['roots'])) { |
217
|
|
|
$opts['roots'] = array(); |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
// check for net volumes stored in session |
221
|
|
|
foreach ($this->getNetVolumes() as $root) { |
222
|
|
|
$opts['roots'][] = $root; |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
// "mount" volumes |
226
|
|
|
foreach ($opts['roots'] as $i => $o) { |
227
|
|
|
$class = 'elFinderVolume'.(isset($o['driver']) ? $o['driver'] : ''); |
228
|
|
|
|
229
|
|
|
if (class_exists($class)) { |
230
|
|
|
$volume = new $class(); |
231
|
|
|
|
232
|
|
|
try { |
233
|
|
|
if ($volume->mount($o)) { |
234
|
|
|
// unique volume id (ends on "_") - used as prefix to files hash |
235
|
|
|
$id = $volume->id(); |
236
|
|
|
|
237
|
|
|
$this->volumes[$id] = $volume; |
238
|
|
|
if (!$this->default && $volume->isReadable()) { |
239
|
|
|
$this->default = $this->volumes[$id]; |
240
|
|
|
} |
241
|
|
|
} else { |
242
|
|
|
$this->mountErrors[] = 'Driver "'.$class.'" : '.implode(' ', $volume->error()); |
243
|
|
|
} |
244
|
|
|
} catch (Exception $e) { |
245
|
|
|
$this->mountErrors[] = 'Driver "'.$class.'" : '.$e->getMessage(); |
246
|
|
|
} |
247
|
|
|
} else { |
248
|
|
|
$this->mountErrors[] = 'Driver "'.$class.'" does not exists'; |
249
|
|
|
} |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
// if at least one readable volume - ii desu >_< |
253
|
|
|
$this->loaded = !empty($this->default); |
254
|
|
|
} |
255
|
|
|
|
256
|
|
|
/** |
257
|
|
|
* Return true if fm init correctly |
258
|
|
|
* |
259
|
|
|
* @return bool |
260
|
|
|
* @author Dmitry (dio) Levashov |
261
|
|
|
**/ |
262
|
|
|
public function loaded() { |
263
|
|
|
return $this->loaded; |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
/** |
267
|
|
|
* Return version (api) number |
268
|
|
|
* |
269
|
|
|
* @return string |
270
|
|
|
* @author Dmitry (dio) Levashov |
271
|
|
|
**/ |
272
|
|
|
public function version() { |
273
|
|
|
return $this->version; |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
/** |
277
|
|
|
* Add handler to elFinder command |
278
|
|
|
* |
279
|
|
|
* @param string command name |
280
|
|
|
* @param string|array callback name or array(object, method) |
281
|
|
|
* @return elFinder |
282
|
|
|
* @author Dmitry (dio) Levashov |
283
|
|
|
**/ |
284
|
|
|
public function bind($cmd, $handler) { |
285
|
|
|
$cmds = $cmd == '*' |
286
|
|
|
? array_keys($this->commands) |
287
|
|
|
: array_map('trim', explode(' ', $cmd)); |
288
|
|
|
|
289
|
|
|
foreach ($cmds as $cmd) { |
290
|
|
|
if ($cmd) { |
291
|
|
|
if (!isset($this->listeners[$cmd])) { |
292
|
|
|
$this->listeners[$cmd] = array(); |
293
|
|
|
} |
294
|
|
|
|
295
|
|
|
if (is_callable($handler)) { |
296
|
|
|
$this->listeners[$cmd][] = $handler; |
297
|
|
|
} |
298
|
|
|
} |
299
|
|
|
} |
300
|
|
|
|
301
|
|
|
return $this; |
302
|
|
|
} |
303
|
|
|
|
304
|
|
|
/** |
305
|
|
|
* Remove event (command exec) handler |
306
|
|
|
* |
307
|
|
|
* @param string command name |
308
|
|
|
* @param string|array callback name or array(object, method) |
309
|
|
|
* @return elFinder |
310
|
|
|
* @author Dmitry (dio) Levashov |
311
|
|
|
**/ |
312
|
|
|
public function unbind($cmd, $handler) { |
313
|
|
|
if (!empty($this->listeners[$cmd])) { |
314
|
|
|
foreach ($this->listeners[$cmd] as $i => $h) { |
315
|
|
|
if ($h === $handler) { |
316
|
|
|
unset($this->listeners[$cmd][$i]); |
317
|
|
|
return $this; |
318
|
|
|
} |
319
|
|
|
} |
320
|
|
|
} |
321
|
|
|
return $this; |
322
|
|
|
} |
323
|
|
|
|
324
|
|
|
/** |
325
|
|
|
* Return true if command exists |
326
|
|
|
* |
327
|
|
|
* @param string command name |
328
|
|
|
* @return bool |
329
|
|
|
* @author Dmitry (dio) Levashov |
330
|
|
|
**/ |
331
|
|
|
public function commandExists($cmd) { |
332
|
|
|
return $this->loaded && isset($this->commands[$cmd]) && method_exists($this, $cmd); |
333
|
|
|
} |
334
|
|
|
|
335
|
|
|
/** |
336
|
|
|
* Return root - file's owner (public func of volume()) |
337
|
|
|
* |
338
|
|
|
* @param string file hash |
339
|
|
|
* @return elFinderStorageDriver |
340
|
|
|
* @author Naoki Sawada |
341
|
|
|
*/ |
342
|
|
|
public function getVolume($hash) { |
343
|
|
|
return $this->volume($hash); |
344
|
|
|
} |
345
|
|
|
|
346
|
|
|
/** |
347
|
|
|
* Return command required arguments info |
348
|
|
|
* |
349
|
|
|
* @param string command name |
350
|
|
|
* @return array |
351
|
|
|
* @author Dmitry (dio) Levashov |
352
|
|
|
**/ |
353
|
|
|
public function commandArgsList($cmd) { |
354
|
|
|
return $this->commandExists($cmd) ? $this->commands[$cmd] : array(); |
355
|
|
|
} |
356
|
|
|
|
357
|
|
|
private function session_expires() { |
|
|
|
|
358
|
|
|
|
359
|
|
|
if (!isset($_SESSION['LAST_ACTIVITY'])) { |
360
|
|
|
$_SESSION['LAST_ACTIVITY'] = time(); |
361
|
|
|
return false; |
362
|
|
|
} |
363
|
|
|
|
364
|
|
|
if ( ($this->timeout > 0) && (time() - $_SESSION['LAST_ACTIVITY'] > $this->timeout) ) { |
365
|
|
|
return true; |
366
|
|
|
} |
367
|
|
|
|
368
|
|
|
$_SESSION['LAST_ACTIVITY'] = time(); |
369
|
|
|
return false; |
370
|
|
|
} |
371
|
|
|
|
372
|
|
|
/** |
373
|
|
|
* Exec command and return result |
374
|
|
|
* |
375
|
|
|
* @param string $cmd command name |
376
|
|
|
* @param array $args command arguments |
377
|
|
|
* @return array |
378
|
|
|
* @author Dmitry (dio) Levashov |
379
|
|
|
**/ |
380
|
|
|
public function exec($cmd, $args) { |
381
|
|
|
|
382
|
|
|
if (!$this->loaded) { |
383
|
|
|
return array('error' => $this->error(self::ERROR_CONF, self::ERROR_CONF_NO_VOL)); |
384
|
|
|
} |
385
|
|
|
|
386
|
|
|
if ($this->session_expires()) { |
387
|
|
|
return array('error' => $this->error(self::ERROR_SESSION_EXPIRES)); |
388
|
|
|
} |
389
|
|
|
|
390
|
|
|
if (!$this->commandExists($cmd)) { |
391
|
|
|
return array('error' => $this->error(self::ERROR_UNKNOWN_CMD)); |
392
|
|
|
} |
393
|
|
|
|
394
|
|
|
if (!empty($args['mimes']) && is_array($args['mimes'])) { |
395
|
|
|
foreach ($this->volumes as $id => $v) { |
396
|
|
|
$this->volumes[$id]->setMimesFilter($args['mimes']); |
397
|
|
|
} |
398
|
|
|
} |
399
|
|
|
|
400
|
|
|
$result = $this->$cmd($args); |
401
|
|
|
|
402
|
|
|
if (isset($result['removed'])) { |
403
|
|
|
foreach ($this->volumes as $volume) { |
404
|
|
|
$result['removed'] = array_merge($result['removed'], $volume->removed()); |
405
|
|
|
$volume->resetRemoved(); |
406
|
|
|
} |
407
|
|
|
} |
408
|
|
|
|
409
|
|
|
// call handlers for this command |
410
|
|
|
if (!empty($this->listeners[$cmd])) { |
411
|
|
|
foreach ($this->listeners[$cmd] as $handler) { |
412
|
|
|
if (call_user_func_array($handler,array($cmd,&$result,$args,$this))) { |
413
|
|
|
// handler return true to force sync client after command completed |
414
|
|
|
$result['sync'] = true; |
415
|
|
|
} |
416
|
|
|
} |
417
|
|
|
} |
418
|
|
|
|
419
|
|
|
// replace removed files info with removed files hashes |
420
|
|
|
if (!empty($result['removed'])) { |
421
|
|
|
$removed = array(); |
422
|
|
|
foreach ($result['removed'] as $file) { |
423
|
|
|
$removed[] = $file['hash']; |
424
|
|
|
} |
425
|
|
|
$result['removed'] = array_unique($removed); |
426
|
|
|
} |
427
|
|
|
// remove hidden files and filter files by mimetypes |
428
|
|
|
if (!empty($result['added'])) { |
429
|
|
|
$result['added'] = $this->filter($result['added']); |
430
|
|
|
} |
431
|
|
|
// remove hidden files and filter files by mimetypes |
432
|
|
|
if (!empty($result['changed'])) { |
433
|
|
|
$result['changed'] = $this->filter($result['changed']); |
434
|
|
|
} |
435
|
|
|
|
436
|
|
|
if ($this->debug || !empty($args['debug'])) { |
437
|
|
|
$result['debug'] = array( |
438
|
|
|
'connector' => 'php', |
439
|
|
|
'phpver' => PHP_VERSION, |
440
|
|
|
'time' => $this->utime() - $this->time, |
441
|
|
|
'memory' => (function_exists('memory_get_peak_usage') ? ceil(memory_get_peak_usage()/1024).'Kb / ' : '').ceil(memory_get_usage()/1024).'Kb / '.ini_get('memory_limit'), |
442
|
|
|
'upload' => $this->uploadDebug, |
443
|
|
|
'volumes' => array(), |
444
|
|
|
'mountErrors' => $this->mountErrors |
445
|
|
|
); |
446
|
|
|
|
447
|
|
|
foreach ($this->volumes as $id => $volume) { |
448
|
|
|
$result['debug']['volumes'][] = $volume->debug(); |
449
|
|
|
} |
450
|
|
|
} |
451
|
|
|
|
452
|
|
|
foreach ($this->volumes as $volume) { |
453
|
|
|
$volume->umount(); |
454
|
|
|
} |
455
|
|
|
|
456
|
|
|
return $result; |
457
|
|
|
} |
458
|
|
|
|
459
|
|
|
/** |
460
|
|
|
* Return file real path |
461
|
|
|
* |
462
|
|
|
* @param string $hash file hash |
463
|
|
|
* @return string |
464
|
|
|
* @author Dmitry (dio) Levashov |
465
|
|
|
**/ |
466
|
|
|
public function realpath($hash) { |
467
|
|
|
if (($volume = $this->volume($hash)) == false) { |
468
|
|
|
return false; |
|
|
|
|
469
|
|
|
} |
470
|
|
|
return $volume->realpath($hash); |
471
|
|
|
} |
472
|
|
|
|
473
|
|
|
/** |
474
|
|
|
* Return network volumes config. |
475
|
|
|
* |
476
|
|
|
* @return array |
477
|
|
|
* @author Dmitry (dio) Levashov |
478
|
|
|
*/ |
479
|
|
|
protected function getNetVolumes() { |
|
|
|
|
480
|
|
|
return isset($_SESSION['elFinderNetVolumes']) && is_array($_SESSION['elFinderNetVolumes']) ? $_SESSION['elFinderNetVolumes'] : array(); |
481
|
|
|
} |
482
|
|
|
|
483
|
|
|
/** |
484
|
|
|
* Save network volumes config. |
485
|
|
|
* |
486
|
|
|
* @param array $volumes volumes config |
487
|
|
|
* @return void |
488
|
|
|
* @author Dmitry (dio) Levashov |
489
|
|
|
*/ |
490
|
|
|
protected function saveNetVolumes($volumes) { |
|
|
|
|
491
|
|
|
$_SESSION['elFinderNetVolumes'] = $volumes; |
492
|
|
|
} |
493
|
|
|
|
494
|
|
|
/***************************************************************************/ |
495
|
|
|
/* commands */ |
496
|
|
|
/***************************************************************************/ |
497
|
|
|
|
498
|
|
|
/** |
499
|
|
|
* Normalize error messages |
500
|
|
|
* |
501
|
|
|
* @return array |
502
|
|
|
* @author Dmitry (dio) Levashov |
503
|
|
|
**/ |
504
|
|
|
public function error() { |
505
|
|
|
$errors = array(); |
506
|
|
|
|
507
|
|
|
foreach (func_get_args() as $msg) { |
508
|
|
|
if (is_array($msg)) { |
509
|
|
|
$errors = array_merge($errors, $msg); |
510
|
|
|
} else { |
511
|
|
|
$errors[] = $msg; |
512
|
|
|
} |
513
|
|
|
} |
514
|
|
|
|
515
|
|
|
return count($errors) ? $errors : array(self::ERROR_UNKNOWN); |
516
|
|
|
} |
517
|
|
|
|
518
|
|
|
protected function netmount($args) { |
519
|
|
|
$options = array(); |
520
|
|
|
$protocol = $args['protocol']; |
521
|
|
|
$driver = isset(self::$netDrivers[$protocol]) ? $protocol : ''; |
522
|
|
|
$class = 'elfindervolume'.$protocol; |
523
|
|
|
|
524
|
|
|
if (!$driver) { |
525
|
|
|
return array('error' => $this->error(self::ERROR_NETMOUNT, $args['host'], self::ERROR_NETMOUNT_NO_DRIVER)); |
526
|
|
|
} |
527
|
|
|
|
528
|
|
|
if (!$args['path']) { |
529
|
|
|
$args['path'] = '/'; |
530
|
|
|
} |
531
|
|
|
|
532
|
|
|
foreach ($args as $k => $v) { |
533
|
|
|
if ($k != 'options' && $k != 'protocol' && $v) { |
534
|
|
|
$options[$k] = $v; |
535
|
|
|
} |
536
|
|
|
} |
537
|
|
|
|
538
|
|
|
if (is_array($args['options'])) { |
539
|
|
|
foreach ($args['options'] as $key => $value) { |
540
|
|
|
$options[$key] = $value; |
541
|
|
|
} |
542
|
|
|
} |
543
|
|
|
|
544
|
|
|
$volume = new $class(); |
545
|
|
|
|
546
|
|
|
if ($volume->mount($options)) { |
547
|
|
|
$netVolumes = $this->getNetVolumes(); |
548
|
|
|
$options['driver'] = $driver; |
549
|
|
|
$netVolumes[] = $options; |
550
|
|
|
$netVolumes = array_unique($netVolumes); |
551
|
|
|
$this->saveNetVolumes($netVolumes); |
552
|
|
|
return array('sync' => true); |
553
|
|
|
} else { |
554
|
|
|
return array('error' => $this->error(self::ERROR_NETMOUNT, $args['host'], implode(' ', $volume->error()))); |
555
|
|
|
} |
556
|
|
|
|
557
|
|
|
} |
558
|
|
|
|
559
|
|
|
/** |
560
|
|
|
* "Open" directory |
561
|
|
|
* Return array with following elements |
562
|
|
|
* - cwd - opened dir info |
563
|
|
|
* - files - opened dir content [and dirs tree if $args[tree]] |
564
|
|
|
* - api - api version (if $args[init]) |
565
|
|
|
* - uplMaxSize - if $args[init] |
566
|
|
|
* - error - on failed |
567
|
|
|
* |
568
|
|
|
* @param array command arguments |
569
|
|
|
* @return array |
570
|
|
|
* @author Dmitry (dio) Levashov |
571
|
|
|
**/ |
572
|
|
|
protected function open($args) { |
573
|
|
|
$target = $args['target']; |
574
|
|
|
$init = !empty($args['init']); |
575
|
|
|
$tree = !empty($args['tree']); |
|
|
|
|
576
|
|
|
$volume = $this->volume($target); |
577
|
|
|
$cwd = $volume ? $volume->dir($target, true) : false; |
578
|
|
|
$hash = $init ? 'default folder' : '#'.$target; |
579
|
|
|
|
580
|
|
|
// on init request we can get invalid dir hash - |
581
|
|
|
// dir which can not be opened now, but remembered by client, |
582
|
|
|
// so open default dir |
583
|
|
|
if ((!$cwd || !$cwd['read']) && $init) { |
584
|
|
|
$volume = $this->default; |
585
|
|
|
$cwd = $volume->dir($volume->defaultPath(), true); |
586
|
|
|
} |
587
|
|
|
|
588
|
|
|
if (!$cwd) { |
589
|
|
|
return array('error' => $this->error(self::ERROR_OPEN, $hash, self::ERROR_DIR_NOT_FOUND)); |
590
|
|
|
} |
591
|
|
|
if (!$cwd['read']) { |
592
|
|
|
return array('error' => $this->error(self::ERROR_OPEN, $hash, self::ERROR_PERM_DENIED)); |
593
|
|
|
} |
594
|
|
|
|
595
|
|
|
$files = array(); |
596
|
|
|
|
597
|
|
|
// get folders trees |
598
|
|
|
if ($args['tree']) { |
599
|
|
|
foreach ($this->volumes as $id => $v) { |
600
|
|
|
if (($tree = $v->tree('', 0, $cwd['hash'])) != false) { |
601
|
|
|
$files = array_merge($files, $tree); |
602
|
|
|
} |
603
|
|
|
} |
604
|
|
|
} |
605
|
|
|
|
606
|
|
|
// get current working directory files list and add to $files if not exists in it |
607
|
|
|
if (($ls = $volume->scandir($cwd['hash'])) === false) { |
608
|
|
|
return array('error' => $this->error(self::ERROR_OPEN, $cwd['name'], $volume->error())); |
609
|
|
|
} |
610
|
|
|
|
611
|
|
|
foreach ($ls as $file) { |
612
|
|
|
if (!in_array($file, $files)) { |
613
|
|
|
$files[] = $file; |
614
|
|
|
} |
615
|
|
|
} |
616
|
|
|
|
617
|
|
|
$result = array( |
618
|
|
|
'cwd' => $cwd, |
619
|
|
|
'options' => $volume->options($cwd['hash']), |
620
|
|
|
'files' => $files |
621
|
|
|
); |
622
|
|
|
|
623
|
|
|
if (!empty($args['init'])) { |
624
|
|
|
$result['api'] = $this->version; |
625
|
|
|
$result['uplMaxSize'] = ini_get('upload_max_filesize'); |
626
|
|
|
$result['netDrivers'] = array_keys(self::$netDrivers); |
627
|
|
|
} |
628
|
|
|
|
629
|
|
|
return $result; |
630
|
|
|
} |
631
|
|
|
|
632
|
|
|
/** |
633
|
|
|
* Return dir files names list |
634
|
|
|
* |
635
|
|
|
* @param array command arguments |
636
|
|
|
* @return array |
637
|
|
|
* @author Dmitry (dio) Levashov |
638
|
|
|
**/ |
639
|
|
View Code Duplication |
protected function ls($args) { |
640
|
|
|
$target = $args['target']; |
641
|
|
|
|
642
|
|
|
if (($volume = $this->volume($target)) == false |
643
|
|
|
|| ($list = $volume->ls($target)) === false) { |
644
|
|
|
return array('error' => $this->error(self::ERROR_OPEN, '#'.$target)); |
645
|
|
|
} |
646
|
|
|
return array('list' => $list); |
647
|
|
|
} |
648
|
|
|
|
649
|
|
|
/** |
650
|
|
|
* Return subdirs for required directory |
651
|
|
|
* |
652
|
|
|
* @param array command arguments |
653
|
|
|
* @return array |
654
|
|
|
* @author Dmitry (dio) Levashov |
655
|
|
|
**/ |
656
|
|
View Code Duplication |
protected function tree($args) { |
657
|
|
|
$target = $args['target']; |
658
|
|
|
|
659
|
|
|
if (($volume = $this->volume($target)) == false |
660
|
|
|
|| ($tree = $volume->tree($target)) == false) { |
661
|
|
|
return array('error' => $this->error(self::ERROR_OPEN, '#'.$target)); |
662
|
|
|
} |
663
|
|
|
|
664
|
|
|
return array('tree' => $tree); |
665
|
|
|
} |
666
|
|
|
|
667
|
|
|
/** |
668
|
|
|
* Return parents dir for required directory |
669
|
|
|
* |
670
|
|
|
* @param array command arguments |
671
|
|
|
* @return array |
672
|
|
|
* @author Dmitry (dio) Levashov |
673
|
|
|
**/ |
674
|
|
View Code Duplication |
protected function parents($args) { |
675
|
|
|
$target = $args['target']; |
676
|
|
|
|
677
|
|
|
if (($volume = $this->volume($target)) == false |
678
|
|
|
|| ($tree = $volume->parents($target)) == false) { |
679
|
|
|
return array('error' => $this->error(self::ERROR_OPEN, '#'.$target)); |
680
|
|
|
} |
681
|
|
|
|
682
|
|
|
return array('tree' => $tree); |
683
|
|
|
} |
684
|
|
|
|
685
|
|
|
/** |
686
|
|
|
* Return new created thumbnails list |
687
|
|
|
* |
688
|
|
|
* @param array command arguments |
689
|
|
|
* @return array |
690
|
|
|
* @author Dmitry (dio) Levashov |
691
|
|
|
**/ |
692
|
|
|
protected function tmb($args) { |
693
|
|
|
|
694
|
|
|
$result = array('images' => array()); |
695
|
|
|
$targets = $args['targets']; |
696
|
|
|
|
697
|
|
|
foreach ($targets as $target) { |
698
|
|
|
if (($volume = $this->volume($target)) != false |
699
|
|
|
&& (($tmb = $volume->tmb($target)) != false)) { |
700
|
|
|
$result['images'][$target] = $tmb; |
701
|
|
|
} |
702
|
|
|
} |
703
|
|
|
return $result; |
704
|
|
|
} |
705
|
|
|
|
706
|
|
|
/** |
707
|
|
|
* Required to output file in browser when volume URL is not set |
708
|
|
|
* Return array contains opened file pointer, root itself and required headers |
709
|
|
|
* |
710
|
|
|
* @param array command arguments |
711
|
|
|
* @return array |
712
|
|
|
* @author Dmitry (dio) Levashov |
713
|
|
|
**/ |
714
|
|
|
protected function file($args) { |
|
|
|
|
715
|
|
|
$target = $args['target']; |
716
|
|
|
$download = !empty($args['download']); |
717
|
|
|
$h403 = 'HTTP/1.x 403 Access Denied'; |
718
|
|
|
$h404 = 'HTTP/1.x 404 Not Found'; |
719
|
|
|
|
720
|
|
View Code Duplication |
if (($volume = $this->volume($target)) == false) { |
721
|
|
|
return array('error' => 'File not found', 'header' => $h404, 'raw' => true); |
722
|
|
|
} |
723
|
|
|
|
724
|
|
View Code Duplication |
if (($file = $volume->file($target)) == false) { |
725
|
|
|
return array('error' => 'File not found', 'header' => $h404, 'raw' => true); |
726
|
|
|
} |
727
|
|
|
|
728
|
|
|
if (!$file['read']) { |
729
|
|
|
return array('error' => 'Access denied', 'header' => $h403, 'raw' => true); |
730
|
|
|
} |
731
|
|
|
|
732
|
|
View Code Duplication |
if (($fp = $volume->open($target)) == false) { |
733
|
|
|
return array('error' => 'File not found', 'header' => $h404, 'raw' => true); |
734
|
|
|
} |
735
|
|
|
|
736
|
|
|
if ($download) { |
737
|
|
|
$disp = 'attachment'; |
738
|
|
|
$mime = 'application/octet-stream'; |
739
|
|
|
} else { |
740
|
|
|
$disp = preg_match('/^(image|text)/i', $file['mime']) || $file['mime'] == 'application/x-shockwave-flash' |
741
|
|
|
? 'inline' |
742
|
|
|
: 'attachment'; |
743
|
|
|
$mime = $file['mime']; |
744
|
|
|
} |
745
|
|
|
|
746
|
|
|
$filenameEncoded = rawurlencode($file['name']); |
747
|
|
|
if (strpos($filenameEncoded, '%') === false) { // ASCII only |
748
|
|
|
$filename = 'filename="'.$file['name'].'"'; |
749
|
|
|
} else { |
750
|
|
|
$ua = $_SERVER["HTTP_USER_AGENT"]; |
751
|
|
|
if (preg_match('/MSIE [4-8]/', $ua)) { // IE < 9 do not support RFC 6266 (RFC 2231/RFC 5987) |
752
|
|
|
$filename = 'filename="'.$filenameEncoded.'"'; |
753
|
|
|
} elseif (strpos($ua, 'Chrome') === false && strpos($ua, 'Safari') !== false) { // Safari |
754
|
|
|
$filename = 'filename="'.str_replace('"', '', $file['name']).'"'; |
755
|
|
|
} else { // RFC 6266 (RFC 2231/RFC 5987) |
756
|
|
|
$filename = 'filename*=UTF-8\'\''.$filenameEncoded; |
757
|
|
|
} |
758
|
|
|
} |
759
|
|
|
|
760
|
|
|
$result = array( |
761
|
|
|
'volume' => $volume, |
762
|
|
|
'pointer' => $fp, |
763
|
|
|
'info' => $file, |
764
|
|
|
'header' => array( |
765
|
|
|
'Content-Type: '.$mime, |
766
|
|
|
'Content-Disposition: '.$disp.'; '.$filename, |
767
|
|
|
'Content-Location: '.$file['name'], |
768
|
|
|
'Content-Transfer-Encoding: binary', |
769
|
|
|
'Content-Length: '.$file['size'], |
770
|
|
|
'Connection: close' |
771
|
|
|
) |
772
|
|
|
); |
773
|
|
|
return $result; |
774
|
|
|
} |
775
|
|
|
|
776
|
|
|
/** |
777
|
|
|
* Count total files size |
778
|
|
|
* |
779
|
|
|
* @param array command arguments |
780
|
|
|
* @return array |
781
|
|
|
* @author Dmitry (dio) Levashov |
782
|
|
|
**/ |
783
|
|
|
protected function size($args) { |
784
|
|
|
$size = 0; |
785
|
|
|
|
786
|
|
|
foreach ($args['targets'] as $target) { |
787
|
|
|
if (($volume = $this->volume($target)) == false |
788
|
|
|
|| ($file = $volume->file($target)) == false |
789
|
|
|
|| !$file['read']) { |
790
|
|
|
return array('error' => $this->error(self::ERROR_OPEN, '#'.$target)); |
791
|
|
|
} |
792
|
|
|
|
793
|
|
|
$size += $volume->size($target); |
794
|
|
|
} |
795
|
|
|
return array('size' => $size); |
796
|
|
|
} |
797
|
|
|
|
798
|
|
|
/** |
799
|
|
|
* Create directory |
800
|
|
|
* |
801
|
|
|
* @param array command arguments |
802
|
|
|
* @return array |
803
|
|
|
* @author Dmitry (dio) Levashov |
804
|
|
|
**/ |
805
|
|
View Code Duplication |
protected function mkdir($args) { |
806
|
|
|
$target = $args['target']; |
807
|
|
|
$name = $args['name']; |
808
|
|
|
|
809
|
|
|
if (($volume = $this->volume($target)) == false) { |
810
|
|
|
return array('error' => $this->error(self::ERROR_MKDIR, $name, self::ERROR_TRGDIR_NOT_FOUND, '#'.$target)); |
811
|
|
|
} |
812
|
|
|
|
813
|
|
|
return ($dir = $volume->mkdir($target, $name)) == false |
814
|
|
|
? array('error' => $this->error(self::ERROR_MKDIR, $name, $volume->error())) |
815
|
|
|
: array('added' => array($dir)); |
816
|
|
|
} |
817
|
|
|
|
818
|
|
|
/** |
819
|
|
|
* Create empty file |
820
|
|
|
* |
821
|
|
|
* @param array command arguments |
822
|
|
|
* @return array |
823
|
|
|
* @author Dmitry (dio) Levashov |
824
|
|
|
**/ |
825
|
|
View Code Duplication |
protected function mkfile($args) { |
826
|
|
|
$target = $args['target']; |
827
|
|
|
$name = $args['name']; |
828
|
|
|
|
829
|
|
|
if (($volume = $this->volume($target)) == false) { |
830
|
|
|
return array('error' => $this->error(self::ERROR_MKFILE, $name, self::ERROR_TRGDIR_NOT_FOUND, '#'.$target)); |
831
|
|
|
} |
832
|
|
|
|
833
|
|
|
return ($file = $volume->mkfile($target, $args['name'])) == false |
834
|
|
|
? array('error' => $this->error(self::ERROR_MKFILE, $name, $volume->error())) |
835
|
|
|
: array('added' => array($file)); |
836
|
|
|
} |
837
|
|
|
|
838
|
|
|
/** |
839
|
|
|
* Rename file |
840
|
|
|
* |
841
|
|
|
* @param array $args |
842
|
|
|
* @return array |
843
|
|
|
* @author Dmitry (dio) Levashov |
844
|
|
|
**/ |
845
|
|
|
protected function rename($args) { |
846
|
|
|
$target = $args['target']; |
847
|
|
|
$name = $args['name']; |
848
|
|
|
|
849
|
|
View Code Duplication |
if (($volume = $this->volume($target)) == false |
850
|
|
|
|| ($rm = $volume->file($target)) == false) { |
851
|
|
|
return array('error' => $this->error(self::ERROR_RENAME, '#'.$target, self::ERROR_FILE_NOT_FOUND)); |
852
|
|
|
} |
853
|
|
|
$rm['realpath'] = $volume->realpath($target); |
854
|
|
|
|
855
|
|
|
return ($file = $volume->rename($target, $name)) == false |
856
|
|
|
? array('error' => $this->error(self::ERROR_RENAME, $rm['name'], $volume->error())) |
857
|
|
|
: array('added' => array($file), 'removed' => array($rm)); |
858
|
|
|
} |
859
|
|
|
|
860
|
|
|
/** |
861
|
|
|
* Duplicate file - create copy with "copy %d" suffix |
862
|
|
|
* |
863
|
|
|
* @param array $args command arguments |
864
|
|
|
* @return array |
865
|
|
|
* @author Dmitry (dio) Levashov |
866
|
|
|
**/ |
867
|
|
|
protected function duplicate($args) { |
868
|
|
|
$targets = is_array($args['targets']) ? $args['targets'] : array(); |
869
|
|
|
$result = array('added' => array()); |
870
|
|
|
$suffix = empty($args['suffix']) ? 'copy' : $args['suffix']; |
871
|
|
|
|
872
|
|
|
foreach ($targets as $target) { |
873
|
|
View Code Duplication |
if (($volume = $this->volume($target)) == false |
874
|
|
|
|| ($src = $volume->file($target)) == false) { |
875
|
|
|
$result['warning'] = $this->error(self::ERROR_COPY, '#'.$target, self::ERROR_FILE_NOT_FOUND); |
876
|
|
|
break; |
877
|
|
|
} |
878
|
|
|
|
879
|
|
|
if (($file = $volume->duplicate($target, $suffix)) == false) { |
880
|
|
|
$result['warning'] = $this->error($volume->error()); |
881
|
|
|
break; |
882
|
|
|
} |
883
|
|
|
|
884
|
|
|
$result['added'][] = $file; |
885
|
|
|
} |
886
|
|
|
|
887
|
|
|
return $result; |
888
|
|
|
} |
889
|
|
|
|
890
|
|
|
/** |
891
|
|
|
* Remove dirs/files |
892
|
|
|
* |
893
|
|
|
* @param array command arguments |
894
|
|
|
* @return array |
895
|
|
|
* @author Dmitry (dio) Levashov |
896
|
|
|
**/ |
897
|
|
|
protected function rm($args) { |
898
|
|
|
$targets = is_array($args['targets']) ? $args['targets'] : array(); |
899
|
|
|
$result = array('removed' => array()); |
900
|
|
|
|
901
|
|
|
foreach ($targets as $target) { |
902
|
|
View Code Duplication |
if (($volume = $this->volume($target)) == false) { |
903
|
|
|
$result['warning'] = $this->error(self::ERROR_RM, '#'.$target, self::ERROR_FILE_NOT_FOUND); |
904
|
|
|
return $result; |
905
|
|
|
} |
906
|
|
|
if (!$volume->rm($target)) { |
907
|
|
|
$result['warning'] = $this->error($volume->error()); |
908
|
|
|
return $result; |
909
|
|
|
} |
910
|
|
|
} |
911
|
|
|
|
912
|
|
|
return $result; |
913
|
|
|
} |
914
|
|
|
|
915
|
|
|
/** |
916
|
|
|
* Save uploaded files |
917
|
|
|
* |
918
|
|
|
* @param array |
919
|
|
|
* @return array |
920
|
|
|
* @author Dmitry (dio) Levashov |
921
|
|
|
**/ |
922
|
|
|
protected function upload($args) { |
923
|
|
|
$target = $args['target']; |
924
|
|
|
$volume = $this->volume($target); |
925
|
|
|
$files = isset($args['FILES']['upload']) && is_array($args['FILES']['upload']) ? $args['FILES']['upload'] : array(); |
926
|
|
|
$result = array('added' => array(), 'header' => empty($args['html']) ? false : 'Content-Type: text/html; charset=utf-8'); |
927
|
|
|
|
928
|
|
|
if (empty($files)) { |
929
|
|
|
return array('error' => $this->error(self::ERROR_UPLOAD, self::ERROR_UPLOAD_NO_FILES), 'header' => $header); |
|
|
|
|
930
|
|
|
} |
931
|
|
|
|
932
|
|
|
if (!$volume) { |
933
|
|
|
return array('error' => $this->error(self::ERROR_UPLOAD, self::ERROR_TRGDIR_NOT_FOUND, '#'.$target), 'header' => $header); |
934
|
|
|
} |
935
|
|
|
|
936
|
|
|
foreach ($files['name'] as $i => $name) { |
937
|
|
|
if (($error = $files['error'][$i]) > 0) { |
938
|
|
|
$result['warning'] = $this->error(self::ERROR_UPLOAD_FILE, $name, $error == UPLOAD_ERR_INI_SIZE || $error == UPLOAD_ERR_FORM_SIZE ? self::ERROR_UPLOAD_FILE_SIZE : self::ERROR_UPLOAD_TRANSFER); |
939
|
|
|
$this->uploadDebug = 'Upload error code: '.$error; |
940
|
|
|
break; |
941
|
|
|
} |
942
|
|
|
|
943
|
|
|
$tmpname = $files['tmp_name'][$i]; |
944
|
|
|
|
945
|
|
|
if (($fp = fopen($tmpname, 'rb')) == false) { |
946
|
|
|
$result['warning'] = $this->error(self::ERROR_UPLOAD_FILE, $name, self::ERROR_UPLOAD_TRANSFER); |
947
|
|
|
$this->uploadDebug = 'Upload error: unable open tmp file'; |
948
|
|
|
break; |
949
|
|
|
} |
950
|
|
|
|
951
|
|
|
if (($file = $volume->upload($fp, $target, $name, $tmpname)) === false) { |
952
|
|
|
$result['warning'] = $this->error(self::ERROR_UPLOAD_FILE, $name, $volume->error()); |
953
|
|
|
fclose($fp); |
954
|
|
|
break; |
955
|
|
|
} |
956
|
|
|
|
957
|
|
|
fclose($fp); |
958
|
|
|
$result['added'][] = $file; |
959
|
|
|
} |
960
|
|
|
|
961
|
|
|
return $result; |
962
|
|
|
} |
963
|
|
|
|
964
|
|
|
/** |
965
|
|
|
* Copy/move files into new destination |
966
|
|
|
* |
967
|
|
|
* @param array command arguments |
968
|
|
|
* @return array |
969
|
|
|
* @author Dmitry (dio) Levashov |
970
|
|
|
**/ |
971
|
|
|
protected function paste($args) { |
972
|
|
|
$dst = $args['dst']; |
973
|
|
|
$targets = is_array($args['targets']) ? $args['targets'] : array(); |
974
|
|
|
$cut = !empty($args['cut']); |
975
|
|
|
$error = $cut ? self::ERROR_MOVE : self::ERROR_COPY; |
976
|
|
|
$result = array('added' => array(), 'removed' => array()); |
977
|
|
|
|
978
|
|
|
if (($dstVolume = $this->volume($dst)) == false) { |
979
|
|
|
return array('error' => $this->error($error, '#'.$targets[0], self::ERROR_TRGDIR_NOT_FOUND, '#'.$dst)); |
980
|
|
|
} |
981
|
|
|
|
982
|
|
|
foreach ($targets as $target) { |
983
|
|
View Code Duplication |
if (($srcVolume = $this->volume($target)) == false) { |
984
|
|
|
$result['warning'] = $this->error($error, '#'.$target, self::ERROR_FILE_NOT_FOUND); |
985
|
|
|
break; |
986
|
|
|
} |
987
|
|
|
|
988
|
|
|
if (($file = $dstVolume->paste($srcVolume, $target, $dst, $cut)) == false) { |
989
|
|
|
$result['warning'] = $this->error($dstVolume->error()); |
990
|
|
|
break; |
991
|
|
|
} |
992
|
|
|
|
993
|
|
|
$result['added'][] = $file; |
994
|
|
|
} |
995
|
|
|
return $result; |
996
|
|
|
} |
997
|
|
|
|
998
|
|
|
/** |
999
|
|
|
* Return file content |
1000
|
|
|
* |
1001
|
|
|
* @param array $args command arguments |
1002
|
|
|
* @return array |
1003
|
|
|
* @author Dmitry (dio) Levashov |
1004
|
|
|
**/ |
1005
|
|
|
protected function get($args) { |
1006
|
|
|
$target = $args['target']; |
1007
|
|
|
$volume = $this->volume($target); |
1008
|
|
|
|
1009
|
|
|
if (!$volume || ($file = $volume->file($target)) == false) { |
1010
|
|
|
return array('error' => $this->error(self::ERROR_OPEN, '#'.$target, self::ERROR_FILE_NOT_FOUND)); |
1011
|
|
|
} |
1012
|
|
|
|
1013
|
|
View Code Duplication |
if (($content = $volume->getContents($target)) === false) { |
1014
|
|
|
return array('error' => $this->error(self::ERROR_OPEN, $volume->path($target), $volume->error())); |
1015
|
|
|
} |
1016
|
|
|
|
1017
|
|
|
$json = json_encode($content); |
1018
|
|
|
|
1019
|
|
|
if ($json == 'null' && strlen($json) < strlen($content)) { |
1020
|
|
|
return array('error' => $this->error(self::ERROR_NOT_UTF8_CONTENT, $volume->path($target))); |
1021
|
|
|
} |
1022
|
|
|
|
1023
|
|
|
return array('content' => $content); |
1024
|
|
|
} |
1025
|
|
|
|
1026
|
|
|
/** |
1027
|
|
|
* Save content into text file |
1028
|
|
|
* |
1029
|
|
|
* @return array |
1030
|
|
|
* @author Dmitry (dio) Levashov |
1031
|
|
|
**/ |
1032
|
|
|
protected function put($args) { |
1033
|
|
|
$target = $args['target']; |
1034
|
|
|
|
1035
|
|
View Code Duplication |
if (($volume = $this->volume($target)) == false |
1036
|
|
|
|| ($file = $volume->file($target)) == false) { |
1037
|
|
|
return array('error' => $this->error(self::ERROR_SAVE, '#'.$target, self::ERROR_FILE_NOT_FOUND)); |
1038
|
|
|
} |
1039
|
|
|
|
1040
|
|
View Code Duplication |
if (($file = $volume->putContents($target, $args['content'])) == false) { |
1041
|
|
|
return array('error' => $this->error(self::ERROR_SAVE, $volume->path($target), $volume->error())); |
1042
|
|
|
} |
1043
|
|
|
|
1044
|
|
|
return array('changed' => array($file)); |
1045
|
|
|
} |
1046
|
|
|
|
1047
|
|
|
/** |
1048
|
|
|
* Extract files from archive |
1049
|
|
|
* |
1050
|
|
|
* @param array $args command arguments |
1051
|
|
|
* @return array |
1052
|
|
|
* @author Dmitry (dio) Levashov, |
1053
|
|
|
* @author Alexey Sukhotin |
1054
|
|
|
**/ |
1055
|
|
|
protected function extract($args) { |
1056
|
|
|
$target = $args['target']; |
1057
|
|
|
$mimes = !empty($args['mimes']) && is_array($args['mimes']) ? $args['mimes'] : array(); |
|
|
|
|
1058
|
|
|
$error = array(self::ERROR_EXTRACT, '#'.$target); |
|
|
|
|
1059
|
|
|
|
1060
|
|
View Code Duplication |
if (($volume = $this->volume($target)) == false |
1061
|
|
|
|| ($file = $volume->file($target)) == false) { |
1062
|
|
|
return array('error' => $this->error(self::ERROR_EXTRACT, '#'.$target, self::ERROR_FILE_NOT_FOUND)); |
1063
|
|
|
} |
1064
|
|
|
|
1065
|
|
|
return ($file = $volume->extract($target)) |
1066
|
|
|
? array('added' => array($file)) |
1067
|
|
|
: array('error' => $this->error(self::ERROR_EXTRACT, $volume->path($target), $volume->error())); |
1068
|
|
|
} |
1069
|
|
|
|
1070
|
|
|
/** |
1071
|
|
|
* Create archive |
1072
|
|
|
* |
1073
|
|
|
* @param array $args command arguments |
1074
|
|
|
* @return array |
1075
|
|
|
* @author Dmitry (dio) Levashov, |
1076
|
|
|
* @author Alexey Sukhotin |
1077
|
|
|
**/ |
1078
|
|
|
protected function archive($args) { |
1079
|
|
|
$type = $args['type']; |
|
|
|
|
1080
|
|
|
$targets = isset($args['targets']) && is_array($args['targets']) ? $args['targets'] : array(); |
1081
|
|
|
|
1082
|
|
|
if (($volume = $this->volume($targets[0])) == false) { |
1083
|
|
|
return $this->error(self::ERROR_ARCHIVE, self::ERROR_TRGDIR_NOT_FOUND); |
1084
|
|
|
} |
1085
|
|
|
|
1086
|
|
|
return ($file = $volume->archive($targets, $args['type'])) |
1087
|
|
|
? array('added' => array($file)) |
1088
|
|
|
: array('error' => $this->error(self::ERROR_ARCHIVE, $volume->error())); |
1089
|
|
|
} |
1090
|
|
|
|
1091
|
|
|
/** |
1092
|
|
|
* Search files |
1093
|
|
|
* |
1094
|
|
|
* @param array $args command arguments |
1095
|
|
|
* @return array |
1096
|
|
|
* @author Dmitry Levashov |
1097
|
|
|
**/ |
1098
|
|
|
protected function search($args) { |
1099
|
|
|
$q = trim($args['q']); |
1100
|
|
|
$mimes = !empty($args['mimes']) && is_array($args['mimes']) ? $args['mimes'] : array(); |
1101
|
|
|
$result = array(); |
1102
|
|
|
|
1103
|
|
|
foreach ($this->volumes as $volume) { |
1104
|
|
|
$result = array_merge($result, $volume->search($q, $mimes)); |
1105
|
|
|
} |
1106
|
|
|
|
1107
|
|
|
return array('files' => $result); |
1108
|
|
|
} |
1109
|
|
|
|
1110
|
|
|
/** |
1111
|
|
|
* Return file info (used by client "places" ui) |
1112
|
|
|
* |
1113
|
|
|
* @param array $args command arguments |
1114
|
|
|
* @return array |
1115
|
|
|
* @author Dmitry Levashov |
1116
|
|
|
**/ |
1117
|
|
|
protected function info($args) { |
1118
|
|
|
$files = array(); |
1119
|
|
|
|
1120
|
|
|
foreach ($args['targets'] as $hash) { |
1121
|
|
|
if (($volume = $this->volume($hash)) != false |
1122
|
|
|
&& ($info = $volume->file($hash)) != false) { |
1123
|
|
|
$files[] = $info; |
1124
|
|
|
} |
1125
|
|
|
} |
1126
|
|
|
|
1127
|
|
|
return array('files' => $files); |
1128
|
|
|
} |
1129
|
|
|
|
1130
|
|
|
/** |
1131
|
|
|
* Return image dimmensions |
1132
|
|
|
* |
1133
|
|
|
* @param array $args command arguments |
1134
|
|
|
* @return array |
1135
|
|
|
* @author Dmitry (dio) Levashov |
1136
|
|
|
**/ |
1137
|
|
|
protected function dim($args) { |
1138
|
|
|
$target = $args['target']; |
1139
|
|
|
|
1140
|
|
|
if (($volume = $this->volume($target)) != false) { |
1141
|
|
|
$dim = $volume->dimensions($target); |
1142
|
|
|
return $dim ? array('dim' => $dim) : array(); |
1143
|
|
|
} |
1144
|
|
|
return array(); |
1145
|
|
|
} |
1146
|
|
|
|
1147
|
|
|
/** |
1148
|
|
|
* Resize image |
1149
|
|
|
* |
1150
|
|
|
* @param array command arguments |
1151
|
|
|
* @return array |
1152
|
|
|
* @author Dmitry (dio) Levashov |
1153
|
|
|
* @author Alexey Sukhotin |
1154
|
|
|
**/ |
1155
|
|
|
protected function resize($args) { |
1156
|
|
|
$target = $args['target']; |
1157
|
|
|
$width = $args['width']; |
1158
|
|
|
$height = $args['height']; |
1159
|
|
|
$x = (int)$args['x']; |
1160
|
|
|
$y = (int)$args['y']; |
1161
|
|
|
$mode = $args['mode']; |
1162
|
|
|
$bg = null; |
1163
|
|
|
$degree = (int)$args['degree']; |
1164
|
|
|
|
1165
|
|
View Code Duplication |
if (($volume = $this->volume($target)) == false |
1166
|
|
|
|| ($file = $volume->file($target)) == false) { |
1167
|
|
|
return array('error' => $this->error(self::ERROR_RESIZE, '#'.$target, self::ERROR_FILE_NOT_FOUND)); |
1168
|
|
|
} |
1169
|
|
|
|
1170
|
|
|
return ($file = $volume->resize($target, $width, $height, $x, $y, $mode, $bg, $degree)) |
1171
|
|
|
? array('changed' => array($file)) |
1172
|
|
|
: array('error' => $this->error(self::ERROR_RESIZE, $volume->path($target), $volume->error())); |
1173
|
|
|
} |
1174
|
|
|
|
1175
|
|
|
/***************************************************************************/ |
1176
|
|
|
/* utils */ |
1177
|
|
|
/***************************************************************************/ |
1178
|
|
|
|
1179
|
|
|
/** |
1180
|
|
|
* Return root - file's owner |
1181
|
|
|
* |
1182
|
|
|
* @param string file hash |
1183
|
|
|
* @return elFinderStorageDriver |
1184
|
|
|
* @author Dmitry (dio) Levashov |
1185
|
|
|
**/ |
1186
|
|
|
protected function volume($hash) { |
1187
|
|
|
foreach ($this->volumes as $id => $v) { |
1188
|
|
|
if (strpos(''.$hash, $id) === 0) { |
1189
|
|
|
return $this->volumes[$id]; |
1190
|
|
|
} |
1191
|
|
|
} |
1192
|
|
|
return false; |
|
|
|
|
1193
|
|
|
} |
1194
|
|
|
|
1195
|
|
|
/** |
1196
|
|
|
* Return files info array |
1197
|
|
|
* |
1198
|
|
|
* @param array $data one file info or files info |
1199
|
|
|
* @return array |
1200
|
|
|
* @author Dmitry (dio) Levashov |
1201
|
|
|
**/ |
1202
|
|
|
protected function toArray($data) { |
1203
|
|
|
return isset($data['hash']) || !is_array($data) ? array($data) : $data; |
1204
|
|
|
} |
1205
|
|
|
|
1206
|
|
|
/** |
1207
|
|
|
* Return fils hashes list |
1208
|
|
|
* |
1209
|
|
|
* @param array $files files info |
1210
|
|
|
* @return array |
1211
|
|
|
* @author Dmitry (dio) Levashov |
1212
|
|
|
**/ |
1213
|
|
|
protected function hashes($files) { |
1214
|
|
|
$ret = array(); |
1215
|
|
|
foreach ($files as $file) { |
1216
|
|
|
$ret[] = $file['hash']; |
1217
|
|
|
} |
1218
|
|
|
return $ret; |
1219
|
|
|
} |
1220
|
|
|
|
1221
|
|
|
/** |
1222
|
|
|
* Remove from files list hidden files and files with required mime types |
1223
|
|
|
* |
1224
|
|
|
* @param array $files files info |
1225
|
|
|
* @return array |
1226
|
|
|
* @author Dmitry (dio) Levashov |
1227
|
|
|
**/ |
1228
|
|
|
protected function filter($files) { |
1229
|
|
|
foreach ($files as $i => $file) { |
1230
|
|
|
if (!empty($file['hidden']) || !$this->default->mimeAccepted($file['mime'])) { |
1231
|
|
|
unset($files[$i]); |
1232
|
|
|
} |
1233
|
|
|
} |
1234
|
|
|
return array_merge($files, array()); |
1235
|
|
|
} |
1236
|
|
|
|
1237
|
|
|
protected function utime() { |
1238
|
|
|
$time = explode(" ", microtime()); |
1239
|
|
|
return (double)$time[1] + (double)$time[0]; |
1240
|
|
|
} |
1241
|
|
|
|
1242
|
|
|
} // END class |
1243
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.