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,1477 @@
1
+ <?php
2
+
3
+ // Implement similar functionality in PHP 5.2 or 5.3
4
+ // http://php.net/manual/class.recursivecallbackfilteriterator.php#110974
5
+ if (!class_exists('RecursiveCallbackFilterIterator', false)) {
6
+ class RecursiveCallbackFilterIterator extends RecursiveFilterIterator
7
+ {
8
+ private $callback;
9
+
10
+ public function __construct(RecursiveIterator $iterator, $callback)
11
+ {
12
+ $this->callback = $callback;
13
+ parent::__construct($iterator);
14
+ }
15
+
16
+ public function accept()
17
+ {
18
+ return call_user_func($this->callback, parent::current(), parent::key(), parent::getInnerIterator());
19
+ }
20
+
21
+ public function getChildren()
22
+ {
23
+ return new self($this->getInnerIterator()->getChildren(), $this->callback);
24
+ }
25
+ }
26
+ }
27
+
28
+ /**
29
+ * elFinder driver for local filesystem.
30
+ *
31
+ * @author Dmitry (dio) Levashov
32
+ * @author Troex Nevelin
33
+ **/
34
+ class elFinderVolumeLocalFileSystem extends elFinderVolumeDriver
35
+ {
36
+
37
+ /**
38
+ * Driver id
39
+ * Must be started from letter and contains [a-z0-9]
40
+ * Used as part of volume id
41
+ *
42
+ * @var string
43
+ **/
44
+ protected $driverId = 'l';
45
+
46
+ /**
47
+ * Required to count total archive files size
48
+ *
49
+ * @var int
50
+ **/
51
+ protected $archiveSize = 0;
52
+
53
+ /**
54
+ * Is checking stat owner
55
+ *
56
+ * @var boolean
57
+ */
58
+ protected $statOwner = false;
59
+
60
+ /**
61
+ * Path to quarantine directory
62
+ *
63
+ * @var string
64
+ */
65
+ private $quarantine;
66
+
67
+ /**
68
+ * Constructor
69
+ * Extend options with required fields
70
+ *
71
+ * @author Dmitry (dio) Levashov
72
+ */
73
+ public function __construct()
74
+ {
75
+ $this->options['alias'] = ''; // alias to replace root dir name
76
+ $this->options['dirMode'] = 0755; // new dirs mode
77
+ $this->options['fileMode'] = 0644; // new files mode
78
+ $this->options['rootCssClass'] = 'elfinder-navbar-root-local';
79
+ $this->options['followSymLinks'] = true;
80
+ $this->options['detectDirIcon'] = ''; // file name that is detected as a folder icon e.g. '.diricon.png'
81
+ $this->options['keepTimestamp'] = array('copy', 'move'); // keep timestamp at inner filesystem allowed 'copy', 'move' and 'upload'
82
+ $this->options['substituteImg'] = true; // support substitute image with dim command
83
+ $this->options['statCorrector'] = null; // callable to correct stat data `function(&$stat, $path, $statOwner, $volumeDriveInstance){}`
84
+ if (DIRECTORY_SEPARATOR === '/') {
85
+ // Linux
86
+ $this->options['acceptedName'] = '/^[^\.\/\x00][^\/\x00]*$/';
87
+ } else {
88
+ // Windows
89
+ $this->options['acceptedName'] = '/^[^\.\/\x00\\\:*?"<>|][^\/\x00\\\:*?"<>|]*$/';
90
+ }
91
+ }
92
+
93
+ /*********************************************************************/
94
+ /* INIT AND CONFIGURE */
95
+ /*********************************************************************/
96
+
97
+ /**
98
+ * Prepare driver before mount volume.
99
+ * Return true if volume is ready.
100
+ *
101
+ * @return bool
102
+ **/
103
+ protected function init()
104
+ {
105
+ // Normalize directory separator for windows
106
+ if (DIRECTORY_SEPARATOR !== '/') {
107
+ foreach (array('path', 'tmbPath', 'tmpPath', 'quarantine') as $key) {
108
+ if (!empty($this->options[$key])) {
109
+ $this->options[$key] = str_replace('/', DIRECTORY_SEPARATOR, $this->options[$key]);
110
+ }
111
+ }
112
+ // PHP >= 7.1 Supports UTF-8 path on Windows
113
+ if (version_compare(PHP_VERSION, '7.1', '>=')) {
114
+ $this->options['encoding'] = '';
115
+ $this->options['locale'] = '';
116
+ }
117
+ }
118
+ if (!$cwd = getcwd()) {
119
+ return $this->setError('elFinder LocalVolumeDriver requires a result of getcwd().');
120
+ }
121
+ // detect systemRoot
122
+ if (!isset($this->options['systemRoot'])) {
123
+ if ($cwd[0] === DIRECTORY_SEPARATOR || $this->root[0] === DIRECTORY_SEPARATOR) {
124
+ $this->systemRoot = DIRECTORY_SEPARATOR;
125
+ } else if (preg_match('/^([a-zA-Z]:' . preg_quote(DIRECTORY_SEPARATOR, '/') . ')/', $this->root, $m)) {
126
+ $this->systemRoot = $m[1];
127
+ } else if (preg_match('/^([a-zA-Z]:' . preg_quote(DIRECTORY_SEPARATOR, '/') . ')/', $cwd, $m)) {
128
+ $this->systemRoot = $m[1];
129
+ }
130
+ }
131
+ $this->root = $this->getFullPath($this->root, $cwd);
132
+ if (!empty($this->options['startPath'])) {
133
+ $this->options['startPath'] = $this->getFullPath($this->options['startPath'], $this->root);
134
+ }
135
+
136
+ if (is_null($this->options['syncChkAsTs'])) {
137
+ $this->options['syncChkAsTs'] = true;
138
+ }
139
+ if (is_null($this->options['syncCheckFunc'])) {
140
+ $this->options['syncCheckFunc'] = array($this, 'localFileSystemInotify');
141
+ }
142
+ // check 'statCorrector'
143
+ if (empty($this->options['statCorrector']) || !is_callable($this->options['statCorrector'])) {
144
+ $this->options['statCorrector'] = null;
145
+ }
146
+
147
+ return true;
148
+ }
149
+
150
+ /**
151
+ * Configure after successfull mount.
152
+ *
153
+ * @return void
154
+ * @throws elFinderAbortException
155
+ * @author Dmitry (dio) Levashov
156
+ */
157
+ protected function configure()
158
+ {
159
+ $hiddens = array();
160
+ $root = $this->stat($this->root);
161
+
162
+ // check thumbnails path
163
+ if (!empty($this->options['tmbPath'])) {
164
+ if (strpos($this->options['tmbPath'], DIRECTORY_SEPARATOR) === false) {
165
+ $hiddens['tmb'] = $this->options['tmbPath'];
166
+ $this->options['tmbPath'] = $this->_abspath($this->options['tmbPath']);
167
+ } else {
168
+ $this->options['tmbPath'] = $this->_normpath($this->options['tmbPath']);
169
+ }
170
+ }
171
+ // check temp path
172
+ if (!empty($this->options['tmpPath'])) {
173
+ if (strpos($this->options['tmpPath'], DIRECTORY_SEPARATOR) === false) {
174
+ $hiddens['temp'] = $this->options['tmpPath'];
175
+ $this->options['tmpPath'] = $this->_abspath($this->options['tmpPath']);
176
+ } else {
177
+ $this->options['tmpPath'] = $this->_normpath($this->options['tmpPath']);
178
+ }
179
+ }
180
+ // check quarantine path
181
+ $_quarantine = '';
182
+ if (!empty($this->options['quarantine'])) {
183
+ if (strpos($this->options['quarantine'], DIRECTORY_SEPARATOR) === false) {
184
+ //$hiddens['quarantine'] = $this->options['quarantine'];
185
+ //$this->options['quarantine'] = $this->_abspath($this->options['quarantine']);
186
+ $_quarantine = $this->_abspath($this->options['quarantine']);
187
+ $this->options['quarantine'] = '';
188
+ } else {
189
+ $this->options['quarantine'] = $this->_normpath($this->options['quarantine']);
190
+ }
191
+ } else {
192
+ $_quarantine = $this->_abspath('.quarantine');
193
+ }
194
+ is_dir($_quarantine) && self::localRmdirRecursive($_quarantine);
195
+
196
+ parent::configure();
197
+
198
+ // check tmbPath
199
+ if (!$this->tmbPath && isset($hiddens['tmb'])) {
200
+ unset($hiddens['tmb']);
201
+ }
202
+
203
+ // if no thumbnails url - try detect it
204
+ if ($root['read'] && !$this->tmbURL && $this->URL) {
205
+ if (strpos($this->tmbPath, $this->root) === 0) {
206
+ $this->tmbURL = $this->URL . str_replace(DIRECTORY_SEPARATOR, '/', substr($this->tmbPath, strlen($this->root) + 1));
207
+ if (preg_match("|[^/?&=]$|", $this->tmbURL)) {
208
+ $this->tmbURL .= '/';
209
+ }
210
+ }
211
+ }
212
+
213
+ // set $this->tmp by options['tmpPath']
214
+ $this->tmp = '';
215
+ if (!empty($this->options['tmpPath'])) {
216
+ if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'], $this->options['dirMode'], true)) && is_writable($this->options['tmpPath'])) {
217
+ $this->tmp = $this->options['tmpPath'];
218
+ } else {
219
+ if (isset($hiddens['temp'])) {
220
+ unset($hiddens['temp']);
221
+ }
222
+ }
223
+ }
224
+ if (!$this->tmp && ($tmp = elFinder::getStaticVar('commonTempPath'))) {
225
+ $this->tmp = $tmp;
226
+ }
227
+
228
+ // check quarantine dir
229
+ $this->quarantine = '';
230
+ if (!empty($this->options['quarantine'])) {
231
+ if ((is_dir($this->options['quarantine']) || mkdir($this->options['quarantine'], $this->options['dirMode'], true)) && is_writable($this->options['quarantine'])) {
232
+ $this->quarantine = $this->options['quarantine'];
233
+ } else {
234
+ if (isset($hiddens['quarantine'])) {
235
+ unset($hiddens['quarantine']);
236
+ }
237
+ }
238
+ } else if ($_path = elFinder::getCommonTempPath()) {
239
+ $this->quarantine = $_path;
240
+ }
241
+
242
+ if (!$this->quarantine) {
243
+ if (!$this->tmp) {
244
+ $this->archivers['extract'] = array();
245
+ $this->disabled[] = 'extract';
246
+ } else {
247
+ $this->quarantine = $this->tmp;
248
+ }
249
+ }
250
+
251
+ if ($hiddens) {
252
+ foreach ($hiddens as $hidden) {
253
+ $this->attributes[] = array(
254
+ 'pattern' => '~^' . preg_quote(DIRECTORY_SEPARATOR . $hidden, '~') . '$~',
255
+ 'read' => false,
256
+ 'write' => false,
257
+ 'locked' => true,
258
+ 'hidden' => true
259
+ );
260
+ }
261
+ }
262
+
263
+ if (!empty($this->options['keepTimestamp'])) {
264
+ $this->options['keepTimestamp'] = array_flip($this->options['keepTimestamp']);
265
+ }
266
+
267
+ $this->statOwner = (!empty($this->options['statOwner']));
268
+
269
+ // enable WinRemoveTailDots plugin on Windows server
270
+ if (DIRECTORY_SEPARATOR !== '/') {
271
+ if (!isset($this->options['plugin'])) {
272
+ $this->options['plugin'] = array();
273
+ }
274
+ $this->options['plugin']['WinRemoveTailDots'] = array('enable' => true);
275
+ }
276
+ }
277
+
278
+ /**
279
+ * Long pooling sync checker
280
+ * This function require server command `inotifywait`
281
+ * If `inotifywait` need full path, Please add `define('ELFINER_INOTIFYWAIT_PATH', '/PATH_TO/inotifywait');` into connector.php
282
+ *
283
+ * @param string $path
284
+ * @param int $standby
285
+ * @param number $compare
286
+ *
287
+ * @return number|bool
288
+ * @throws elFinderAbortException
289
+ */
290
+ public function localFileSystemInotify($path, $standby, $compare)
291
+ {
292
+ if (isset($this->sessionCache['localFileSystemInotify_disable'])) {
293
+ return false;
294
+ }
295
+ $path = realpath($path);
296
+ $mtime = filemtime($path);
297
+ if (!$mtime) {
298
+ return false;
299
+ }
300
+ if ($mtime != $compare) {
301
+ return $mtime;
302
+ }
303
+ $inotifywait = defined('ELFINER_INOTIFYWAIT_PATH') ? ELFINER_INOTIFYWAIT_PATH : 'inotifywait';
304
+ $standby = max(1, intval($standby));
305
+ $cmd = $inotifywait . ' ' . escapeshellarg($path) . ' -t ' . $standby . ' -e moved_to,moved_from,move,close_write,delete,delete_self';
306
+ $this->procExec($cmd, $o, $r);
307
+ if ($r === 0) {
308
+ // changed
309
+ clearstatcache();
310
+ if (file_exists($path)) {
311
+ $mtime = filemtime($path); // error on busy?
312
+ return $mtime ? $mtime : time();
313
+ } else {
314
+ // target was removed
315
+ return 0;
316
+ }
317
+ } else if ($r === 2) {
318
+ // not changed (timeout)
319
+ return $compare;
320
+ }
321
+ // error
322
+ // cache to $_SESSION
323
+ $this->sessionCache['localFileSystemInotify_disable'] = true;
324
+ $this->session->set($this->id, $this->sessionCache);
325
+ return false;
326
+ }
327
+
328
+ /*********************************************************************/
329
+ /* FS API */
330
+ /*********************************************************************/
331
+
332
+ /*********************** paths/urls *************************/
333
+
334
+ /**
335
+ * Return parent directory path
336
+ *
337
+ * @param string $path file path
338
+ *
339
+ * @return string
340
+ * @author Dmitry (dio) Levashov
341
+ **/
342
+ protected function _dirname($path)
343
+ {
344
+ return dirname($path);
345
+ }
346
+
347
+ /**
348
+ * Return file name
349
+ *
350
+ * @param string $path file path
351
+ *
352
+ * @return string
353
+ * @author Dmitry (dio) Levashov
354
+ **/
355
+ protected function _basename($path)
356
+ {
357
+ return basename($path);
358
+ }
359
+
360
+ /**
361
+ * Join dir name and file name and retur full path
362
+ *
363
+ * @param string $dir
364
+ * @param string $name
365
+ *
366
+ * @return string
367
+ * @author Dmitry (dio) Levashov
368
+ **/
369
+ protected function _joinPath($dir, $name)
370
+ {
371
+ $dir = rtrim($dir, DIRECTORY_SEPARATOR);
372
+ $path = realpath($dir . DIRECTORY_SEPARATOR . $name);
373
+ // realpath() returns FALSE if the file does not exist
374
+ if ($path === false || strpos($path, $this->root) !== 0) {
375
+ if (DIRECTORY_SEPARATOR !== '/') {
376
+ $name = str_replace('/', DIRECTORY_SEPARATOR, $name);
377
+ }
378
+ // Directory traversal measures
379
+ if (strpos($name, '..' . DIRECTORY_SEPARATOR) !== false) {
380
+ $name = basename($name);
381
+ }
382
+ $path = $dir . DIRECTORY_SEPARATOR . $name;
383
+ }
384
+ return $path;
385
+ }
386
+
387
+ /**
388
+ * Return normalized path, this works the same as os.path.normpath() in Python
389
+ *
390
+ * @param string $path path
391
+ *
392
+ * @return string
393
+ * @author Troex Nevelin
394
+ **/
395
+ protected function _normpath($path)
396
+ {
397
+ if (empty($path)) {
398
+ return '.';
399
+ }
400
+
401
+ $changeSep = (DIRECTORY_SEPARATOR !== '/');
402
+ if ($changeSep) {
403
+ $drive = '';
404
+ if (preg_match('/^([a-zA-Z]:)(.*)/', $path, $m)) {
405
+ $drive = $m[1];
406
+ $path = $m[2] ? $m[2] : '/';
407
+ }
408
+ $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
409
+ }
410
+
411
+ if (strpos($path, '/') === 0) {
412
+ $initial_slashes = true;
413
+ } else {
414
+ $initial_slashes = false;
415
+ }
416
+
417
+ if (($initial_slashes)
418
+ && (strpos($path, '//') === 0)
419
+ && (strpos($path, '///') === false)) {
420
+ $initial_slashes = 2;
421
+ }
422
+
423
+ $initial_slashes = (int)$initial_slashes;
424
+
425
+ $comps = explode('/', $path);
426
+ $new_comps = array();
427
+ foreach ($comps as $comp) {
428
+ if (in_array($comp, array('', '.'))) {
429
+ continue;
430
+ }
431
+
432
+ if (($comp != '..')
433
+ || (!$initial_slashes && !$new_comps)
434
+ || ($new_comps && (end($new_comps) == '..'))) {
435
+ array_push($new_comps, $comp);
436
+ } elseif ($new_comps) {
437
+ array_pop($new_comps);
438
+ }
439
+ }
440
+ $comps = $new_comps;
441
+ $path = implode('/', $comps);
442
+ if ($initial_slashes) {
443
+ $path = str_repeat('/', $initial_slashes) . $path;
444
+ }
445
+
446
+ if ($changeSep) {
447
+ $path = $drive . str_replace('/', DIRECTORY_SEPARATOR, $path);
448
+ }
449
+
450
+ return $path ? $path : '.';
451
+ }
452
+
453
+ /**
454
+ * Return file path related to root dir
455
+ *
456
+ * @param string $path file path
457
+ *
458
+ * @return string
459
+ * @author Dmitry (dio) Levashov
460
+ **/
461
+ protected function _relpath($path)
462
+ {
463
+ if ($path === $this->root) {
464
+ return '';
465
+ } else {
466
+ if (strpos($path, $this->root) === 0) {
467
+ return ltrim(substr($path, strlen($this->root)), DIRECTORY_SEPARATOR);
468
+ } else {
469
+ // for link
470
+ return $path;
471
+ }
472
+ }
473
+ }
474
+
475
+ /**
476
+ * Convert path related to root dir into real path
477
+ *
478
+ * @param string $path file path
479
+ *
480
+ * @return string
481
+ * @author Dmitry (dio) Levashov
482
+ **/
483
+ protected function _abspath($path)
484
+ {
485
+ if ($path === DIRECTORY_SEPARATOR) {
486
+ return $this->root;
487
+ } else {
488
+ $path = $this->_normpath($path);
489
+ if (strpos($path, $this->systemRoot) === 0) {
490
+ return $path;
491
+ } else if (DIRECTORY_SEPARATOR !== '/' && preg_match('/^[a-zA-Z]:' . preg_quote(DIRECTORY_SEPARATOR, '/') . '/', $path)) {
492
+ return $path;
493
+ } else {
494
+ return $this->_joinPath($this->root, $path);
495
+ }
496
+ }
497
+ }
498
+
499
+ /**
500
+ * Return fake path started from root dir
501
+ *
502
+ * @param string $path file path
503
+ *
504
+ * @return string
505
+ * @author Dmitry (dio) Levashov
506
+ **/
507
+ protected function _path($path)
508
+ {
509
+ return $this->rootName . ($path == $this->root ? '' : $this->separator . $this->_relpath($path));
510
+ }
511
+
512
+ /**
513
+ * Return true if $path is children of $parent
514
+ *
515
+ * @param string $path path to check
516
+ * @param string $parent parent path
517
+ *
518
+ * @return bool
519
+ * @author Dmitry (dio) Levashov
520
+ **/
521
+ protected function _inpath($path, $parent)
522
+ {
523
+ $cwd = getcwd();
524
+ $real_path = $this->getFullPath($path, $cwd);
525
+ $real_parent = $this->getFullPath($parent, $cwd);
526
+ if ($real_path && $real_parent) {
527
+ return $real_path === $real_parent || strpos($real_path, rtrim($real_parent, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR) === 0;
528
+ }
529
+ return false;
530
+ }
531
+
532
+
533
+
534
+ /***************** file stat ********************/
535
+
536
+ /**
537
+ * Return stat for given path.
538
+ * Stat contains following fields:
539
+ * - (int) size file size in b. required
540
+ * - (int) ts file modification time in unix time. required
541
+ * - (string) mime mimetype. required for folders, others - optionally
542
+ * - (bool) read read permissions. required
543
+ * - (bool) write write permissions. required
544
+ * - (bool) locked is object locked. optionally
545
+ * - (bool) hidden is object hidden. optionally
546
+ * - (string) alias for symlinks - link target path relative to root path. optionally
547
+ * - (string) target for symlinks - link target path. optionally
548
+ * If file does not exists - returns empty array or false.
549
+ *
550
+ * @param string $path file path
551
+ *
552
+ * @return array|false
553
+ * @author Dmitry (dio) Levashov
554
+ **/
555
+ protected function _stat($path)
556
+ {
557
+ $stat = array();
558
+
559
+ if (!file_exists($path) && !is_link($path)) {
560
+ return $stat;
561
+ }
562
+
563
+ //Verifies the given path is the root or is inside the root. Prevents directory traveral.
564
+ if (!$this->_inpath($path, $this->root)) {
565
+ return $stat;
566
+ }
567
+
568
+ $stat['isowner'] = false;
569
+ $linkreadable = false;
570
+ if ($path != $this->root && is_link($path)) {
571
+ if (!$this->options['followSymLinks']) {
572
+ return array();
573
+ }
574
+ if (!($target = $this->readlink($path))
575
+ || $target == $path) {
576
+ if (is_null($target)) {
577
+ $stat = array();
578
+ return $stat;
579
+ } else {
580
+ $stat['mime'] = 'symlink-broken';
581
+ $target = readlink($path);
582
+ $lstat = lstat($path);
583
+ $ostat = $this->getOwnerStat($lstat['uid'], $lstat['gid']);
584
+ $linkreadable = !empty($ostat['isowner']);
585
+ }
586
+ }
587
+ $stat['alias'] = $this->_path($target);
588
+ $stat['target'] = $target;
589
+ }
590
+
591
+ $readable = is_readable($path);
592
+
593
+ if ($readable) {
594
+ $size = sprintf('%u', filesize($path));
595
+ $stat['ts'] = filemtime($path);
596
+ if ($this->statOwner) {
597
+ $fstat = stat($path);
598
+ $uid = $fstat['uid'];
599
+ $gid = $fstat['gid'];
600
+ $stat['perm'] = substr((string)decoct($fstat['mode']), -4);
601
+ $stat = array_merge($stat, $this->getOwnerStat($uid, $gid));
602
+ }
603
+ }
604
+
605
+ if (($dir = is_dir($path)) && $this->options['detectDirIcon']) {
606
+ $favicon = $path . DIRECTORY_SEPARATOR . $this->options['detectDirIcon'];
607
+ if ($this->URL && file_exists($favicon)) {
608
+ $stat['icon'] = $this->URL . str_replace(DIRECTORY_SEPARATOR, '/', substr($favicon, strlen($this->root) + 1));
609
+ }
610
+ }
611
+
612
+ if (!isset($stat['mime'])) {
613
+ $stat['mime'] = $dir ? 'directory' : $this->mimetype($path);
614
+ }
615
+ //logical rights first
616
+ $stat['read'] = ($linkreadable || $readable) ? null : false;
617
+ $stat['write'] = is_writable($path) ? null : false;
618
+
619
+ if (is_null($stat['read'])) {
620
+ if ($dir) {
621
+ $stat['size'] = 0;
622
+ } else if (isset($size)) {
623
+ $stat['size'] = $size;
624
+ }
625
+ }
626
+
627
+ if ($this->options['statCorrector']) {
628
+ call_user_func_array($this->options['statCorrector'], array(&$stat, $path, $this->statOwner, $this));
629
+ }
630
+
631
+ return $stat;
632
+ }
633
+
634
+ /**
635
+ * Get stat `owner`, `group` and `isowner` by `uid` and `gid`
636
+ * Sub-fuction of _stat() and _scandir()
637
+ *
638
+ * @param integer $uid
639
+ * @param integer $gid
640
+ *
641
+ * @return array stat
642
+ */
643
+ protected function getOwnerStat($uid, $gid)
644
+ {
645
+ static $names = null;
646
+ static $phpuid = null;
647
+
648
+ if (is_null($names)) {
649
+ $names = array('uid' => array(), 'gid' => array());
650
+ }
651
+ if (is_null($phpuid)) {
652
+ if (is_callable('posix_getuid')) {
653
+ $phpuid = posix_getuid();
654
+ } else {
655
+ $phpuid = 0;
656
+ }
657
+ }
658
+
659
+ $stat = array();
660
+
661
+ if ($uid) {
662
+ $stat['isowner'] = ($phpuid == $uid);
663
+ if (isset($names['uid'][$uid])) {
664
+ $stat['owner'] = $names['uid'][$uid];
665
+ } else if (is_callable('posix_getpwuid')) {
666
+ $pwuid = posix_getpwuid($uid);
667
+ $stat['owner'] = $names['uid'][$uid] = $pwuid['name'];
668
+ } else {
669
+ $stat['owner'] = $names['uid'][$uid] = $uid;
670
+ }
671
+ }
672
+ if ($gid) {
673
+ if (isset($names['gid'][$gid])) {
674
+ $stat['group'] = $names['gid'][$gid];
675
+ } else if (is_callable('posix_getgrgid')) {
676
+ $grgid = posix_getgrgid($gid);
677
+ $stat['group'] = $names['gid'][$gid] = $grgid['name'];
678
+ } else {
679
+ $stat['group'] = $names['gid'][$gid] = $gid;
680
+ }
681
+ }
682
+
683
+ return $stat;
684
+ }
685
+
686
+ /**
687
+ * Return true if path is dir and has at least one childs directory
688
+ *
689
+ * @param string $path dir path
690
+ *
691
+ * @return bool
692
+ * @author Dmitry (dio) Levashov
693
+ **/
694
+ protected function _subdirs($path)
695
+ {
696
+
697
+ $dirs = false;
698
+ if (is_dir($path) && is_readable($path)) {
699
+ if (class_exists('FilesystemIterator', false)) {
700
+ $dirItr = new ParentIterator(
701
+ new RecursiveDirectoryIterator($path,
702
+ FilesystemIterator::SKIP_DOTS |
703
+ FilesystemIterator::CURRENT_AS_SELF |
704
+ (defined('RecursiveDirectoryIterator::FOLLOW_SYMLINKS') ?
705
+ RecursiveDirectoryIterator::FOLLOW_SYMLINKS : 0)
706
+ )
707
+ );
708
+ $dirItr->rewind();
709
+ if ($dirItr->hasChildren()) {
710
+ $dirs = true;
711
+ $name = $dirItr->getSubPathName();
712
+ while ($dirItr->valid()) {
713
+ if (!$this->attr($path . DIRECTORY_SEPARATOR . $name, 'read', null, true)) {
714
+ $dirs = false;
715
+ $dirItr->next();
716
+ $name = $dirItr->getSubPathName();
717
+ continue;
718
+ }
719
+ $dirs = true;
720
+ break;
721
+ }
722
+ }
723
+ } else {
724
+ $path = strtr($path, array('[' => '\\[', ']' => '\\]', '*' => '\\*', '?' => '\\?'));
725
+ return (bool)glob(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . '*', GLOB_ONLYDIR);
726
+ }
727
+ }
728
+ return $dirs;
729
+ }
730
+
731
+ /**
732
+ * Return object width and height
733
+ * Usualy used for images, but can be realize for video etc...
734
+ *
735
+ * @param string $path file path
736
+ * @param string $mime file mime type
737
+ *
738
+ * @return string
739
+ * @author Dmitry (dio) Levashov
740
+ **/
741
+ protected function _dimensions($path, $mime)
742
+ {
743
+ clearstatcache();
744
+ return strpos($mime, 'image') === 0 && is_readable($path) && filesize($path) && ($s = getimagesize($path)) !== false
745
+ ? $s[0] . 'x' . $s[1]
746
+ : false;
747
+ }
748
+ /******************** file/dir content *********************/
749
+
750
+ /**
751
+ * Return symlink target file
752
+ *
753
+ * @param string $path link path
754
+ *
755
+ * @return string
756
+ * @author Dmitry (dio) Levashov
757
+ **/
758
+ protected function readlink($path)
759
+ {
760
+ if (!($target = readlink($path))) {
761
+ return null;
762
+ }
763
+
764
+ if (strpos($target, $this->systemRoot) !== 0) {
765
+ $target = $this->_joinPath(dirname($path), $target);
766
+ }
767
+
768
+ if (!file_exists($target)) {
769
+ return false;
770
+ }
771
+
772
+ return $target;
773
+ }
774
+
775
+ /**
776
+ * Return files list in directory.
777
+ *
778
+ * @param string $path dir path
779
+ *
780
+ * @return array
781
+ * @throws elFinderAbortException
782
+ * @author Dmitry (dio) Levashov
783
+ */
784
+ protected function _scandir($path)
785
+ {
786
+ elFinder::checkAborted();
787
+ $files = array();
788
+ $cache = array();
789
+ $dirWritable = is_writable($path);
790
+ $dirItr = array();
791
+ $followSymLinks = $this->options['followSymLinks'];
792
+ try {
793
+ $dirItr = new DirectoryIterator($path);
794
+ } catch (UnexpectedValueException $e) {
795
+ }
796
+
797
+ foreach ($dirItr as $file) {
798
+ try {
799
+ if ($file->isDot()) {
800
+ continue;
801
+ }
802
+
803
+ $files[] = $fpath = $file->getPathname();
804
+
805
+ $br = false;
806
+ $stat = array();
807
+
808
+ $stat['isowner'] = false;
809
+ $linkreadable = false;
810
+ if ($file->isLink()) {
811
+ if (!$followSymLinks) {
812
+ continue;
813
+ }
814
+ if (!($target = $this->readlink($fpath))
815
+ || $target == $fpath) {
816
+ if (is_null($target)) {
817
+ $stat = array();
818
+ $br = true;
819
+ } else {
820
+ $_path = $fpath;
821
+ $stat['mime'] = 'symlink-broken';
822
+ $target = readlink($_path);
823
+ $lstat = lstat($_path);
824
+ $ostat = $this->getOwnerStat($lstat['uid'], $lstat['gid']);
825
+ $linkreadable = !empty($ostat['isowner']);
826
+ $dir = false;
827
+ $stat['alias'] = $this->_path($target);
828
+ $stat['target'] = $target;
829
+ }
830
+ } else {
831
+ $dir = is_dir($target);
832
+ $stat['alias'] = $this->_path($target);
833
+ $stat['target'] = $target;
834
+ $stat['mime'] = $dir ? 'directory' : $this->mimetype($stat['alias']);
835
+ }
836
+ } else {
837
+ if (($dir = $file->isDir()) && $this->options['detectDirIcon']) {
838
+ $path = $file->getPathname();
839
+ $favicon = $path . DIRECTORY_SEPARATOR . $this->options['detectDirIcon'];
840
+ if ($this->URL && file_exists($favicon)) {
841
+ $stat['icon'] = $this->URL . str_replace(DIRECTORY_SEPARATOR, '/', substr($favicon, strlen($this->root) + 1));
842
+ }
843
+ }
844
+ $stat['mime'] = $dir ? 'directory' : $this->mimetype($fpath);
845
+ }
846
+ $size = sprintf('%u', $file->getSize());
847
+ $stat['ts'] = $file->getMTime();
848
+ if (!$br) {
849
+ if ($this->statOwner && !$linkreadable) {
850
+ $uid = $file->getOwner();
851
+ $gid = $file->getGroup();
852
+ $stat['perm'] = substr((string)decoct($file->getPerms()), -4);
853
+ $stat = array_merge($stat, $this->getOwnerStat($uid, $gid));
854
+ }
855
+
856
+ //logical rights first
857
+ $stat['read'] = ($linkreadable || $file->isReadable()) ? null : false;
858
+ $stat['write'] = $file->isWritable() ? null : false;
859
+ $stat['locked'] = $dirWritable ? null : true;
860
+
861
+ if (is_null($stat['read'])) {
862
+ $stat['size'] = $dir ? 0 : $size;
863
+ }
864
+
865
+ if ($this->options['statCorrector']) {
866
+ call_user_func_array($this->options['statCorrector'], array(&$stat, $fpath, $this->statOwner, $this));
867
+ }
868
+ }
869
+
870
+ $cache[] = array($fpath, $stat);
871
+ } catch (RuntimeException $e) {
872
+ continue;
873
+ }
874
+ }
875
+
876
+ if ($cache) {
877
+ $cache = $this->convEncOut($cache, false);
878
+ foreach ($cache as $d) {
879
+ $this->updateCache($d[0], $d[1]);
880
+ }
881
+ }
882
+
883
+ return $files;
884
+ }
885
+
886
+ /**
887
+ * Open file and return file pointer
888
+ *
889
+ * @param string $path file path
890
+ * @param string $mode
891
+ *
892
+ * @return false|resource
893
+ * @internal param bool $write open file for writing
894
+ * @author Dmitry (dio) Levashov
895
+ */
896
+ protected function _fopen($path, $mode = 'rb')
897
+ {
898
+ return fopen($path, $mode);
899
+ }
900
+
901
+ /**
902
+ * Close opened file
903
+ *
904
+ * @param resource $fp file pointer
905
+ * @param string $path
906
+ *
907
+ * @return bool
908
+ * @author Dmitry (dio) Levashov
909
+ */
910
+ protected function _fclose($fp, $path = '')
911
+ {
912
+ return (is_resource($fp) && fclose($fp));
913
+ }
914
+
915
+ /******************** file/dir manipulations *************************/
916
+
917
+ /**
918
+ * Create dir and return created dir path or false on failed
919
+ *
920
+ * @param string $path parent dir path
921
+ * @param string $name new directory name
922
+ *
923
+ * @return string|bool
924
+ * @author Dmitry (dio) Levashov
925
+ **/
926
+ protected function _mkdir($path, $name)
927
+ {
928
+ $path = $this->_joinPath($path, $name);
929
+
930
+ if (mkdir($path)) {
931
+ chmod($path, $this->options['dirMode']);
932
+ return $path;
933
+ }
934
+
935
+ return false;
936
+ }
937
+
938
+ /**
939
+ * Create file and return it's path or false on failed
940
+ *
941
+ * @param string $path parent dir path
942
+ * @param string $name new file name
943
+ *
944
+ * @return string|bool
945
+ * @author Dmitry (dio) Levashov
946
+ **/
947
+ protected function _mkfile($path, $name)
948
+ {
949
+ $path = $this->_joinPath($path, $name);
950
+
951
+ if (($fp = fopen($path, 'w'))) {
952
+ fclose($fp);
953
+ chmod($path, $this->options['fileMode']);
954
+ return $path;
955
+ }
956
+ return false;
957
+ }
958
+
959
+ /**
960
+ * Create symlink
961
+ *
962
+ * @param string $source file to link to
963
+ * @param string $targetDir folder to create link in
964
+ * @param string $name symlink name
965
+ *
966
+ * @return bool
967
+ * @author Dmitry (dio) Levashov
968
+ **/
969
+ protected function _symlink($source, $targetDir, $name)
970
+ {
971
+ return symlink($source, $this->_joinPath($targetDir, $name));
972
+ }
973
+
974
+ /**
975
+ * Copy file into another file
976
+ *
977
+ * @param string $source source file path
978
+ * @param string $targetDir target directory path
979
+ * @param string $name new file name
980
+ *
981
+ * @return bool
982
+ * @author Dmitry (dio) Levashov
983
+ **/
984
+ protected function _copy($source, $targetDir, $name)
985
+ {
986
+ $mtime = filemtime($source);
987
+ $target = $this->_joinPath($targetDir, $name);
988
+ if ($ret = copy($source, $target)) {
989
+ isset($this->options['keepTimestamp']['copy']) && $mtime && touch($target, $mtime);
990
+ }
991
+ return $ret;
992
+ }
993
+
994
+ /**
995
+ * Move file into another parent dir.
996
+ * Return new file path or false.
997
+ *
998
+ * @param string $source source file path
999
+ * @param $targetDir
1000
+ * @param string $name file name
1001
+ *
1002
+ * @return bool|string
1003
+ * @internal param string $target target dir path
1004
+ * @author Dmitry (dio) Levashov
1005
+ */
1006
+ protected function _move($source, $targetDir, $name)
1007
+ {
1008
+ $mtime = filemtime($source);
1009
+ $target = $this->_joinPath($targetDir, $name);
1010
+ if ($ret = rename($source, $target) ? $target : false) {
1011
+ isset($this->options['keepTimestamp']['move']) && $mtime && touch($target, $mtime);
1012
+ }
1013
+ return $ret;
1014
+ }
1015
+
1016
+ /**
1017
+ * Remove file
1018
+ *
1019
+ * @param string $path file path
1020
+ *
1021
+ * @return bool
1022
+ * @author Dmitry (dio) Levashov
1023
+ **/
1024
+ protected function _unlink($path)
1025
+ {
1026
+ return is_file($path) && unlink($path);
1027
+ }
1028
+
1029
+ /**
1030
+ * Remove dir
1031
+ *
1032
+ * @param string $path dir path
1033
+ *
1034
+ * @return bool
1035
+ * @author Dmitry (dio) Levashov
1036
+ **/
1037
+ protected function _rmdir($path)
1038
+ {
1039
+ return rmdir($path);
1040
+ }
1041
+
1042
+ /**
1043
+ * Create new file and write into it from file pointer.
1044
+ * Return new file path or false on error.
1045
+ *
1046
+ * @param resource $fp file pointer
1047
+ * @param string $dir target dir path
1048
+ * @param string $name file name
1049
+ * @param array $stat file stat (required by some virtual fs)
1050
+ *
1051
+ * @return bool|string
1052
+ * @author Dmitry (dio) Levashov
1053
+ **/
1054
+ protected function _save($fp, $dir, $name, $stat)
1055
+ {
1056
+ $path = $this->_joinPath($dir, $name);
1057
+
1058
+ $meta = stream_get_meta_data($fp);
1059
+ $uri = isset($meta['uri']) ? $meta['uri'] : '';
1060
+ if ($uri && !preg_match('#^[a-zA-Z0-9]+://#', $uri) && !is_link($uri)) {
1061
+ fclose($fp);
1062
+ $mtime = filemtime($uri);
1063
+ $isCmdPaste = ($this->ARGS['cmd'] === 'paste');
1064
+ $isCmdCopy = ($isCmdPaste && empty($this->ARGS['cut']));
1065
+ if (($isCmdCopy || !rename($uri, $path)) && !copy($uri, $path)) {
1066
+ return false;
1067
+ }
1068
+ // keep timestamp on upload
1069
+ if ($mtime && $this->ARGS['cmd'] === 'upload') {
1070
+ touch($path, isset($this->options['keepTimestamp']['upload']) ? $mtime : time());
1071
+ }
1072
+ } else {
1073
+ if (file_put_contents($path, $fp, LOCK_EX) === false) {
1074
+ return false;
1075
+ }
1076
+ }
1077
+
1078
+ chmod($path, $this->options['fileMode']);
1079
+ return $path;
1080
+ }
1081
+
1082
+ /**
1083
+ * Get file contents
1084
+ *
1085
+ * @param string $path file path
1086
+ *
1087
+ * @return string|false
1088
+ * @author Dmitry (dio) Levashov
1089
+ **/
1090
+ protected function _getContents($path)
1091
+ {
1092
+ return file_get_contents($path);
1093
+ }
1094
+
1095
+ /**
1096
+ * Write a string to a file
1097
+ *
1098
+ * @param string $path file path
1099
+ * @param string $content new file content
1100
+ *
1101
+ * @return bool
1102
+ * @author Dmitry (dio) Levashov
1103
+ **/
1104
+ protected function _filePutContents($path, $content)
1105
+ {
1106
+ return (file_put_contents($path, $content, LOCK_EX) !== false);
1107
+ }
1108
+
1109
+ /**
1110
+ * Detect available archivers
1111
+ *
1112
+ * @return void
1113
+ * @throws elFinderAbortException
1114
+ */
1115
+ protected function _checkArchivers()
1116
+ {
1117
+ $this->archivers = $this->getArchivers();
1118
+ return;
1119
+ }
1120
+
1121
+ /**
1122
+ * chmod availability
1123
+ *
1124
+ * @param string $path
1125
+ * @param string $mode
1126
+ *
1127
+ * @return bool
1128
+ */
1129
+ protected function _chmod($path, $mode)
1130
+ {
1131
+ $modeOct = is_string($mode) ? octdec($mode) : octdec(sprintf("%04o", $mode));
1132
+ return chmod($path, $modeOct);
1133
+ }
1134
+
1135
+ /**
1136
+ * Recursive symlinks search
1137
+ *
1138
+ * @param string $path file/dir path
1139
+ *
1140
+ * @return bool
1141
+ * @throws Exception
1142
+ * @author Dmitry (dio) Levashov
1143
+ */
1144
+ protected function _findSymlinks($path)
1145
+ {
1146
+ return self::localFindSymlinks($path);
1147
+ }
1148
+
1149
+ /**
1150
+ * Extract files from archive
1151
+ *
1152
+ * @param string $path archive path
1153
+ * @param array $arc archiver command and arguments (same as in $this->archivers)
1154
+ *
1155
+ * @return array|string|boolean
1156
+ * @throws elFinderAbortException
1157
+ * @author Dmitry (dio) Levashov,
1158
+ * @author Alexey Sukhotin
1159
+ */
1160
+ protected function _extract($path, $arc)
1161
+ {
1162
+
1163
+ if ($this->quarantine) {
1164
+
1165
+ $dir = $this->quarantine . DIRECTORY_SEPARATOR . md5(basename($path) . mt_rand());
1166
+ $archive = (isset($arc['toSpec']) || $arc['cmd'] === 'phpfunction') ? '' : $dir . DIRECTORY_SEPARATOR . basename($path);
1167
+
1168
+ if (!mkdir($dir)) {
1169
+ return false;
1170
+ }
1171
+
1172
+ // insurance unexpected shutdown
1173
+ register_shutdown_function(array($this, 'rmdirRecursive'), realpath($dir));
1174
+
1175
+ chmod($dir, 0777);
1176
+
1177
+ // copy in quarantine
1178
+ if (!is_readable($path) || ($archive && !copy($path, $archive))) {
1179
+ return false;
1180
+ }
1181
+
1182
+ // extract in quarantine
1183
+ try {
1184
+ $this->unpackArchive($path, $arc, $archive ? true : $dir);
1185
+ } catch(Exception $e) {
1186
+ return $this->setError($e->getMessage());
1187
+ }
1188
+
1189
+ // get files list
1190
+ try {
1191
+ $ls = self::localScandir($dir);
1192
+ } catch (Exception $e) {
1193
+ return false;
1194
+ }
1195
+
1196
+ // no files - extract error ?
1197
+ if (empty($ls)) {
1198
+ return false;
1199
+ }
1200
+
1201
+ $this->archiveSize = 0;
1202
+
1203
+ // find symlinks and check extracted items
1204
+ $checkRes = $this->checkExtractItems($dir);
1205
+ if ($checkRes['symlinks']) {
1206
+ self::localRmdirRecursive($dir);
1207
+ return $this->setError(array_merge($this->error, array(elFinder::ERROR_ARC_SYMLINKS)));
1208
+ }
1209
+ $this->archiveSize = $checkRes['totalSize'];
1210
+ if ($checkRes['rmNames']) {
1211
+ foreach ($checkRes['rmNames'] as $name) {
1212
+ $this->addError(elFinder::ERROR_SAVE, $name);
1213
+ }
1214
+ }
1215
+
1216
+ // check max files size
1217
+ if ($this->options['maxArcFilesSize'] > 0 && $this->options['maxArcFilesSize'] < $this->archiveSize) {
1218
+ $this->delTree($dir);
1219
+ return $this->setError(elFinder::ERROR_ARC_MAXSIZE);
1220
+ }
1221
+
1222
+ $extractTo = $this->extractToNewdir; // 'auto', ture or false
1223
+
1224
+ // archive contains one item - extract in archive dir
1225
+ $name = '';
1226
+ $src = $dir . DIRECTORY_SEPARATOR . $ls[0];
1227
+ if (($extractTo === 'auto' || !$extractTo) && count($ls) === 1 && is_file($src)) {
1228
+ $name = $ls[0];
1229
+ } else if ($extractTo === 'auto' || $extractTo) {
1230
+ // for several files - create new directory
1231
+ // create unique name for directory
1232
+ $src = $dir;
1233
+ $splits = elFinder::splitFileExtention(basename($path));
1234
+ $name = $splits[0];
1235
+ $test = dirname($path) . DIRECTORY_SEPARATOR . $name;
1236
+ if (file_exists($test) || is_link($test)) {
1237
+ $name = $this->uniqueName(dirname($path), $name, '-', false);
1238
+ }
1239
+ }
1240
+
1241
+ if ($name !== '') {
1242
+ $result = dirname($path) . DIRECTORY_SEPARATOR . $name;
1243
+
1244
+ if (!rename($src, $result)) {
1245
+ $this->delTree($dir);
1246
+ return false;
1247
+ }
1248
+ } else {
1249
+ $dstDir = dirname($path);
1250
+ $result = array();
1251
+ foreach ($ls as $name) {
1252
+ $target = $dstDir . DIRECTORY_SEPARATOR . $name;
1253
+ if (self::localMoveRecursive($dir . DIRECTORY_SEPARATOR . $name, $target, true, $this->options['copyJoin'])) {
1254
+ $result[] = $target;
1255
+ }
1256
+ }
1257
+ if (!$result) {
1258
+ $this->delTree($dir);
1259
+ return false;
1260
+ }
1261
+ }
1262
+
1263
+ is_dir($dir) && $this->delTree($dir);
1264
+
1265
+ return (is_array($result) || file_exists($result)) ? $result : false;
1266
+ }
1267
+ //TODO: Add return statement here
1268
+ return false;
1269
+ }
1270
+
1271
+ /**
1272
+ * Create archive and return its path
1273
+ *
1274
+ * @param string $dir target dir
1275
+ * @param array $files files names list
1276
+ * @param string $name archive name
1277
+ * @param array $arc archiver options
1278
+ *
1279
+ * @return string|bool
1280
+ * @throws elFinderAbortException
1281
+ * @author Dmitry (dio) Levashov,
1282
+ * @author Alexey Sukhotin
1283
+ */
1284
+ protected function _archive($dir, $files, $name, $arc)
1285
+ {
1286
+ return $this->makeArchive($dir, $files, $name, $arc);
1287
+ }
1288
+
1289
+ /******************** Over write functions *************************/
1290
+
1291
+ /**
1292
+ * File path of local server side work file path
1293
+ *
1294
+ * @param string $path
1295
+ *
1296
+ * @return string
1297
+ * @author Naoki Sawada
1298
+ */
1299
+ protected function getWorkFile($path)
1300
+ {
1301
+ return $path;
1302
+ }
1303
+
1304
+ /**
1305
+ * Delete dirctory trees
1306
+ *
1307
+ * @param string $localpath path need convert encoding to server encoding
1308
+ *
1309
+ * @return boolean
1310
+ * @throws elFinderAbortException
1311
+ * @author Naoki Sawada
1312
+ */
1313
+ protected function delTree($localpath)
1314
+ {
1315
+ return $this->rmdirRecursive($localpath);
1316
+ }
1317
+
1318
+ /**
1319
+ * Return fileinfo based on filename
1320
+ * For item ID based path file system
1321
+ * Please override if needed on each drivers
1322
+ *
1323
+ * @param string $path file cache
1324
+ *
1325
+ * @return array|boolean false
1326
+ */
1327
+ protected function isNameExists($path)
1328
+ {
1329
+ $exists = file_exists($this->convEncIn($path));
1330
+ // restore locale
1331
+ $this->convEncOut();
1332
+ return $exists ? $this->stat($path) : false;
1333
+ }
1334
+
1335
+ /******************** Over write (Optimized) functions *************************/
1336
+
1337
+ /**
1338
+ * Recursive files search
1339
+ *
1340
+ * @param string $path dir path
1341
+ * @param string $q search string
1342
+ * @param array $mimes
1343
+ *
1344
+ * @return array
1345
+ * @throws elFinderAbortException
1346
+ * @author Dmitry (dio) Levashov
1347
+ * @author Naoki Sawada
1348
+ */
1349
+ protected function doSearch($path, $q, $mimes)
1350
+ {
1351
+ if (!empty($this->doSearchCurrentQuery['matchMethod']) || $this->encoding || !class_exists('FilesystemIterator', false)) {
1352
+ // has custom match method or non UTF-8, use elFinderVolumeDriver::doSearch()
1353
+ return parent::doSearch($path, $q, $mimes);
1354
+ }
1355
+
1356
+ $result = array();
1357
+
1358
+ $timeout = $this->options['searchTimeout'] ? $this->searchStart + $this->options['searchTimeout'] : 0;
1359
+ if ($timeout && $timeout < time()) {
1360
+ $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($path)));
1361
+ return $result;
1362
+ }
1363
+ elFinder::extendTimeLimit($this->options['searchTimeout'] + 30);
1364
+
1365
+ $match = array();
1366
+ try {
1367
+ $iterator = new RecursiveIteratorIterator(
1368
+ new RecursiveCallbackFilterIterator(
1369
+ new RecursiveDirectoryIterator($path,
1370
+ FilesystemIterator::KEY_AS_PATHNAME |
1371
+ FilesystemIterator::SKIP_DOTS |
1372
+ ((defined('RecursiveDirectoryIterator::FOLLOW_SYMLINKS') && $this->options['followSymLinks']) ?
1373
+ RecursiveDirectoryIterator::FOLLOW_SYMLINKS : 0)
1374
+ ),
1375
+ array($this, 'localFileSystemSearchIteratorFilter')
1376
+ ),
1377
+ RecursiveIteratorIterator::SELF_FIRST,
1378
+ RecursiveIteratorIterator::CATCH_GET_CHILD
1379
+ );
1380
+ foreach ($iterator as $key => $node) {
1381
+ if ($timeout && ($this->error || $timeout < time())) {
1382
+ !$this->error && $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($node->getPath)));
1383
+ break;
1384
+ }
1385
+ if ($node->isDir()) {
1386
+ if ($this->stripos($node->getFilename(), $q) !== false) {
1387
+ $match[] = $key;
1388
+ }
1389
+ } else {
1390
+ $match[] = $key;
1391
+ }
1392
+ }
1393
+ } catch (Exception $e) {
1394
+ }
1395
+
1396
+ if ($match) {
1397
+ foreach ($match as $p) {
1398
+ if ($timeout && ($this->error || $timeout < time())) {
1399
+ !$this->error && $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode(dirname($p))));
1400
+ break;
1401
+ }
1402
+
1403
+ $stat = $this->stat($p);
1404
+
1405
+ if (!$stat) { // invalid links
1406
+ continue;
1407
+ }
1408
+
1409
+ if (!empty($stat['hidden']) || !$this->mimeAccepted($stat['mime'], $mimes)) {
1410
+ continue;
1411
+ }
1412
+
1413
+ if ((!$mimes || $stat['mime'] !== 'directory')) {
1414
+ $stat['path'] = $this->path($stat['hash']);
1415
+ if ($this->URL && !isset($stat['url'])) {
1416
+ $_path = str_replace(DIRECTORY_SEPARATOR, '/', substr($p, strlen($this->root) + 1));
1417
+ $stat['url'] = $this->URL . str_replace('%2F', '/', rawurlencode($_path));
1418
+ }
1419
+
1420
+ $result[] = $stat;
1421
+ }
1422
+ }
1423
+ }
1424
+
1425
+ return $result;
1426
+ }
1427
+
1428
+ /******************** Original local functions ************************
1429
+ *
1430
+ * @param $file
1431
+ * @param $key
1432
+ * @param $iterator
1433
+ *
1434
+ * @return bool
1435
+ */
1436
+
1437
+ public function localFileSystemSearchIteratorFilter($file, $key, $iterator)
1438
+ {
1439
+ /* @var FilesystemIterator $file */
1440
+ /* @var RecursiveDirectoryIterator $iterator */
1441
+ $name = $file->getFilename();
1442
+ if ($this->doSearchCurrentQuery['excludes']) {
1443
+ foreach ($this->doSearchCurrentQuery['excludes'] as $exclude) {
1444
+ if ($this->stripos($name, $exclude) !== false) {
1445
+ return false;
1446
+ }
1447
+ }
1448
+ }
1449
+ if ($iterator->hasChildren()) {
1450
+ if ($this->options['searchExDirReg'] && preg_match($this->options['searchExDirReg'], $key)) {
1451
+ return false;
1452
+ }
1453
+ return (bool)$this->attr($key, 'read', null, true);
1454
+ }
1455
+ return ($this->stripos($name, $this->doSearchCurrentQuery['q']) === false) ? false : true;
1456
+ }
1457
+
1458
+ /**
1459
+ * Creates a symbolic link
1460
+ *
1461
+ * @param string $target The target
1462
+ * @param string $link The link
1463
+ *
1464
+ * @return boolean ( result of symlink() )
1465
+ */
1466
+ protected function localFileSystemSymlink($target, $link)
1467
+ {
1468
+ $res = false;
1469
+ $errlev = error_reporting();
1470
+ error_reporting($errlev ^ E_WARNING);
1471
+ if ($res = symlink(realpath($target), $link)) {
1472
+ $res = is_readable($link);
1473
+ }
1474
+ error_reporting($errlev);
1475
+ return $res;
1476
+ }
1477
+ } // END class