drg_elfinder 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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