drg_elfinder 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (185) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +28 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/config/drg_elfinder_manifest.js +1 -0
  6. data/app/assets/javascripts/drg_elfinder.js +15 -0
  7. data/app/assets/javascripts/elfinder/Changelog +1283 -0
  8. data/app/assets/javascripts/elfinder/LICENSE.md +15 -0
  9. data/app/assets/javascripts/elfinder/README.md +216 -0
  10. data/app/assets/javascripts/elfinder/bower.json +28 -0
  11. data/app/assets/javascripts/elfinder/composer.json +39 -0
  12. data/app/assets/javascripts/elfinder/css/elfinder.full.css +5350 -0
  13. data/app/assets/javascripts/elfinder/css/elfinder.min.css +9 -0
  14. data/app/assets/javascripts/elfinder/css/theme.css +430 -0
  15. data/app/assets/javascripts/elfinder/elfinder.html +74 -0
  16. data/app/assets/javascripts/elfinder/elfinder.legacy.html +94 -0
  17. data/app/assets/javascripts/elfinder/img/arrows-active.png +0 -0
  18. data/app/assets/javascripts/elfinder/img/arrows-normal.png +0 -0
  19. data/app/assets/javascripts/elfinder/img/crop.gif +0 -0
  20. data/app/assets/javascripts/elfinder/img/dialogs.png +0 -0
  21. data/app/assets/javascripts/elfinder/img/edit_aceeditor.png +0 -0
  22. data/app/assets/javascripts/elfinder/img/edit_ckeditor.png +0 -0
  23. data/app/assets/javascripts/elfinder/img/edit_ckeditor5.png +0 -0
  24. data/app/assets/javascripts/elfinder/img/edit_codemirror.png +0 -0
  25. data/app/assets/javascripts/elfinder/img/edit_creativecloud.png +0 -0
  26. data/app/assets/javascripts/elfinder/img/edit_onlineconvert.png +0 -0
  27. data/app/assets/javascripts/elfinder/img/edit_pixlreditor.png +0 -0
  28. data/app/assets/javascripts/elfinder/img/edit_pixlrexpress.png +0 -0
  29. data/app/assets/javascripts/elfinder/img/edit_simplemde.png +0 -0
  30. data/app/assets/javascripts/elfinder/img/edit_tinymce.png +0 -0
  31. data/app/assets/javascripts/elfinder/img/edit_tuiimgedit.png +0 -0
  32. data/app/assets/javascripts/elfinder/img/edit_zohooffice.png +0 -0
  33. data/app/assets/javascripts/elfinder/img/editor-icons.png +0 -0
  34. data/app/assets/javascripts/elfinder/img/icons-big.png +0 -0
  35. data/app/assets/javascripts/elfinder/img/icons-big.svg +1 -0
  36. data/app/assets/javascripts/elfinder/img/icons-small.png +0 -0
  37. data/app/assets/javascripts/elfinder/img/logo.png +0 -0
  38. data/app/assets/javascripts/elfinder/img/progress.gif +0 -0
  39. data/app/assets/javascripts/elfinder/img/quicklook-bg.png +0 -0
  40. data/app/assets/javascripts/elfinder/img/quicklook-icons.png +0 -0
  41. data/app/assets/javascripts/elfinder/img/resize.png +0 -0
  42. data/app/assets/javascripts/elfinder/img/spinner-mini.gif +0 -0
  43. data/app/assets/javascripts/elfinder/img/toolbar.png +0 -0
  44. data/app/assets/javascripts/elfinder/img/trashmesh.png +0 -0
  45. data/app/assets/javascripts/elfinder/img/tui-icon-a.svg +235 -0
  46. data/app/assets/javascripts/elfinder/img/tui-icon-b.svg +224 -0
  47. data/app/assets/javascripts/elfinder/img/tui-icon-c.svg +224 -0
  48. data/app/assets/javascripts/elfinder/img/tui-icon-d.svg +224 -0
  49. data/app/assets/javascripts/elfinder/img/ui-icons_ffffff_256x240.png +0 -0
  50. data/app/assets/javascripts/elfinder/img/volume_icon_box.png +0 -0
  51. data/app/assets/javascripts/elfinder/img/volume_icon_box.svg +1 -0
  52. data/app/assets/javascripts/elfinder/img/volume_icon_dropbox.png +0 -0
  53. data/app/assets/javascripts/elfinder/img/volume_icon_dropbox.svg +1 -0
  54. data/app/assets/javascripts/elfinder/img/volume_icon_ftp.png +0 -0
  55. data/app/assets/javascripts/elfinder/img/volume_icon_ftp.svg +1 -0
  56. data/app/assets/javascripts/elfinder/img/volume_icon_googledrive.png +0 -0
  57. data/app/assets/javascripts/elfinder/img/volume_icon_googledrive.svg +1 -0
  58. data/app/assets/javascripts/elfinder/img/volume_icon_local.png +0 -0
  59. data/app/assets/javascripts/elfinder/img/volume_icon_local.svg +1 -0
  60. data/app/assets/javascripts/elfinder/img/volume_icon_network.png +0 -0
  61. data/app/assets/javascripts/elfinder/img/volume_icon_network.svg +1 -0
  62. data/app/assets/javascripts/elfinder/img/volume_icon_onedrive.png +0 -0
  63. data/app/assets/javascripts/elfinder/img/volume_icon_onedrive.svg +1 -0
  64. data/app/assets/javascripts/elfinder/img/volume_icon_sql.png +0 -0
  65. data/app/assets/javascripts/elfinder/img/volume_icon_sql.svg +1 -0
  66. data/app/assets/javascripts/elfinder/img/volume_icon_trash.png +0 -0
  67. data/app/assets/javascripts/elfinder/img/volume_icon_trash.svg +1 -0
  68. data/app/assets/javascripts/elfinder/img/volume_icon_zip.png +0 -0
  69. data/app/assets/javascripts/elfinder/img/volume_icon_zip.svg +1 -0
  70. data/app/assets/javascripts/elfinder/js/elfinder.full.js +36019 -0
  71. data/app/assets/javascripts/elfinder/js/elfinder.min.js +25 -0
  72. data/app/assets/javascripts/elfinder/js/extras/editors.default.js +2643 -0
  73. data/app/assets/javascripts/elfinder/js/extras/editors.default.min.js +2 -0
  74. data/app/assets/javascripts/elfinder/js/extras/quicklook.googledocs.js +75 -0
  75. data/app/assets/javascripts/elfinder/js/extras/quicklook.googledocs.min.js +1 -0
  76. data/app/assets/javascripts/elfinder/js/i18n/elfinder.LANG.js +587 -0
  77. data/app/assets/javascripts/elfinder/js/i18n/elfinder.ar.js +580 -0
  78. data/app/assets/javascripts/elfinder/js/i18n/elfinder.bg.js +559 -0
  79. data/app/assets/javascripts/elfinder/js/i18n/elfinder.ca.js +375 -0
  80. data/app/assets/javascripts/elfinder/js/i18n/elfinder.cs.js +581 -0
  81. data/app/assets/javascripts/elfinder/js/i18n/elfinder.da.js +580 -0
  82. data/app/assets/javascripts/elfinder/js/i18n/elfinder.de.js +582 -0
  83. data/app/assets/javascripts/elfinder/js/i18n/elfinder.el.js +374 -0
  84. data/app/assets/javascripts/elfinder/js/i18n/elfinder.es.js +546 -0
  85. data/app/assets/javascripts/elfinder/js/i18n/elfinder.fa.js +580 -0
  86. data/app/assets/javascripts/elfinder/js/i18n/elfinder.fallback.js +11 -0
  87. data/app/assets/javascripts/elfinder/js/i18n/elfinder.fo.js +419 -0
  88. data/app/assets/javascripts/elfinder/js/i18n/elfinder.fr.js +578 -0
  89. data/app/assets/javascripts/elfinder/js/i18n/elfinder.fr_CA.js +580 -0
  90. data/app/assets/javascripts/elfinder/js/i18n/elfinder.he.js +375 -0
  91. data/app/assets/javascripts/elfinder/js/i18n/elfinder.hr.js +434 -0
  92. data/app/assets/javascripts/elfinder/js/i18n/elfinder.hu.js +580 -0
  93. data/app/assets/javascripts/elfinder/js/i18n/elfinder.id.js +498 -0
  94. data/app/assets/javascripts/elfinder/js/i18n/elfinder.it.js +552 -0
  95. data/app/assets/javascripts/elfinder/js/i18n/elfinder.ja.js +581 -0
  96. data/app/assets/javascripts/elfinder/js/i18n/elfinder.ko.js +582 -0
  97. data/app/assets/javascripts/elfinder/js/i18n/elfinder.nl.js +581 -0
  98. data/app/assets/javascripts/elfinder/js/i18n/elfinder.no.js +374 -0
  99. data/app/assets/javascripts/elfinder/js/i18n/elfinder.pl.js +580 -0
  100. data/app/assets/javascripts/elfinder/js/i18n/elfinder.pt_BR.js +580 -0
  101. data/app/assets/javascripts/elfinder/js/i18n/elfinder.ro.js +417 -0
  102. data/app/assets/javascripts/elfinder/js/i18n/elfinder.ru.js +582 -0
  103. data/app/assets/javascripts/elfinder/js/i18n/elfinder.si.js +537 -0
  104. data/app/assets/javascripts/elfinder/js/i18n/elfinder.sk.js +581 -0
  105. data/app/assets/javascripts/elfinder/js/i18n/elfinder.sl.js +374 -0
  106. data/app/assets/javascripts/elfinder/js/i18n/elfinder.sr.js +374 -0
  107. data/app/assets/javascripts/elfinder/js/i18n/elfinder.sv.js +375 -0
  108. data/app/assets/javascripts/elfinder/js/i18n/elfinder.tr.js +583 -0
  109. data/app/assets/javascripts/elfinder/js/i18n/elfinder.ug_CN.js +374 -0
  110. data/app/assets/javascripts/elfinder/js/i18n/elfinder.uk.js +580 -0
  111. data/app/assets/javascripts/elfinder/js/i18n/elfinder.vi.js +579 -0
  112. data/app/assets/javascripts/elfinder/js/i18n/elfinder.zh_CN.js +585 -0
  113. data/app/assets/javascripts/elfinder/js/i18n/elfinder.zh_TW.js +582 -0
  114. data/app/assets/javascripts/elfinder/js/i18n/help/cs.html.js +10 -0
  115. data/app/assets/javascripts/elfinder/js/i18n/help/de.html.js +15 -0
  116. data/app/assets/javascripts/elfinder/js/i18n/help/en.html.js +10 -0
  117. data/app/assets/javascripts/elfinder/js/i18n/help/es.html.js +10 -0
  118. data/app/assets/javascripts/elfinder/js/i18n/help/ja.html.js +10 -0
  119. data/app/assets/javascripts/elfinder/js/i18n/help/ko.html.js +10 -0
  120. data/app/assets/javascripts/elfinder/js/i18n/help/pl.html.js +10 -0
  121. data/app/assets/javascripts/elfinder/js/i18n/help/ru.html.js +10 -0
  122. data/app/assets/javascripts/elfinder/js/i18n/help/sk.html.js +10 -0
  123. data/app/assets/javascripts/elfinder/js/i18n/help/tr.html.js +10 -0
  124. data/app/assets/javascripts/elfinder/js/proxy/elFinderSupportVer1.js +408 -0
  125. data/app/assets/javascripts/elfinder/js/worker/calcfilehash.js +20 -0
  126. data/app/assets/javascripts/elfinder/js/worker/quicklook.tiff.js +7 -0
  127. data/app/assets/javascripts/elfinder/js/worker/quicklook.unzip.js +55 -0
  128. data/app/assets/javascripts/elfinder/main.default.js +175 -0
  129. data/app/assets/javascripts/elfinder/package.json +13 -0
  130. data/app/assets/javascripts/elfinder/php/MySQLStorage.sql +47 -0
  131. data/app/assets/javascripts/elfinder/php/autoload.php +56 -0
  132. data/app/assets/javascripts/elfinder/php/connector.maximal.php-dist +449 -0
  133. data/app/assets/javascripts/elfinder/php/connector.minimal.php-dist +180 -0
  134. data/app/assets/javascripts/elfinder/php/editors/OnlineConvert/editor.php +113 -0
  135. data/app/assets/javascripts/elfinder/php/editors/ZipArchive/editor.php +12 -0
  136. data/app/assets/javascripts/elfinder/php/editors/ZohoOffice/editor.php +206 -0
  137. data/app/assets/javascripts/elfinder/php/editors/editor.php +79 -0
  138. data/app/assets/javascripts/elfinder/php/elFinder.class.php +5401 -0
  139. data/app/assets/javascripts/elfinder/php/elFinderConnector.class.php +380 -0
  140. data/app/assets/javascripts/elfinder/php/elFinderFlysystemGoogleDriveNetmount.php +380 -0
  141. data/app/assets/javascripts/elfinder/php/elFinderPlugin.php +113 -0
  142. data/app/assets/javascripts/elfinder/php/elFinderSession.php +335 -0
  143. data/app/assets/javascripts/elfinder/php/elFinderSessionInterface.php +57 -0
  144. data/app/assets/javascripts/elfinder/php/elFinderVolumeBox.class.php +1972 -0
  145. data/app/assets/javascripts/elfinder/php/elFinderVolumeDriver.class.php +7651 -0
  146. data/app/assets/javascripts/elfinder/php/elFinderVolumeDropbox.class.php +1464 -0
  147. data/app/assets/javascripts/elfinder/php/elFinderVolumeDropbox2.class.php +1516 -0
  148. data/app/assets/javascripts/elfinder/php/elFinderVolumeFTP.class.php +1810 -0
  149. data/app/assets/javascripts/elfinder/php/elFinderVolumeGoogleDrive.class.php +2163 -0
  150. data/app/assets/javascripts/elfinder/php/elFinderVolumeGroup.class.php +315 -0
  151. data/app/assets/javascripts/elfinder/php/elFinderVolumeLocalFileSystem.class.php +1477 -0
  152. data/app/assets/javascripts/elfinder/php/elFinderVolumeMySQL.class.php +1022 -0
  153. data/app/assets/javascripts/elfinder/php/elFinderVolumeOneDrive.class.php +2131 -0
  154. data/app/assets/javascripts/elfinder/php/elFinderVolumeSFTPphpseclib.class.php +838 -0
  155. data/app/assets/javascripts/elfinder/php/elFinderVolumeTrash.class.php +51 -0
  156. data/app/assets/javascripts/elfinder/php/elFinderVolumeTrashMySQL.class.php +51 -0
  157. data/app/assets/javascripts/elfinder/php/libs/GdBmp.php +473 -0
  158. data/app/assets/javascripts/elfinder/php/mime.types +781 -0
  159. data/app/assets/javascripts/elfinder/php/plugins/AutoResize/plugin.php +151 -0
  160. data/app/assets/javascripts/elfinder/php/plugins/AutoRotate/plugin.php +148 -0
  161. data/app/assets/javascripts/elfinder/php/plugins/Normalizer/plugin.php +204 -0
  162. data/app/assets/javascripts/elfinder/php/plugins/Sanitizer/plugin.php +157 -0
  163. data/app/assets/javascripts/elfinder/php/plugins/Watermark/logo.png +0 -0
  164. data/app/assets/javascripts/elfinder/php/plugins/Watermark/plugin.php +432 -0
  165. data/app/assets/javascripts/elfinder/php/plugins/WinRemoveTailDots/plugin.php +114 -0
  166. data/app/assets/javascripts/elfinder/php/resources/image.png +0 -0
  167. data/app/assets/javascripts/elfinder/php/resources/video.png +0 -0
  168. data/app/assets/javascripts/elfinder/sounds/rm.wav +0 -0
  169. data/app/controllers/dc_elfinder_controller.rb +63 -0
  170. data/app/models/drgcms_form_fields/elfinder.rb +85 -0
  171. data/changelog.md +0 -0
  172. data/lib/drg_elfinder/engine.rb +5 -0
  173. data/lib/drg_elfinder/version.rb +3 -0
  174. data/lib/drg_elfinder.rb +9 -0
  175. data/lib/el_finder/action.rb +19 -0
  176. data/lib/el_finder/base64.rb +24 -0
  177. data/lib/el_finder/connector.rb +625 -0
  178. data/lib/el_finder/image.rb +33 -0
  179. data/lib/el_finder/mime_type.rb +86 -0
  180. data/lib/el_finder/pathname.rb +185 -0
  181. data/lib/el_finder/version.rb +5 -0
  182. data/lib/el_finder.rb +8 -0
  183. data/lib/patches/patch_for_elfinder.rb +115 -0
  184. data/lib/tasks/drg_elfinder_tasks.rake +10 -0
  185. metadata +245 -0
@@ -0,0 +1,1810 @@
1
+ <?php
2
+
3
+ /**
4
+ * Simple elFinder driver for FTP
5
+ *
6
+ * @author Dmitry (dio) Levashov
7
+ * @author Cem (discofever)
8
+ **/
9
+ class elFinderVolumeFTP extends elFinderVolumeDriver
10
+ {
11
+
12
+ /**
13
+ * Driver id
14
+ * Must be started from letter and contains [a-z0-9]
15
+ * Used as part of volume id
16
+ *
17
+ * @var string
18
+ **/
19
+ protected $driverId = 'f';
20
+
21
+ /**
22
+ * FTP Connection Instance
23
+ *
24
+ * @var resource a FTP stream
25
+ **/
26
+ protected $connect = null;
27
+
28
+ /**
29
+ * Directory for tmp files
30
+ * If not set driver will try to use tmbDir as tmpDir
31
+ *
32
+ * @var string
33
+ **/
34
+ protected $tmpPath = '';
35
+
36
+ /**
37
+ * Last FTP error message
38
+ *
39
+ * @var string
40
+ **/
41
+ protected $ftpError = '';
42
+
43
+ /**
44
+ * FTP server output list as ftp on linux
45
+ *
46
+ * @var bool
47
+ **/
48
+ protected $ftpOsUnix;
49
+
50
+ /**
51
+ * FTP LIST command option
52
+ *
53
+ * @var string
54
+ */
55
+ protected $ftpListOption = '-al';
56
+
57
+
58
+ /**
59
+ * Is connected server Pure FTPd?
60
+ *
61
+ * @var bool
62
+ */
63
+ protected $isPureFtpd = false;
64
+
65
+ /**
66
+ * Is connected server with FTPS?
67
+ *
68
+ * @var bool
69
+ */
70
+ protected $isFTPS = false;
71
+
72
+ /**
73
+ * Tmp folder path
74
+ *
75
+ * @var string
76
+ **/
77
+ protected $tmp = '';
78
+
79
+ /**
80
+ * FTP command `MLST` support
81
+ *
82
+ * @var bool
83
+ */
84
+ private $MLSTsupprt = false;
85
+
86
+ /**
87
+ * Calling cacheDir() target path with non-MLST
88
+ *
89
+ * @var string
90
+ */
91
+ private $cacheDirTarget = '';
92
+
93
+ /**
94
+ * Constructor
95
+ * Extend options with required fields
96
+ *
97
+ * @author Dmitry (dio) Levashov
98
+ * @author Cem (DiscoFever)
99
+ */
100
+ public function __construct()
101
+ {
102
+ $opts = array(
103
+ 'host' => 'localhost',
104
+ 'user' => '',
105
+ 'pass' => '',
106
+ 'port' => 21,
107
+ 'mode' => 'passive',
108
+ 'ssl' => false,
109
+ 'path' => '/',
110
+ 'timeout' => 20,
111
+ 'owner' => true,
112
+ 'tmbPath' => '',
113
+ 'tmpPath' => '',
114
+ 'separator' => '/',
115
+ 'checkSubfolders' => -1,
116
+ 'dirMode' => 0755,
117
+ 'fileMode' => 0644,
118
+ 'rootCssClass' => 'elfinder-navbar-root-ftp',
119
+ 'ftpListOption' => '-al',
120
+ );
121
+ $this->options = array_merge($this->options, $opts);
122
+ $this->options['mimeDetect'] = 'internal';
123
+ }
124
+
125
+ /**
126
+ * Prepare
127
+ * Call from elFinder::netmout() before volume->mount()
128
+ *
129
+ * @param $options
130
+ *
131
+ * @return array volume root options
132
+ * @author Naoki Sawada
133
+ */
134
+ public function netmountPrepare($options)
135
+ {
136
+ if (!empty($_REQUEST['encoding']) && iconv('UTF-8', $_REQUEST['encoding'], '') !== false) {
137
+ $options['encoding'] = $_REQUEST['encoding'];
138
+ if (!empty($_REQUEST['locale']) && setlocale(LC_ALL, $_REQUEST['locale'])) {
139
+ setlocale(LC_ALL, elFinder::$locale);
140
+ $options['locale'] = $_REQUEST['locale'];
141
+ }
142
+ }
143
+ if (!empty($_REQUEST['FTPS'])) {
144
+ $options['ssl'] = true;
145
+ }
146
+ $options['statOwner'] = true;
147
+ $options['allowChmodReadOnly'] = true;
148
+ $options['acceptedName'] = '#^[^/\\?*:|"<>]*[^./\\?*:|"<>]$#';
149
+ return $options;
150
+ }
151
+
152
+ /*********************************************************************/
153
+ /* INIT AND CONFIGURE */
154
+ /*********************************************************************/
155
+
156
+ /**
157
+ * Prepare FTP connection
158
+ * Connect to remote server and check if credentials are correct, if so, store the connection id in $ftp_conn
159
+ *
160
+ * @return bool
161
+ * @author Dmitry (dio) Levashov
162
+ * @author Cem (DiscoFever)
163
+ **/
164
+ protected function init()
165
+ {
166
+ if (!$this->options['host']
167
+ || !$this->options['port']) {
168
+ return $this->setError('Required options undefined.');
169
+ }
170
+
171
+ if (!$this->options['user']) {
172
+ $this->options['user'] = 'anonymous';
173
+ $this->options['pass'] = '';
174
+ }
175
+ if (!$this->options['path']) {
176
+ $this->options['path'] = '/';
177
+ }
178
+
179
+ // make ney mount key
180
+ $this->netMountKey = md5(join('-', array('ftp', $this->options['host'], $this->options['port'], $this->options['path'], $this->options['user'])));
181
+
182
+ if (!function_exists('ftp_connect')) {
183
+ return $this->setError('FTP extension not loaded.');
184
+ }
185
+
186
+ // remove protocol from host
187
+ $scheme = parse_url($this->options['host'], PHP_URL_SCHEME);
188
+
189
+ if ($scheme) {
190
+ $this->options['host'] = substr($this->options['host'], strlen($scheme) + 3);
191
+ }
192
+
193
+ // normalize root path
194
+ $this->root = $this->options['path'] = $this->_normpath($this->options['path']);
195
+
196
+ if (empty($this->options['alias'])) {
197
+ $this->options['alias'] = $this->options['user'] . '@' . $this->options['host'];
198
+ if (!empty($this->options['netkey'])) {
199
+ elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'alias', $this->options['alias']);
200
+ }
201
+ }
202
+
203
+ $this->rootName = $this->options['alias'];
204
+ $this->options['separator'] = '/';
205
+
206
+ if (is_null($this->options['syncChkAsTs'])) {
207
+ $this->options['syncChkAsTs'] = true;
208
+ }
209
+
210
+ if (isset($this->options['ftpListOption'])) {
211
+ $this->ftpListOption = $this->options['ftpListOption'];
212
+ }
213
+
214
+ return $this->needOnline? $this->connect() : true;
215
+
216
+ }
217
+
218
+
219
+ /**
220
+ * Configure after successfull mount.
221
+ *
222
+ * @return void
223
+ * @throws elFinderAbortException
224
+ * @author Dmitry (dio) Levashov
225
+ */
226
+ protected function configure()
227
+ {
228
+ parent::configure();
229
+
230
+ if (!empty($this->options['tmpPath'])) {
231
+ if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'], 0755, true)) && is_writable($this->options['tmpPath'])) {
232
+ $this->tmp = $this->options['tmpPath'];
233
+ }
234
+ }
235
+ if (!$this->tmp && ($tmp = elFinder::getStaticVar('commonTempPath'))) {
236
+ $this->tmp = $tmp;
237
+ }
238
+
239
+ // fallback of $this->tmp
240
+ if (!$this->tmp && $this->tmbPathWritable) {
241
+ $this->tmp = $this->tmbPath;
242
+ }
243
+
244
+ if (!$this->tmp) {
245
+ $this->disabled[] = 'mkfile';
246
+ $this->disabled[] = 'paste';
247
+ $this->disabled[] = 'duplicate';
248
+ $this->disabled[] = 'upload';
249
+ $this->disabled[] = 'edit';
250
+ $this->disabled[] = 'archive';
251
+ $this->disabled[] = 'extract';
252
+ }
253
+
254
+ // echo $this->tmp;
255
+
256
+ }
257
+
258
+ /**
259
+ * Connect to ftp server
260
+ *
261
+ * @return bool
262
+ * @author Dmitry (dio) Levashov
263
+ **/
264
+ protected function connect()
265
+ {
266
+ $withSSL = empty($this->options['ssl']) ? '' : ' with SSL';
267
+ if ($withSSL) {
268
+ if (!function_exists('ftp_ssl_connect') || !($this->connect = ftp_ssl_connect($this->options['host'], $this->options['port'], $this->options['timeout']))) {
269
+ return $this->setError('Unable to connect to FTP server ' . $this->options['host'] . $withSSL);
270
+ }
271
+ $this->isFTPS = true;
272
+ } else {
273
+ if (!($this->connect = ftp_connect($this->options['host'], $this->options['port'], $this->options['timeout']))) {
274
+ return $this->setError('Unable to connect to FTP server ' . $this->options['host']);
275
+ }
276
+ }
277
+ if (!ftp_login($this->connect, $this->options['user'], $this->options['pass'])) {
278
+ $this->umount();
279
+ return $this->setError('Unable to login into ' . $this->options['host'] . $withSSL);
280
+ }
281
+
282
+ // try switch utf8 mode
283
+ if ($this->encoding) {
284
+ ftp_raw($this->connect, 'OPTS UTF8 OFF');
285
+ } else {
286
+ ftp_raw($this->connect, 'OPTS UTF8 ON');
287
+ }
288
+
289
+ $help = ftp_raw($this->connect, 'HELP');
290
+ $this->isPureFtpd = stripos(implode(' ', $help), 'Pure-FTPd') !== false;
291
+
292
+ if (!$this->isPureFtpd) {
293
+ // switch off extended passive mode - may be usefull for some servers
294
+ // this command, for pure-ftpd, doesn't work and takes a timeout in some pure-ftpd versions
295
+ ftp_raw($this->connect, 'epsv4 off');
296
+ }
297
+ // enter passive mode if required
298
+ $pasv = ($this->options['mode'] == 'passive');
299
+ if (!ftp_pasv($this->connect, $pasv)) {
300
+ if ($pasv) {
301
+ $this->options['mode'] = 'active';
302
+ }
303
+ }
304
+
305
+ // enter root folder
306
+ if (!ftp_chdir($this->connect, $this->root)
307
+ || $this->root != ftp_pwd($this->connect)) {
308
+ $this->umount();
309
+ return $this->setError('Unable to open root folder.');
310
+ }
311
+
312
+ // check for MLST support
313
+ $features = ftp_raw($this->connect, 'FEAT');
314
+ if (!is_array($features)) {
315
+ $this->umount();
316
+ return $this->setError('Server does not support command FEAT.');
317
+ }
318
+
319
+ foreach ($features as $feat) {
320
+ if (strpos(trim($feat), 'MLST') === 0) {
321
+ $this->MLSTsupprt = true;
322
+ break;
323
+ }
324
+ }
325
+
326
+ return true;
327
+ }
328
+
329
+ /**
330
+ * Call ftp_rawlist with option prefix
331
+ *
332
+ * @param string $path
333
+ *
334
+ * @return array
335
+ */
336
+ protected function ftpRawList($path)
337
+ {
338
+ if ($this->isPureFtpd) {
339
+ $path = str_replace(' ', '\ ', $path);
340
+ }
341
+ if ($this->ftpListOption) {
342
+ $path = $this->ftpListOption . ' ' . $path;
343
+ }
344
+ $res = ftp_rawlist($this->connect, $path);
345
+ if ($res === false) {
346
+ $res = array();
347
+ }
348
+ return $res;
349
+ }
350
+
351
+ /*********************************************************************/
352
+ /* FS API */
353
+ /*********************************************************************/
354
+
355
+ /**
356
+ * Close opened connection
357
+ *
358
+ * @return void
359
+ * @author Dmitry (dio) Levashov
360
+ **/
361
+ public function umount()
362
+ {
363
+ $this->connect && ftp_close($this->connect);
364
+ }
365
+
366
+
367
+ /**
368
+ * Parse line from ftp_rawlist() output and return file stat (array)
369
+ *
370
+ * @param string $raw line from ftp_rawlist() output
371
+ * @param $base
372
+ * @param bool $nameOnly
373
+ *
374
+ * @return array
375
+ * @author Dmitry Levashov
376
+ */
377
+ protected function parseRaw($raw, $base, $nameOnly = false)
378
+ {
379
+ static $now;
380
+ static $lastyear;
381
+
382
+ if (!$now) {
383
+ $now = time();
384
+ $lastyear = date('Y') - 1;
385
+ }
386
+
387
+ $info = preg_split("/\s+/", $raw, 8);
388
+ if (isset($info[7])) {
389
+ list($info[7], $info[8]) = explode(' ', $info[7], 2);
390
+ }
391
+ $stat = array();
392
+
393
+ if (!isset($this->ftpOsUnix)) {
394
+ $this->ftpOsUnix = !preg_match('/\d/', substr($info[0], 0, 1));
395
+ }
396
+ if (!$this->ftpOsUnix) {
397
+ $info = $this->normalizeRawWindows($raw);
398
+ }
399
+
400
+ if (count($info) < 9 || $info[8] == '.' || $info[8] == '..') {
401
+ return false;
402
+ }
403
+
404
+ $name = $info[8];
405
+
406
+ if (preg_match('|(.+)\-\>(.+)|', $name, $m)) {
407
+ $name = trim($m[1]);
408
+ // check recursive processing
409
+ if ($this->cacheDirTarget && $this->_joinPath($base, $name) !== $this->cacheDirTarget) {
410
+ return array();
411
+ }
412
+ if (!$nameOnly) {
413
+ $target = trim($m[2]);
414
+ if (substr($target, 0, 1) !== $this->separator) {
415
+ $target = $this->getFullPath($target, $base);
416
+ }
417
+ $target = $this->_normpath($target);
418
+ $stat['name'] = $name;
419
+ $stat['target'] = $target;
420
+ return $stat;
421
+ }
422
+ }
423
+
424
+ if ($nameOnly) {
425
+ return array('name' => $name);
426
+ }
427
+
428
+ if (is_numeric($info[5]) && !$info[6] && !$info[7]) {
429
+ // by normalizeRawWindows()
430
+ $stat['ts'] = $info[5];
431
+ } else {
432
+ $stat['ts'] = strtotime($info[5] . ' ' . $info[6] . ' ' . $info[7]);
433
+ if ($stat['ts'] && $stat['ts'] > $now && strpos($info[7], ':') !== false) {
434
+ $stat['ts'] = strtotime($info[5] . ' ' . $info[6] . ' ' . $lastyear . ' ' . $info[7]);
435
+ }
436
+ if (empty($stat['ts'])) {
437
+ $stat['ts'] = strtotime($info[6] . ' ' . $info[5] . ' ' . $info[7]);
438
+ if ($stat['ts'] && $stat['ts'] > $now && strpos($info[7], ':') !== false) {
439
+ $stat['ts'] = strtotime($info[6] . ' ' . $info[5] . ' ' . $lastyear . ' ' . $info[7]);
440
+ }
441
+ }
442
+ }
443
+
444
+ if ($this->options['statOwner']) {
445
+ $stat['owner'] = $info[2];
446
+ $stat['group'] = $info[3];
447
+ $stat['perm'] = substr($info[0], 1);
448
+ //
449
+ // if not exists owner in LS ftp ==> isowner = true
450
+ // if is defined as option : 'owner' => true isowner = true
451
+ //
452
+ // if exist owner in LS ftp and 'owner' => False isowner = result of owner(file) == user(logged with ftp)
453
+ //
454
+ $stat['isowner'] = isset($stat['owner']) ? ($this->options['owner'] ? true : ($stat['owner'] == $this->options['user'])) : true;
455
+ }
456
+
457
+ $owner_computed = isset($stat['isowner']) ? $stat['isowner'] : $this->options['owner'];
458
+ $perm = $this->parsePermissions($info[0], $owner_computed);
459
+ $stat['name'] = $name;
460
+ $stat['mime'] = substr(strtolower($info[0]), 0, 1) == 'd' ? 'directory' : $this->mimetype($stat['name'], true);
461
+ $stat['size'] = $stat['mime'] == 'directory' ? 0 : $info[4];
462
+ $stat['read'] = $perm['read'];
463
+ $stat['write'] = $perm['write'];
464
+
465
+ return $stat;
466
+ }
467
+
468
+ /**
469
+ * Normalize MS-DOS style FTP LIST Raw line
470
+ *
471
+ * @param string $raw line from FTP LIST (MS-DOS style)
472
+ *
473
+ * @return array
474
+ * @author Naoki Sawada
475
+ **/
476
+ protected function normalizeRawWindows($raw)
477
+ {
478
+ $info = array_pad(array(), 9, '');
479
+ $item = preg_replace('#\s+#', ' ', trim($raw), 3);
480
+ list($date, $time, $size, $name) = explode(' ', $item, 4);
481
+ $format = strlen($date) === 8 ? 'm-d-yH:iA' : 'Y-m-dH:i';
482
+ $dateObj = DateTime::createFromFormat($format, $date . $time);
483
+ $info[5] = strtotime($dateObj->format('Y-m-d H:i'));
484
+ $info[8] = $name;
485
+ if ($size === '<DIR>') {
486
+ $info[4] = 0;
487
+ $info[0] = 'drwxr-xr-x';
488
+ } else {
489
+ $info[4] = (int)$size;
490
+ $info[0] = '-rw-r--r--';
491
+ }
492
+ return $info;
493
+ }
494
+
495
+ /**
496
+ * Parse permissions string. Return array(read => true/false, write => true/false)
497
+ *
498
+ * @param string $perm permissions string 'rwx' + 'rwx' + 'rwx'
499
+ * ^ ^ ^
500
+ * | | +-> others
501
+ * | +---------> group
502
+ * +-----------------> owner
503
+ * The isowner parameter is computed by the caller.
504
+ * If the owner parameter in the options is true, the user is the actual owner of all objects even if che user used in the ftp Login
505
+ * is different from the file owner id.
506
+ * If the owner parameter is false to understand if the user is the file owner we compare the ftp user with the file owner id.
507
+ * @param Boolean $isowner . Tell if the current user is the owner of the object.
508
+ *
509
+ * @return array
510
+ * @author Dmitry (dio) Levashov
511
+ * @author Ugo Vierucci
512
+ */
513
+ protected function parsePermissions($perm, $isowner = true)
514
+ {
515
+ $res = array();
516
+ $parts = array();
517
+ for ($i = 0, $l = strlen($perm); $i < $l; $i++) {
518
+ $parts[] = substr($perm, $i, 1);
519
+ }
520
+
521
+ $read = ($isowner && $parts[1] == 'r') || $parts[4] == 'r' || $parts[7] == 'r';
522
+
523
+ return array(
524
+ 'read' => $parts[0] == 'd' ? $read && (($isowner && $parts[3] == 'x') || $parts[6] == 'x' || $parts[9] == 'x') : $read,
525
+ 'write' => ($isowner && $parts[2] == 'w') || $parts[5] == 'w' || $parts[8] == 'w'
526
+ );
527
+ }
528
+
529
+ /**
530
+ * Cache dir contents
531
+ *
532
+ * @param string $path dir path
533
+ *
534
+ * @return void
535
+ * @author Dmitry Levashov
536
+ **/
537
+ protected function cacheDir($path)
538
+ {
539
+ $this->dirsCache[$path] = array();
540
+ $hasDir = false;
541
+
542
+ $list = array();
543
+ $encPath = $this->convEncIn($path);
544
+ foreach ($this->ftpRawList($encPath) as $raw) {
545
+ if (($stat = $this->parseRaw($raw, $encPath))) {
546
+ $list[] = $stat;
547
+ }
548
+ }
549
+ $list = $this->convEncOut($list);
550
+ $prefix = ($path === $this->separator) ? $this->separator : $path . $this->separator;
551
+ $targets = array();
552
+ foreach ($list as $stat) {
553
+ $p = $prefix . $stat['name'];
554
+ if (isset($stat['target'])) {
555
+ // stat later
556
+ $targets[$stat['name']] = $stat['target'];
557
+ } else {
558
+ $stat = $this->updateCache($p, $stat);
559
+ if (empty($stat['hidden'])) {
560
+ if (!$hasDir && $stat['mime'] === 'directory') {
561
+ $hasDir = true;
562
+ }
563
+ $this->dirsCache[$path][] = $p;
564
+ }
565
+ }
566
+ }
567
+ // stat link targets
568
+ foreach ($targets as $name => $target) {
569
+ $stat = array();
570
+ $stat['name'] = $name;
571
+ $p = $prefix . $name;
572
+ $cacheDirTarget = $this->cacheDirTarget;
573
+ $this->cacheDirTarget = $this->convEncIn($target, true);
574
+ if ($tstat = $this->stat($target)) {
575
+ $stat['size'] = $tstat['size'];
576
+ $stat['alias'] = $target;
577
+ $stat['thash'] = $tstat['hash'];
578
+ $stat['mime'] = $tstat['mime'];
579
+ $stat['read'] = $tstat['read'];
580
+ $stat['write'] = $tstat['write'];
581
+
582
+ if (isset($tstat['ts'])) {
583
+ $stat['ts'] = $tstat['ts'];
584
+ }
585
+ if (isset($tstat['owner'])) {
586
+ $stat['owner'] = $tstat['owner'];
587
+ }
588
+ if (isset($tstat['group'])) {
589
+ $stat['group'] = $tstat['group'];
590
+ }
591
+ if (isset($tstat['perm'])) {
592
+ $stat['perm'] = $tstat['perm'];
593
+ }
594
+ if (isset($tstat['isowner'])) {
595
+ $stat['isowner'] = $tstat['isowner'];
596
+ }
597
+ } else {
598
+
599
+ $stat['mime'] = 'symlink-broken';
600
+ $stat['read'] = false;
601
+ $stat['write'] = false;
602
+ $stat['size'] = 0;
603
+
604
+ }
605
+ $this->cacheDirTarget = $cacheDirTarget;
606
+ $stat = $this->updateCache($p, $stat);
607
+ if (empty($stat['hidden'])) {
608
+ if (!$hasDir && $stat['mime'] === 'directory') {
609
+ $hasDir = true;
610
+ }
611
+ $this->dirsCache[$path][] = $p;
612
+ }
613
+ }
614
+
615
+ if (isset($this->sessionCache['subdirs'])) {
616
+ $this->sessionCache['subdirs'][$path] = $hasDir;
617
+ }
618
+ }
619
+
620
+ /**
621
+ * Return ftp transfer mode for file
622
+ *
623
+ * @param string $path file path
624
+ *
625
+ * @return string
626
+ * @author Dmitry (dio) Levashov
627
+ **/
628
+ protected function ftpMode($path)
629
+ {
630
+ return strpos($this->mimetype($path), 'text/') === 0 ? FTP_ASCII : FTP_BINARY;
631
+ }
632
+
633
+ /*********************** paths/urls *************************/
634
+
635
+ /**
636
+ * Return parent directory path
637
+ *
638
+ * @param string $path file path
639
+ *
640
+ * @return string
641
+ * @author Naoki Sawada
642
+ **/
643
+ protected function _dirname($path)
644
+ {
645
+ $parts = explode($this->separator, trim($path, $this->separator));
646
+ array_pop($parts);
647
+ return $this->separator . join($this->separator, $parts);
648
+ }
649
+
650
+ /**
651
+ * Return file name
652
+ *
653
+ * @param string $path file path
654
+ *
655
+ * @return string
656
+ * @author Naoki Sawada
657
+ **/
658
+ protected function _basename($path)
659
+ {
660
+ $parts = explode($this->separator, trim($path, $this->separator));
661
+ return array_pop($parts);
662
+ }
663
+
664
+ /**
665
+ * Join dir name and file name and retur full path
666
+ *
667
+ * @param string $dir
668
+ * @param string $name
669
+ *
670
+ * @return string
671
+ * @author Dmitry (dio) Levashov
672
+ **/
673
+ protected function _joinPath($dir, $name)
674
+ {
675
+ return rtrim($dir, $this->separator) . $this->separator . $name;
676
+ }
677
+
678
+ /**
679
+ * Return normalized path, this works the same as os.path.normpath() in Python
680
+ *
681
+ * @param string $path path
682
+ *
683
+ * @return string
684
+ * @author Troex Nevelin
685
+ **/
686
+ protected function _normpath($path)
687
+ {
688
+ if (empty($path)) {
689
+ $path = '.';
690
+ }
691
+ // path must be start with /
692
+ $path = preg_replace('|^\.\/?|', $this->separator, $path);
693
+ $path = preg_replace('/^([^\/])/', "/$1", $path);
694
+
695
+ if ($path[0] === $this->separator) {
696
+ $initial_slashes = true;
697
+ } else {
698
+ $initial_slashes = false;
699
+ }
700
+
701
+ if (($initial_slashes)
702
+ && (strpos($path, '//') === 0)
703
+ && (strpos($path, '///') === false)) {
704
+ $initial_slashes = 2;
705
+ }
706
+
707
+ $initial_slashes = (int)$initial_slashes;
708
+
709
+ $comps = explode($this->separator, $path);
710
+ $new_comps = array();
711
+ foreach ($comps as $comp) {
712
+ if (in_array($comp, array('', '.'))) {
713
+ continue;
714
+ }
715
+
716
+ if (($comp != '..')
717
+ || (!$initial_slashes && !$new_comps)
718
+ || ($new_comps && (end($new_comps) == '..'))) {
719
+ array_push($new_comps, $comp);
720
+ } elseif ($new_comps) {
721
+ array_pop($new_comps);
722
+ }
723
+ }
724
+ $comps = $new_comps;
725
+ $path = implode($this->separator, $comps);
726
+ if ($initial_slashes) {
727
+ $path = str_repeat($this->separator, $initial_slashes) . $path;
728
+ }
729
+
730
+ return $path ? $path : '.';
731
+ }
732
+
733
+ /**
734
+ * Return file path related to root dir
735
+ *
736
+ * @param string $path file path
737
+ *
738
+ * @return string
739
+ * @author Dmitry (dio) Levashov
740
+ **/
741
+ protected function _relpath($path)
742
+ {
743
+ if ($path === $this->root) {
744
+ return '';
745
+ } else {
746
+ if (strpos($path, $this->root) === 0) {
747
+ return ltrim(substr($path, strlen($this->root)), $this->separator);
748
+ } else {
749
+ // for link
750
+ return $path;
751
+ }
752
+ }
753
+ }
754
+
755
+ /**
756
+ * Convert path related to root dir into real path
757
+ *
758
+ * @param string $path file path
759
+ *
760
+ * @return string
761
+ * @author Dmitry (dio) Levashov
762
+ **/
763
+ protected function _abspath($path)
764
+ {
765
+ if ($path === $this->separator) {
766
+ return $this->root;
767
+ } else {
768
+ if ($path[0] === $this->separator) {
769
+ // for link
770
+ return $path;
771
+ } else {
772
+ return $this->_joinPath($this->root, $path);
773
+ }
774
+ }
775
+ }
776
+
777
+ /**
778
+ * Return fake path started from root dir
779
+ *
780
+ * @param string $path file path
781
+ *
782
+ * @return string
783
+ * @author Dmitry (dio) Levashov
784
+ **/
785
+ protected function _path($path)
786
+ {
787
+ return $this->rootName . ($path == $this->root ? '' : $this->separator . $this->_relpath($path));
788
+ }
789
+
790
+ /**
791
+ * Return true if $path is children of $parent
792
+ *
793
+ * @param string $path path to check
794
+ * @param string $parent parent path
795
+ *
796
+ * @return bool
797
+ * @author Dmitry (dio) Levashov
798
+ **/
799
+ protected function _inpath($path, $parent)
800
+ {
801
+ return $path == $parent || strpos($path, rtrim($parent, $this->separator) . $this->separator) === 0;
802
+ }
803
+
804
+ /***************** file stat ********************/
805
+ /**
806
+ * Return stat for given path.
807
+ * Stat contains following fields:
808
+ * - (int) size file size in b. required
809
+ * - (int) ts file modification time in unix time. required
810
+ * - (string) mime mimetype. required for folders, others - optionally
811
+ * - (bool) read read permissions. required
812
+ * - (bool) write write permissions. required
813
+ * - (bool) locked is object locked. optionally
814
+ * - (bool) hidden is object hidden. optionally
815
+ * - (string) alias for symlinks - link target path relative to root path. optionally
816
+ * - (string) target for symlinks - link target path. optionally
817
+ * If file does not exists - returns empty array or false.
818
+ *
819
+ * @param string $path file path
820
+ *
821
+ * @return array|false
822
+ * @author Dmitry (dio) Levashov
823
+ **/
824
+ protected function _stat($path)
825
+ {
826
+ $outPath = $this->convEncOut($path);
827
+ if (isset($this->cache[$outPath])) {
828
+ return $this->convEncIn($this->cache[$outPath]);
829
+ } else {
830
+ $this->convEncIn();
831
+ }
832
+ if (!$this->MLSTsupprt) {
833
+ if ($path === $this->root) {
834
+ $res = array(
835
+ 'name' => $this->root,
836
+ 'mime' => 'directory',
837
+ 'dirs' => -1
838
+ );
839
+ if ($this->needOnline && (($this->ARGS['cmd'] === 'open' && $this->ARGS['target'] === $this->encode($this->root)) || $this->isMyReload())) {
840
+ $check = array(
841
+ 'ts' => true,
842
+ 'dirs' => true,
843
+ );
844
+ $ts = 0;
845
+ foreach ($this->ftpRawList($path) as $str) {
846
+ $info = preg_split('/\s+/', $str, 9);
847
+ if ($info[8] === '.') {
848
+ $info[8] = 'root';
849
+ if ($stat = $this->parseRaw(join(' ', $info), $path)) {
850
+ unset($stat['name']);
851
+ $res = array_merge($res, $stat);
852
+ if ($res['ts']) {
853
+ $ts = 0;
854
+ unset($check['ts']);
855
+ }
856
+ }
857
+ }
858
+ if ($check && ($stat = $this->parseRaw($str, $path))) {
859
+ if (isset($stat['ts']) && !empty($stat['ts'])) {
860
+ $ts = max($ts, $stat['ts']);
861
+ }
862
+ if (isset($stat['dirs']) && $stat['mime'] === 'directory') {
863
+ $res['dirs'] = 1;
864
+ unset($stat['dirs']);
865
+ }
866
+ if (!$check) {
867
+ break;
868
+ }
869
+ }
870
+ }
871
+ if ($ts) {
872
+ $res['ts'] = $ts;
873
+ }
874
+ $this->cache[$outPath] = $res;
875
+ }
876
+ return $res;
877
+ }
878
+
879
+ $pPath = $this->_dirname($path);
880
+ if ($this->_inPath($pPath, $this->root)) {
881
+ $outPPpath = $this->convEncOut($pPath);
882
+ if (!isset($this->dirsCache[$outPPpath])) {
883
+ $parentSubdirs = null;
884
+ if (isset($this->sessionCache['subdirs']) && isset($this->sessionCache['subdirs'][$outPPpath])) {
885
+ $parentSubdirs = $this->sessionCache['subdirs'][$outPPpath];
886
+ }
887
+ $this->cacheDir($outPPpath);
888
+ if ($parentSubdirs) {
889
+ $this->sessionCache['subdirs'][$outPPpath] = $parentSubdirs;
890
+ }
891
+ }
892
+ }
893
+
894
+ $stat = $this->convEncIn(isset($this->cache[$outPath]) ? $this->cache[$outPath] : array());
895
+ if (!$this->mounted) {
896
+ // dispose incomplete cache made by calling `stat` by 'startPath' option
897
+ $this->cache = array();
898
+ }
899
+ return $stat;
900
+ }
901
+ $raw = ftp_raw($this->connect, 'MLST ' . $path);
902
+ if (is_array($raw) && count($raw) > 1 && substr(trim($raw[0]), 0, 1) == 2) {
903
+ $parts = explode(';', trim($raw[1]));
904
+ array_pop($parts);
905
+ $parts = array_map('strtolower', $parts);
906
+ $stat = array();
907
+ $mode = '';
908
+ foreach ($parts as $part) {
909
+
910
+ list($key, $val) = explode('=', $part, 2);
911
+
912
+ switch ($key) {
913
+ case 'type':
914
+ if (strpos($val, 'dir') !== false) {
915
+ $stat['mime'] = 'directory';
916
+ } else if (strpos($val, 'link') !== false) {
917
+ $stat['mime'] = 'symlink';
918
+ break(2);
919
+ } else {
920
+ $stat['mime'] = $this->mimetype($path);
921
+ }
922
+ break;
923
+
924
+ case 'size':
925
+ $stat['size'] = $val;
926
+ break;
927
+
928
+ case 'modify':
929
+ $ts = mktime(intval(substr($val, 8, 2)), intval(substr($val, 10, 2)), intval(substr($val, 12, 2)), intval(substr($val, 4, 2)), intval(substr($val, 6, 2)), substr($val, 0, 4));
930
+ $stat['ts'] = $ts;
931
+ break;
932
+
933
+ case 'unix.mode':
934
+ $mode = strval($val);
935
+ break;
936
+
937
+ case 'unix.uid':
938
+ $stat['owner'] = $val;
939
+ break;
940
+
941
+ case 'unix.gid':
942
+ $stat['group'] = $val;
943
+ break;
944
+
945
+ case 'perm':
946
+ $val = strtolower($val);
947
+ $stat['read'] = (int)preg_match('/e|l|r/', $val);
948
+ $stat['write'] = (int)preg_match('/w|m|c/', $val);
949
+ if (!preg_match('/f|d/', $val)) {
950
+ $stat['locked'] = 1;
951
+ }
952
+ break;
953
+ }
954
+ }
955
+
956
+ if (empty($stat['mime'])) {
957
+ return array();
958
+ }
959
+
960
+ // do not use MLST to get stat of symlink
961
+ if ($stat['mime'] === 'symlink') {
962
+ $this->MLSTsupprt = false;
963
+ $res = $this->_stat($path);
964
+ $this->MLSTsupprt = true;
965
+ return $res;
966
+ }
967
+
968
+ if ($stat['mime'] === 'directory') {
969
+ $stat['size'] = 0;
970
+ }
971
+
972
+ if ($mode) {
973
+ $stat['perm'] = '';
974
+ if ($mode[0] === '0') {
975
+ $mode = substr($mode, 1);
976
+ }
977
+
978
+ $perm = array();
979
+ for ($i = 0; $i <= 2; $i++) {
980
+ $perm[$i] = array(false, false, false);
981
+ $n = isset($mode[$i]) ? $mode[$i] : 0;
982
+
983
+ if ($n - 4 >= 0) {
984
+ $perm[$i][0] = true;
985
+ $n = $n - 4;
986
+ $stat['perm'] .= 'r';
987
+ } else {
988
+ $stat['perm'] .= '-';
989
+ }
990
+
991
+ if ($n - 2 >= 0) {
992
+ $perm[$i][1] = true;
993
+ $n = $n - 2;
994
+ $stat['perm'] .= 'w';
995
+ } else {
996
+ $stat['perm'] .= '-';
997
+ }
998
+
999
+ if ($n - 1 == 0) {
1000
+ $perm[$i][2] = true;
1001
+ $stat['perm'] .= 'x';
1002
+ } else {
1003
+ $stat['perm'] .= '-';
1004
+ }
1005
+ }
1006
+
1007
+ $stat['perm'] = trim($stat['perm']);
1008
+ //
1009
+ // if not exists owner in LS ftp ==> isowner = true
1010
+ // if is defined as option : 'owner' => true isowner = true
1011
+ //
1012
+ // if exist owner in LS ftp and 'owner' => False isowner = result of owner(file) == user(logged with ftp)
1013
+
1014
+ $owner_computed = isset($stat['owner']) ? ($this->options['owner'] ? true : ($stat['owner'] == $this->options['user'])) : true;
1015
+
1016
+ $read = ($owner_computed && $perm[0][0]) || $perm[1][0] || $perm[2][0];
1017
+
1018
+ $stat['read'] = $stat['mime'] == 'directory' ? $read && (($owner_computed && $perm[0][2]) || $perm[1][2] || $perm[2][2]) : $read;
1019
+ $stat['write'] = ($owner_computed && $perm[0][1]) || $perm[1][1] || $perm[2][1];
1020
+
1021
+ if ($this->options['statOwner']) {
1022
+ $stat['isowner'] = $owner_computed;
1023
+ } else {
1024
+ unset($stat['owner'], $stat['group'], $stat['perm']);
1025
+ }
1026
+ }
1027
+
1028
+ return $stat;
1029
+
1030
+ }
1031
+
1032
+ return array();
1033
+ }
1034
+
1035
+ /**
1036
+ * Return true if path is dir and has at least one childs directory
1037
+ *
1038
+ * @param string $path dir path
1039
+ *
1040
+ * @return bool
1041
+ * @author Dmitry (dio) Levashov
1042
+ **/
1043
+ protected function _subdirs($path)
1044
+ {
1045
+
1046
+ foreach ($this->ftpRawList($path) as $str) {
1047
+ $info = preg_split('/\s+/', $str, 9);
1048
+ if (!isset($this->ftpOsUnix)) {
1049
+ $this->ftpOsUnix = !preg_match('/\d/', substr($info[0], 0, 1));
1050
+ }
1051
+ if (!$this->ftpOsUnix) {
1052
+ $info = $this->normalizeRawWindows($str);
1053
+ }
1054
+ $name = isset($info[8]) ? trim($info[8]) : '';
1055
+ if ($name && $name !== '.' && $name !== '..' && substr(strtolower($info[0]), 0, 1) === 'd') {
1056
+ return true;
1057
+ }
1058
+ }
1059
+ return false;
1060
+ }
1061
+
1062
+ /**
1063
+ * Return object width and height
1064
+ * Ususaly used for images, but can be realize for video etc...
1065
+ *
1066
+ * @param string $path file path
1067
+ * @param string $mime file mime type
1068
+ *
1069
+ * @return string|false
1070
+ * @throws ImagickException
1071
+ * @throws elFinderAbortException
1072
+ * @author Dmitry (dio) Levashov
1073
+ */
1074
+ protected function _dimensions($path, $mime)
1075
+ {
1076
+ $ret = false;
1077
+ if ($imgsize = $this->getImageSize($path, $mime)) {
1078
+ $ret = array('dim' => $imgsize['dimensions']);
1079
+ if (!empty($imgsize['url'])) {
1080
+ $ret['url'] = $imgsize['url'];
1081
+ }
1082
+ }
1083
+ return $ret;
1084
+ }
1085
+
1086
+ /******************** file/dir content *********************/
1087
+
1088
+ /**
1089
+ * Return files list in directory.
1090
+ *
1091
+ * @param string $path dir path
1092
+ *
1093
+ * @return array
1094
+ * @author Dmitry (dio) Levashov
1095
+ * @author Cem (DiscoFever)
1096
+ **/
1097
+ protected function _scandir($path)
1098
+ {
1099
+ $files = array();
1100
+
1101
+ foreach ($this->ftpRawList($path) as $str) {
1102
+ if (($stat = $this->parseRaw($str, $path, true))) {
1103
+ $files[] = $this->_joinPath($path, $stat['name']);
1104
+ }
1105
+ }
1106
+
1107
+ return $files;
1108
+ }
1109
+
1110
+ /**
1111
+ * Open file and return file pointer
1112
+ *
1113
+ * @param string $path file path
1114
+ * @param string $mode
1115
+ *
1116
+ * @return false|resource
1117
+ * @throws elFinderAbortException
1118
+ * @internal param bool $write open file for writing
1119
+ * @author Dmitry (dio) Levashov
1120
+ */
1121
+ protected function _fopen($path, $mode = 'rb')
1122
+ {
1123
+ // try ftp stream wrapper
1124
+ if ($this->options['mode'] === 'passive' && ini_get('allow_url_fopen')) {
1125
+ $url = ($this->isFTPS ? 'ftps' : 'ftp') . '://' . $this->options['user'] . ':' . $this->options['pass'] . '@' . $this->options['host'] . ':' . $this->options['port'] . $path;
1126
+ if (strtolower($mode[0]) === 'w') {
1127
+ $context = stream_context_create(array('ftp' => array('overwrite' => true)));
1128
+ $fp = fopen($url, $mode, false, $context);
1129
+ } else {
1130
+ $fp = fopen($url, $mode);
1131
+ }
1132
+ if ($fp) {
1133
+ return $fp;
1134
+ }
1135
+ }
1136
+
1137
+ if ($this->tmp) {
1138
+ $local = $this->getTempFile($path);
1139
+ $fp = fopen($local, 'wb');
1140
+ $ret = ftp_nb_fget($this->connect, $fp, $path, FTP_BINARY);
1141
+ while ($ret === FTP_MOREDATA) {
1142
+ elFinder::extendTimeLimit();
1143
+ $ret = ftp_nb_continue($this->connect);
1144
+ }
1145
+ if ($ret === FTP_FINISHED) {
1146
+ fclose($fp);
1147
+ $fp = fopen($local, $mode);
1148
+ return $fp;
1149
+ }
1150
+ fclose($fp);
1151
+ is_file($local) && unlink($local);
1152
+ }
1153
+
1154
+ return false;
1155
+ }
1156
+
1157
+ /**
1158
+ * Close opened file
1159
+ *
1160
+ * @param resource $fp file pointer
1161
+ * @param string $path
1162
+ *
1163
+ * @return void
1164
+ * @author Dmitry (dio) Levashov
1165
+ */
1166
+ protected function _fclose($fp, $path = '')
1167
+ {
1168
+ is_resource($fp) && fclose($fp);
1169
+ if ($path) {
1170
+ unlink($this->getTempFile($path));
1171
+ }
1172
+ }
1173
+
1174
+ /******************** file/dir manipulations *************************/
1175
+
1176
+ /**
1177
+ * Create dir and return created dir path or false on failed
1178
+ *
1179
+ * @param string $path parent dir path
1180
+ * @param string $name new directory name
1181
+ *
1182
+ * @return string|bool
1183
+ * @author Dmitry (dio) Levashov
1184
+ **/
1185
+ protected function _mkdir($path, $name)
1186
+ {
1187
+ $path = $this->_joinPath($path, $name);
1188
+ if (ftp_mkdir($this->connect, $path) === false) {
1189
+ return false;
1190
+ }
1191
+
1192
+ $this->options['dirMode'] && ftp_chmod($this->connect, $this->options['dirMode'], $path);
1193
+ return $path;
1194
+ }
1195
+
1196
+ /**
1197
+ * Create file and return it's path or false on failed
1198
+ *
1199
+ * @param string $path parent dir path
1200
+ * @param string $name new file name
1201
+ *
1202
+ * @return string|bool
1203
+ * @author Dmitry (dio) Levashov
1204
+ **/
1205
+ protected function _mkfile($path, $name)
1206
+ {
1207
+ if ($this->tmp) {
1208
+ $path = $this->_joinPath($path, $name);
1209
+ $local = $this->getTempFile();
1210
+ $res = touch($local) && ftp_put($this->connect, $path, $local, FTP_ASCII);
1211
+ unlink($local);
1212
+ return $res ? $path : false;
1213
+ }
1214
+ return false;
1215
+ }
1216
+
1217
+ /**
1218
+ * Create symlink. FTP driver does not support symlinks.
1219
+ *
1220
+ * @param string $target link target
1221
+ * @param string $path symlink path
1222
+ * @param string $name
1223
+ *
1224
+ * @return bool
1225
+ * @author Dmitry (dio) Levashov
1226
+ */
1227
+ protected function _symlink($target, $path, $name)
1228
+ {
1229
+ return false;
1230
+ }
1231
+
1232
+ /**
1233
+ * Copy file into another file
1234
+ *
1235
+ * @param string $source source file path
1236
+ * @param string $targetDir target directory path
1237
+ * @param string $name new file name
1238
+ *
1239
+ * @return bool
1240
+ * @author Dmitry (dio) Levashov
1241
+ **/
1242
+ protected function _copy($source, $targetDir, $name)
1243
+ {
1244
+ $res = false;
1245
+
1246
+ if ($this->tmp) {
1247
+ $local = $this->getTempFile();
1248
+ $target = $this->_joinPath($targetDir, $name);
1249
+
1250
+ if (ftp_get($this->connect, $local, $source, FTP_BINARY)
1251
+ && ftp_put($this->connect, $target, $local, $this->ftpMode($target))) {
1252
+ $res = $target;
1253
+ }
1254
+ unlink($local);
1255
+ }
1256
+
1257
+ return $res;
1258
+ }
1259
+
1260
+ /**
1261
+ * Move file into another parent dir.
1262
+ * Return new file path or false.
1263
+ *
1264
+ * @param string $source source file path
1265
+ * @param $targetDir
1266
+ * @param string $name file name
1267
+ *
1268
+ * @return bool|string
1269
+ * @internal param string $target target dir path
1270
+ * @author Dmitry (dio) Levashov
1271
+ */
1272
+ protected function _move($source, $targetDir, $name)
1273
+ {
1274
+ $target = $this->_joinPath($targetDir, $name);
1275
+ return ftp_rename($this->connect, $source, $target) ? $target : false;
1276
+ }
1277
+
1278
+ /**
1279
+ * Remove file
1280
+ *
1281
+ * @param string $path file path
1282
+ *
1283
+ * @return bool
1284
+ * @author Dmitry (dio) Levashov
1285
+ **/
1286
+ protected function _unlink($path)
1287
+ {
1288
+ return ftp_delete($this->connect, $path);
1289
+ }
1290
+
1291
+ /**
1292
+ * Remove dir
1293
+ *
1294
+ * @param string $path dir path
1295
+ *
1296
+ * @return bool
1297
+ * @author Dmitry (dio) Levashov
1298
+ **/
1299
+ protected function _rmdir($path)
1300
+ {
1301
+ return ftp_rmdir($this->connect, $path);
1302
+ }
1303
+
1304
+ /**
1305
+ * Create new file and write into it from file pointer.
1306
+ * Return new file path or false on error.
1307
+ *
1308
+ * @param resource $fp file pointer
1309
+ * @param string $dir target dir path
1310
+ * @param string $name file name
1311
+ * @param array $stat file stat (required by some virtual fs)
1312
+ *
1313
+ * @return bool|string
1314
+ * @author Dmitry (dio) Levashov
1315
+ **/
1316
+ protected function _save($fp, $dir, $name, $stat)
1317
+ {
1318
+ $path = $this->_joinPath($dir, $name);
1319
+ return ftp_fput($this->connect, $path, $fp, $this->ftpMode($path))
1320
+ ? $path
1321
+ : false;
1322
+ }
1323
+
1324
+ /**
1325
+ * Get file contents
1326
+ *
1327
+ * @param string $path file path
1328
+ *
1329
+ * @return string|false
1330
+ * @throws elFinderAbortException
1331
+ * @author Dmitry (dio) Levashov
1332
+ */
1333
+ protected function _getContents($path)
1334
+ {
1335
+ $contents = '';
1336
+ if (($fp = $this->_fopen($path))) {
1337
+ while (!feof($fp)) {
1338
+ $contents .= fread($fp, 8192);
1339
+ }
1340
+ $this->_fclose($fp, $path);
1341
+ return $contents;
1342
+ }
1343
+ return false;
1344
+ }
1345
+
1346
+ /**
1347
+ * Write a string to a file
1348
+ *
1349
+ * @param string $path file path
1350
+ * @param string $content new file content
1351
+ *
1352
+ * @return bool
1353
+ * @author Dmitry (dio) Levashov
1354
+ **/
1355
+ protected function _filePutContents($path, $content)
1356
+ {
1357
+ $res = false;
1358
+
1359
+ if ($this->tmp) {
1360
+ $local = $this->getTempFile();
1361
+
1362
+ if (file_put_contents($local, $content, LOCK_EX) !== false
1363
+ && ($fp = fopen($local, 'rb'))) {
1364
+ $file = $this->stat($this->convEncOut($path, false));
1365
+ if (!empty($file['thash'])) {
1366
+ $path = $this->decode($file['thash']);
1367
+ }
1368
+ clearstatcache();
1369
+ $res = ftp_fput($this->connect, $path, $fp, $this->ftpMode($path));
1370
+ fclose($fp);
1371
+ }
1372
+ file_exists($local) && unlink($local);
1373
+ }
1374
+
1375
+ return $res;
1376
+ }
1377
+
1378
+ /**
1379
+ * Detect available archivers
1380
+ *
1381
+ * @return void
1382
+ * @throws elFinderAbortException
1383
+ */
1384
+ protected function _checkArchivers()
1385
+ {
1386
+ $this->archivers = $this->getArchivers();
1387
+ return;
1388
+ }
1389
+
1390
+ /**
1391
+ * chmod availability
1392
+ *
1393
+ * @param string $path
1394
+ * @param string $mode
1395
+ *
1396
+ * @return bool
1397
+ */
1398
+ protected function _chmod($path, $mode)
1399
+ {
1400
+ $modeOct = is_string($mode) ? octdec($mode) : octdec(sprintf("%04o", $mode));
1401
+ return ftp_chmod($this->connect, $modeOct, $path);
1402
+ }
1403
+
1404
+ /**
1405
+ * Extract files from archive
1406
+ *
1407
+ * @param string $path archive path
1408
+ * @param array $arc archiver command and arguments (same as in $this->archivers)
1409
+ *
1410
+ * @return true
1411
+ * @throws elFinderAbortException
1412
+ * @author Dmitry (dio) Levashov,
1413
+ * @author Alexey Sukhotin
1414
+ */
1415
+ protected function _extract($path, $arc)
1416
+ {
1417
+ $dir = $this->tempDir();
1418
+ if (!$dir) {
1419
+ return false;
1420
+ }
1421
+
1422
+ $basename = $this->_basename($path);
1423
+ $localPath = $dir . DIRECTORY_SEPARATOR . $basename;
1424
+
1425
+ if (!ftp_get($this->connect, $localPath, $path, FTP_BINARY)) {
1426
+ //cleanup
1427
+ $this->rmdirRecursive($dir);
1428
+ return false;
1429
+ }
1430
+
1431
+ $this->unpackArchive($localPath, $arc);
1432
+
1433
+ $this->archiveSize = 0;
1434
+
1435
+ // find symlinks and check extracted items
1436
+ $checkRes = $this->checkExtractItems($dir);
1437
+ if ($checkRes['symlinks']) {
1438
+ $this->rmdirRecursive($dir);
1439
+ return $this->setError(array_merge($this->error, array(elFinder::ERROR_ARC_SYMLINKS)));
1440
+ }
1441
+ $this->archiveSize = $checkRes['totalSize'];
1442
+ if ($checkRes['rmNames']) {
1443
+ foreach ($checkRes['rmNames'] as $name) {
1444
+ $this->addError(elFinder::ERROR_SAVE, $name);
1445
+ }
1446
+ }
1447
+
1448
+ $filesToProcess = self::listFilesInDirectory($dir, true);
1449
+
1450
+ // no files - extract error ?
1451
+ if (empty($filesToProcess)) {
1452
+ $this->rmdirRecursive($dir);
1453
+ return false;
1454
+ }
1455
+
1456
+ // check max files size
1457
+ if ($this->options['maxArcFilesSize'] > 0 && $this->options['maxArcFilesSize'] < $this->archiveSize) {
1458
+ $this->rmdirRecursive($dir);
1459
+ return $this->setError(elFinder::ERROR_ARC_MAXSIZE);
1460
+ }
1461
+
1462
+ $extractTo = $this->extractToNewdir; // 'auto', ture or false
1463
+
1464
+ // archive contains one item - extract in archive dir
1465
+ $name = '';
1466
+ $src = $dir . DIRECTORY_SEPARATOR . $filesToProcess[0];
1467
+ if (($extractTo === 'auto' || !$extractTo) && count($filesToProcess) === 1 && is_file($src)) {
1468
+ $name = $filesToProcess[0];
1469
+ } else if ($extractTo === 'auto' || $extractTo) {
1470
+ // for several files - create new directory
1471
+ // create unique name for directory
1472
+ $src = $dir;
1473
+ $splits = elFinder::splitFileExtention(basename($path));
1474
+ $name = $splits[0];
1475
+ $test = $this->_joinPath(dirname($path), $name);
1476
+ if ($this->stat($test)) {
1477
+ $name = $this->uniqueName(dirname($path), $name, '-', false);
1478
+ }
1479
+ }
1480
+
1481
+ if ($name !== '' && is_file($src)) {
1482
+ $result = $this->_joinPath(dirname($path), $name);
1483
+
1484
+ if (!ftp_put($this->connect, $result, $src, FTP_BINARY)) {
1485
+ $this->rmdirRecursive($dir);
1486
+ return false;
1487
+ }
1488
+ } else {
1489
+ $dstDir = $this->_dirname($path);
1490
+ $result = array();
1491
+ if (is_dir($src) && $name) {
1492
+ $target = $this->_joinPath($dstDir, $name);
1493
+ $_stat = $this->_stat($target);
1494
+ if ($_stat) {
1495
+ if (!$this->options['copyJoin']) {
1496
+ if ($_stat['mime'] === 'directory') {
1497
+ $this->delTree($target);
1498
+ } else {
1499
+ $this->_unlink($target);
1500
+ }
1501
+ $_stat = false;
1502
+ } else {
1503
+ $dstDir = $target;
1504
+ }
1505
+ }
1506
+ if (!$_stat && (!$dstDir = $this->_mkdir($dstDir, $name))) {
1507
+ $this->rmdirRecursive($dir);
1508
+ return false;
1509
+ }
1510
+ $result[] = $dstDir;
1511
+ }
1512
+ foreach ($filesToProcess as $name) {
1513
+ $name = rtrim($name, DIRECTORY_SEPARATOR);
1514
+ $src = $dir . DIRECTORY_SEPARATOR . $name;
1515
+ if (is_dir($src)) {
1516
+ $p = dirname($name);
1517
+ if ($p === '.') {
1518
+ $p = '';
1519
+ }
1520
+ $name = basename($name);
1521
+ $target = $this->_joinPath($this->_joinPath($dstDir, $p), $name);
1522
+ $_stat = $this->_stat($target);
1523
+ if ($_stat) {
1524
+ if (!$this->options['copyJoin']) {
1525
+ if ($_stat['mime'] === 'directory') {
1526
+ $this->delTree($target);
1527
+ } else {
1528
+ $this->_unlink($target);
1529
+ }
1530
+ $_stat = false;
1531
+ }
1532
+ }
1533
+ if (!$_stat && (!$target = $this->_mkdir($this->_joinPath($dstDir, $p), $name))) {
1534
+ $this->rmdirRecursive($dir);
1535
+ return false;
1536
+ }
1537
+ } else {
1538
+ $target = $this->_joinPath($dstDir, $name);
1539
+ if (!ftp_put($this->connect, $target, $src, FTP_BINARY)) {
1540
+ $this->rmdirRecursive($dir);
1541
+ return false;
1542
+ }
1543
+ }
1544
+ $result[] = $target;
1545
+ }
1546
+ if (!$result) {
1547
+ $this->rmdirRecursive($dir);
1548
+ return false;
1549
+ }
1550
+ }
1551
+
1552
+ is_dir($dir) && $this->rmdirRecursive($dir);
1553
+
1554
+ $this->clearcache();
1555
+ return $result ? $result : false;
1556
+ }
1557
+
1558
+ /**
1559
+ * Create archive and return its path
1560
+ *
1561
+ * @param string $dir target dir
1562
+ * @param array $files files names list
1563
+ * @param string $name archive name
1564
+ * @param array $arc archiver options
1565
+ *
1566
+ * @return string|bool
1567
+ * @throws elFinderAbortException
1568
+ * @author Dmitry (dio) Levashov,
1569
+ * @author Alexey Sukhotin
1570
+ */
1571
+ protected function _archive($dir, $files, $name, $arc)
1572
+ {
1573
+ // get current directory
1574
+ $cwd = getcwd();
1575
+
1576
+ $tmpDir = $this->tempDir();
1577
+ if (!$tmpDir) {
1578
+ return false;
1579
+ }
1580
+
1581
+ //download data
1582
+ if (!$this->ftp_download_files($dir, $files, $tmpDir)) {
1583
+ //cleanup
1584
+ $this->rmdirRecursive($tmpDir);
1585
+ return false;
1586
+ }
1587
+
1588
+ $remoteArchiveFile = false;
1589
+ if ($path = $this->makeArchive($tmpDir, $files, $name, $arc)) {
1590
+ $remoteArchiveFile = $this->_joinPath($dir, $name);
1591
+ if (!ftp_put($this->connect, $remoteArchiveFile, $path, FTP_BINARY)) {
1592
+ $remoteArchiveFile = false;
1593
+ }
1594
+ }
1595
+
1596
+ //cleanup
1597
+ if (!$this->rmdirRecursive($tmpDir)) {
1598
+ return false;
1599
+ }
1600
+
1601
+ return $remoteArchiveFile;
1602
+ }
1603
+
1604
+ /**
1605
+ * Create writable temporary directory and return path to it.
1606
+ *
1607
+ * @return string path to the new temporary directory or false in case of error.
1608
+ */
1609
+ private function tempDir()
1610
+ {
1611
+ $tempPath = tempnam($this->tmp, 'elFinder');
1612
+ if (!$tempPath) {
1613
+ $this->setError(elFinder::ERROR_CREATING_TEMP_DIR, $this->tmp);
1614
+ return false;
1615
+ }
1616
+ $success = unlink($tempPath);
1617
+ if (!$success) {
1618
+ $this->setError(elFinder::ERROR_CREATING_TEMP_DIR, $this->tmp);
1619
+ return false;
1620
+ }
1621
+ $success = mkdir($tempPath, 0700, true);
1622
+ if (!$success) {
1623
+ $this->setError(elFinder::ERROR_CREATING_TEMP_DIR, $this->tmp);
1624
+ return false;
1625
+ }
1626
+ return $tempPath;
1627
+ }
1628
+
1629
+ /**
1630
+ * Gets an array of absolute remote FTP paths of files and
1631
+ * folders in $remote_directory omitting symbolic links.
1632
+ *
1633
+ * @param $remote_directory string remote FTP path to scan for file and folders recursively
1634
+ * @param $targets array Array of target item. `null` is to get all of items
1635
+ *
1636
+ * @return array of elements each of which is an array of two elements:
1637
+ * <ul>
1638
+ * <li>$item['path'] - absolute remote FTP path</li>
1639
+ * <li>$item['type'] - either 'f' for file or 'd' for directory</li>
1640
+ * </ul>
1641
+ */
1642
+ protected function ftp_scan_dir($remote_directory, $targets = null)
1643
+ {
1644
+ $buff = $this->ftpRawList($remote_directory);
1645
+ $items = array();
1646
+ if ($targets && is_array($targets)) {
1647
+ $targets = array_flip($targets);
1648
+ } else {
1649
+ $targets = false;
1650
+ }
1651
+ foreach ($buff as $str) {
1652
+ $info = preg_split("/\s+/", $str, 9);
1653
+ if (!isset($this->ftpOsUnix)) {
1654
+ $this->ftpOsUnix = !preg_match('/\d/', substr($info[0], 0, 1));
1655
+ }
1656
+ if (!$this->ftpOsUnix) {
1657
+ $info = $this->normalizeRawWindows($str);
1658
+ }
1659
+ $type = substr($info[0], 0, 1);
1660
+ $name = trim($info[8]);
1661
+ if ($name !== '.' && $name !== '..' && (!$targets || isset($targets[$name]))) {
1662
+ switch ($type) {
1663
+ case 'l' : //omit symbolic links
1664
+ case 'd' :
1665
+ $remote_file_path = $this->_joinPath($remote_directory, $name);
1666
+ $item = array();
1667
+ $item['path'] = $remote_file_path;
1668
+ $item['type'] = 'd'; // normal file
1669
+ $items[] = $item;
1670
+ $items = array_merge($items, $this->ftp_scan_dir($remote_file_path));
1671
+ break;
1672
+ default:
1673
+ $remote_file_path = $this->_joinPath($remote_directory, $name);
1674
+ $item = array();
1675
+ $item['path'] = $remote_file_path;
1676
+ $item['type'] = 'f'; // normal file
1677
+ $items[] = $item;
1678
+ }
1679
+ }
1680
+ }
1681
+ return $items;
1682
+ }
1683
+
1684
+ /**
1685
+ * Downloads specified files from remote directory
1686
+ * if there is a directory among files it is downloaded recursively (omitting symbolic links).
1687
+ *
1688
+ * @param $remote_directory string remote FTP path to a source directory to download from.
1689
+ * @param array $files list of files to download from remote directory.
1690
+ * @param $dest_local_directory string destination folder to store downloaded files.
1691
+ *
1692
+ * @return bool true on success and false on failure.
1693
+ */
1694
+ private function ftp_download_files($remote_directory, array $files, $dest_local_directory)
1695
+ {
1696
+ $contents = $this->ftp_scan_dir($remote_directory, $files);
1697
+ if (!isset($contents)) {
1698
+ $this->setError(elFinder::ERROR_FTP_DOWNLOAD_FILE, $remote_directory);
1699
+ return false;
1700
+ }
1701
+ $remoteDirLen = strlen($remote_directory);
1702
+ foreach ($contents as $item) {
1703
+ $relative_path = substr($item['path'], $remoteDirLen);
1704
+ $local_path = $dest_local_directory . DIRECTORY_SEPARATOR . $relative_path;
1705
+ switch ($item['type']) {
1706
+ case 'd':
1707
+ $success = mkdir($local_path);
1708
+ break;
1709
+ case 'f':
1710
+ $success = ftp_get($this->connect, $local_path, $item['path'], FTP_BINARY);
1711
+ break;
1712
+ default:
1713
+ $success = true;
1714
+ }
1715
+ if (!$success) {
1716
+ $this->setError(elFinder::ERROR_FTP_DOWNLOAD_FILE, $remote_directory);
1717
+ return false;
1718
+ }
1719
+ }
1720
+ return true;
1721
+ }
1722
+
1723
+ /**
1724
+ * Delete local directory recursively.
1725
+ *
1726
+ * @param $dirPath string to directory to be erased.
1727
+ *
1728
+ * @return bool true on success and false on failure.
1729
+ * @throws Exception
1730
+ */
1731
+ private function deleteDir($dirPath)
1732
+ {
1733
+ if (!is_dir($dirPath)) {
1734
+ $success = unlink($dirPath);
1735
+ } else {
1736
+ $success = true;
1737
+ foreach (array_reverse(elFinderVolumeFTP::listFilesInDirectory($dirPath, false)) as $path) {
1738
+ $path = $dirPath . DIRECTORY_SEPARATOR . $path;
1739
+ if (is_link($path)) {
1740
+ unlink($path);
1741
+ } else if (is_dir($path)) {
1742
+ $success = rmdir($path);
1743
+ } else {
1744
+ $success = unlink($path);
1745
+ }
1746
+ if (!$success) {
1747
+ break;
1748
+ }
1749
+ }
1750
+ if ($success) {
1751
+ $success = rmdir($dirPath);
1752
+ }
1753
+ }
1754
+ if (!$success) {
1755
+ $this->setError(elFinder::ERROR_RM, $dirPath);
1756
+ return false;
1757
+ }
1758
+ return $success;
1759
+ }
1760
+
1761
+ /**
1762
+ * Returns array of strings containing all files and folders in the specified local directory.
1763
+ *
1764
+ * @param $dir
1765
+ * @param $omitSymlinks
1766
+ * @param string $prefix
1767
+ *
1768
+ * @return array array of files and folders names relative to the $path
1769
+ * or an empty array if the directory $path is empty,
1770
+ * <br />
1771
+ * false if $path is not a directory or does not exist.
1772
+ * @throws Exception
1773
+ * @internal param string $path path to directory to scan.
1774
+ */
1775
+ private static function listFilesInDirectory($dir, $omitSymlinks, $prefix = '')
1776
+ {
1777
+ if (!is_dir($dir)) {
1778
+ return false;
1779
+ }
1780
+ $excludes = array(".", "..");
1781
+ $result = array();
1782
+ $files = self::localScandir($dir);
1783
+ if (!$files) {
1784
+ return array();
1785
+ }
1786
+ foreach ($files as $file) {
1787
+ if (!in_array($file, $excludes)) {
1788
+ $path = $dir . DIRECTORY_SEPARATOR . $file;
1789
+ if (is_link($path)) {
1790
+ if ($omitSymlinks) {
1791
+ continue;
1792
+ } else {
1793
+ $result[] = $prefix . $file;
1794
+ }
1795
+ } else if (is_dir($path)) {
1796
+ $result[] = $prefix . $file . DIRECTORY_SEPARATOR;
1797
+ $subs = elFinderVolumeFTP::listFilesInDirectory($path, $omitSymlinks, $prefix . $file . DIRECTORY_SEPARATOR);
1798
+ if ($subs) {
1799
+ $result = array_merge($result, $subs);
1800
+ }
1801
+
1802
+ } else {
1803
+ $result[] = $prefix . $file;
1804
+ }
1805
+ }
1806
+ }
1807
+ return $result;
1808
+ }
1809
+
1810
+ } // END class