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,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