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,1516 @@
1
+ <?php
2
+
3
+ use Kunnu\Dropbox\Dropbox;
4
+ use Kunnu\Dropbox\DropboxApp;
5
+ use Kunnu\Dropbox\DropboxFile;
6
+ use Kunnu\Dropbox\Exceptions\DropboxClientException;
7
+ use Kunnu\Dropbox\Models\FileMetadata;
8
+ use Kunnu\Dropbox\Models\FolderMetadata;
9
+
10
+ /**
11
+ * Simple elFinder driver for Dropbox
12
+ * kunalvarma05/dropbox-php-sdk:0.1.5 or above.
13
+ *
14
+ * @author Naoki Sawada
15
+ **/
16
+ class elFinderVolumeDropbox2 extends elFinderVolumeDriver
17
+ {
18
+ /**
19
+ * Driver id
20
+ * Must be started from letter and contains [a-z0-9]
21
+ * Used as part of volume id.
22
+ *
23
+ * @var string
24
+ **/
25
+ protected $driverId = 'db';
26
+
27
+ /**
28
+ * Dropbox service object.
29
+ *
30
+ * @var object
31
+ **/
32
+ protected $service = null;
33
+
34
+ /**
35
+ * Fetch options.
36
+ *
37
+ * @var string
38
+ */
39
+ private $FETCH_OPTIONS = [];
40
+
41
+ /**
42
+ * Directory for tmp files
43
+ * If not set driver will try to use tmbDir as tmpDir.
44
+ *
45
+ * @var string
46
+ **/
47
+ protected $tmp = '';
48
+
49
+ /**
50
+ * Net mount key.
51
+ *
52
+ * @var string
53
+ **/
54
+ public $netMountKey = '';
55
+
56
+ /**
57
+ * Constructor
58
+ * Extend options with required fields.
59
+ *
60
+ * @author Naoki Sawada
61
+ **/
62
+ public function __construct()
63
+ {
64
+ $opts = [
65
+ 'app_key' => '',
66
+ 'app_secret' => '',
67
+ 'access_token' => '',
68
+ 'aliasFormat' => '%s@Dropbox',
69
+ 'path' => '/',
70
+ 'separator' => '/',
71
+ 'acceptedName' => '#^[^\\\/]+$#',
72
+ 'rootCssClass' => 'elfinder-navbar-root-dropbox',
73
+ 'publishPermission' => [
74
+ 'requested_visibility' => 'public',
75
+ //'link_password' => '',
76
+ //'expires' => '',
77
+ ],
78
+ 'getThumbSize' => 'medium', // Available sizes: 'thumb', 'small', 'medium', 'large', 'huge'
79
+ ];
80
+ $this->options = array_merge($this->options, $opts);
81
+ $this->options['mimeDetect'] = 'internal';
82
+ }
83
+
84
+ /*********************************************************************/
85
+ /* ORIGINAL FUNCTIONS */
86
+ /*********************************************************************/
87
+
88
+ /**
89
+ * Get Parent ID, Item ID, Parent Path as an array from path.
90
+ *
91
+ * @param string $path
92
+ *
93
+ * @return array
94
+ */
95
+ protected function _db_splitPath($path)
96
+ {
97
+ $path = trim($path, '/');
98
+ if ($path === '') {
99
+ $dirname = '/';
100
+ $basename = '';
101
+ } else {
102
+ $pos = strrpos($path, '/');
103
+ if ($pos === false) {
104
+ $dirname = '/';
105
+ $basename = $path;
106
+ } else {
107
+ $dirname = '/' . substr($path, 0, $pos);
108
+ $basename = substr($path, $pos + 1);
109
+ }
110
+ }
111
+
112
+ return [$dirname, $basename];
113
+ }
114
+
115
+ /**
116
+ * Get dat(Dropbox metadata) from Dropbox.
117
+ *
118
+ * @param string $path
119
+ *
120
+ * @return boolean|object Dropbox metadata
121
+ */
122
+ private function _db_getFile($path)
123
+ {
124
+ if ($path === '/') {
125
+ return true;
126
+ }
127
+
128
+ $res = false;
129
+ try {
130
+ $file = $this->service->getMetadata($path, $this->FETCH_OPTIONS);
131
+ if ($file instanceof FolderMetadata || $file instanceof FileMetadata) {
132
+ $res = $file;
133
+ }
134
+
135
+ return $res;
136
+ } catch (DropboxClientException $e) {
137
+ return false;
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Parse line from Dropbox metadata output and return file stat (array).
143
+ *
144
+ * @param object $raw line from ftp_rawlist() output
145
+ *
146
+ * @return array
147
+ * @author Naoki Sawada
148
+ **/
149
+ protected function _db_parseRaw($raw)
150
+ {
151
+ $stat = [];
152
+ $isFolder = false;
153
+ if ($raw === true) {
154
+ // root folder
155
+ $isFolder = true;
156
+ $stat['name'] = '';
157
+ $stat['iid'] = '0';
158
+ }
159
+
160
+ $data = [];
161
+ if (is_object($raw)) {
162
+ $isFolder = $raw instanceof FolderMetadata;
163
+ $data = $raw->getData();
164
+ } elseif (is_array($raw)) {
165
+ $isFolder = $raw['.tag'] === 'folder';
166
+ $data = $raw;
167
+ }
168
+
169
+ if (isset($data['path_lower'])) {
170
+ $stat['path'] = $data['path_lower'];
171
+ }
172
+
173
+ if (isset($data['name'])) {
174
+ $stat['name'] = $data['name'];
175
+ }
176
+
177
+ if (isset($data['id'])) {
178
+ $stat['iid'] = substr($data['id'], 3);
179
+ }
180
+
181
+ if ($isFolder) {
182
+ $stat['mime'] = 'directory';
183
+ $stat['size'] = 0;
184
+ $stat['ts'] = 0;
185
+ $stat['dirs'] = -1;
186
+ } else {
187
+ $stat['size'] = isset($data['size']) ? (int)$data['size'] : 0;
188
+ if (isset($data['server_modified'])) {
189
+ $stat['ts'] = strtotime($data['server_modified']);
190
+ } elseif (isset($data['client_modified'])) {
191
+ $stat['ts'] = strtotime($data['client_modified']);
192
+ } else {
193
+ $stat['ts'] = 0;
194
+ }
195
+ $stat['url'] = '1';
196
+ }
197
+
198
+ return $stat;
199
+ }
200
+
201
+ /**
202
+ * Get thumbnail from Dropbox.
203
+ *
204
+ * @param string $path
205
+ * @param string $size
206
+ *
207
+ * @return string | boolean
208
+ */
209
+ protected function _db_getThumbnail($path)
210
+ {
211
+ try {
212
+ return $this->service->getThumbnail($path, $this->options['getThumbSize'])->getContents();
213
+ } catch (DropboxClientException $e) {
214
+ return false;
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Join dir name and file name(display name) and retur full path.
220
+ *
221
+ * @param string $dir
222
+ * @param string $displayName
223
+ *
224
+ * @return string
225
+ */
226
+ protected function _db_joinName($dir, $displayName)
227
+ {
228
+ return rtrim($dir, '/') . '/' . $displayName;
229
+ }
230
+
231
+ /**
232
+ * Get OAuth2 access token form OAuth1 tokens.
233
+ *
234
+ * @param string $app_key
235
+ * @param string $app_secret
236
+ * @param string $oauth1_token
237
+ * @param string $oauth1_secret
238
+ *
239
+ * @return string|false
240
+ */
241
+ public static function getTokenFromOauth1($app_key, $app_secret, $oauth1_token, $oauth1_secret)
242
+ {
243
+ $data = [
244
+ 'oauth1_token' => $oauth1_token,
245
+ 'oauth1_token_secret' => $oauth1_secret,
246
+ ];
247
+ $auth = base64_encode($app_key . ':' . $app_secret);
248
+
249
+ $ch = curl_init('https://api.dropboxapi.com/2/auth/token/from_oauth1');
250
+ curl_setopt($ch, CURLOPT_POST, true);
251
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
252
+ curl_setopt($ch, CURLOPT_HTTPHEADER, [
253
+ 'Content-Type: application/json',
254
+ 'Authorization: Basic ' . $auth,
255
+ ]);
256
+ curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
257
+ $result = curl_exec($ch);
258
+ curl_close($ch);
259
+
260
+ $res = $result ? json_decode($result, true) : [];
261
+
262
+ return isset($res['oauth2_token']) ? $res['oauth2_token'] : false;
263
+ }
264
+
265
+ /*********************************************************************/
266
+ /* EXTENDED FUNCTIONS */
267
+ /*********************************************************************/
268
+
269
+ /**
270
+ * Prepare
271
+ * Call from elFinder::netmout() before volume->mount().
272
+ *
273
+ * @return array
274
+ * @author Naoki Sawada
275
+ **/
276
+ public function netmountPrepare($options)
277
+ {
278
+ if (empty($options['app_key']) && defined('ELFINDER_DROPBOX_APPKEY')) {
279
+ $options['app_key'] = ELFINDER_DROPBOX_APPKEY;
280
+ }
281
+ if (empty($options['app_secret']) && defined('ELFINDER_DROPBOX_APPSECRET')) {
282
+ $options['app_secret'] = ELFINDER_DROPBOX_APPSECRET;
283
+ }
284
+
285
+ if (!isset($options['pass'])) {
286
+ $options['pass'] = '';
287
+ }
288
+
289
+ try {
290
+ $app = new DropboxApp($options['app_key'], $options['app_secret']);
291
+ $dropbox = new Dropbox($app);
292
+ $authHelper = $dropbox->getAuthHelper();
293
+
294
+ if ($options['pass'] === 'reauth') {
295
+ $options['pass'] = '';
296
+ $this->session->set('Dropbox2AuthParams', [])->set('Dropbox2Tokens', []);
297
+ } elseif ($options['pass'] === 'dropbox2') {
298
+ $options['pass'] = '';
299
+ }
300
+
301
+ $options = array_merge($this->session->get('Dropbox2AuthParams', []), $options);
302
+
303
+ if (!isset($options['tokens'])) {
304
+ $options['tokens'] = $this->session->get('Dropbox2Tokens', []);
305
+ $this->session->remove('Dropbox2Tokens');
306
+ }
307
+ $aToken = $options['tokens'];
308
+ if (!is_array($aToken) || !isset($aToken['access_token'])) {
309
+ $aToken = [];
310
+ }
311
+
312
+ $service = null;
313
+ if ($aToken) {
314
+ try {
315
+ $dropbox->setAccessToken($aToken['access_token']);
316
+ $this->session->set('Dropbox2AuthParams', $options);
317
+ } catch (DropboxClientException $e) {
318
+ $aToken = [];
319
+ $options['tokens'] = [];
320
+ if ($options['user'] !== 'init') {
321
+ $this->session->set('Dropbox2AuthParams', $options);
322
+
323
+ return ['exit' => true, 'error' => elFinder::ERROR_REAUTH_REQUIRE];
324
+ }
325
+ }
326
+ }
327
+
328
+ if ((isset($options['user']) && $options['user'] === 'init') || (isset($_GET['host']) && $_GET['host'] == '1')) {
329
+ if (empty($options['url'])) {
330
+ $options['url'] = elFinder::getConnectorUrl();
331
+ }
332
+
333
+ if (!empty($options['id'])) {
334
+ $callback = $options['url']
335
+ . (strpos($options['url'], '?') !== false? '&' : '?') . 'cmd=netmount&protocol=dropbox2&host=' . ($options['id'] === 'elfinder'? '1' : $options['id']);
336
+ }
337
+
338
+ $itpCare = isset($options['code']);
339
+ $code = $itpCare? $options['code'] : (isset($_GET['code'])? $_GET['code'] : '');
340
+ $state = $itpCare? $options['state'] : (isset($_GET['state'])? $_GET['state'] : '');
341
+ if (!$aToken && empty($code)) {
342
+ $url = $authHelper->getAuthUrl($callback);
343
+
344
+ $html = '<input id="elf-volumedriver-dropbox2-host-btn" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" value="{msg:btnApprove}" type="button">';
345
+ $html .= '<script>
346
+ $("#' . $options['id'] . '").elfinder("instance").trigger("netmount", {protocol: "dropbox2", mode: "makebtn", url: "' . $url . '"});
347
+ </script>';
348
+ if (empty($options['pass']) && $options['host'] !== '1') {
349
+ $options['pass'] = 'return';
350
+ $this->session->set('Dropbox2AuthParams', $options);
351
+
352
+ return ['exit' => true, 'body' => $html];
353
+ } else {
354
+ $out = [
355
+ 'node' => $options['id'],
356
+ 'json' => '{"protocol": "dropbox2", "mode": "makebtn", "body" : "' . str_replace($html, '"', '\\"') . '", "error" : "' . elFinder::ERROR_ACCESS_DENIED . '"}',
357
+ 'bind' => 'netmount',
358
+ ];
359
+
360
+ return ['exit' => 'callback', 'out' => $out];
361
+ }
362
+ } else {
363
+ if ($code && $state) {
364
+ if (!empty($options['id'])) {
365
+ // see https://github.com/kunalvarma05/dropbox-php-sdk/issues/115
366
+ $authHelper->getPersistentDataStore()->set('state', filter_var($state, FILTER_SANITIZE_STRING));
367
+ $tokenObj = $authHelper->getAccessToken($code, $state, $callback);
368
+ $options['tokens'] = [
369
+ 'access_token' => $tokenObj->getToken(),
370
+ 'uid' => $tokenObj->getUid(),
371
+ ];
372
+ unset($options['code'], $options['state']);
373
+ $this->session->set('Dropbox2Tokens', $options['tokens'])->set('Dropbox2AuthParams', $options);
374
+ $out = [
375
+ 'node' => $options['id'],
376
+ 'json' => '{"protocol": "dropbox2", "mode": "done", "reset": 1}',
377
+ 'bind' => 'netmount',
378
+ ];
379
+ } else {
380
+ $nodeid = ($_GET['host'] === '1')? 'elfinder' : $_GET['host'];
381
+ $out = [
382
+ 'node' => $nodeid,
383
+ 'json' => json_encode(array(
384
+ 'protocol' => 'dropbox2',
385
+ 'host' => $nodeid,
386
+ 'mode' => 'redirect',
387
+ 'options' => array(
388
+ 'id' => $nodeid,
389
+ 'code' => $code,
390
+ 'state' => $state
391
+ )
392
+ )),
393
+ 'bind' => 'netmount'
394
+ ];
395
+ }
396
+ if (!$itpCare) {
397
+ return array('exit' => 'callback', 'out' => $out);
398
+ } else {
399
+ return array('exit' => true, 'body' => $out['json']);
400
+ }
401
+ }
402
+ $path = $options['path'];
403
+ $folders = [];
404
+ $listFolderContents = $dropbox->listFolder($path);
405
+ $items = $listFolderContents->getItems();
406
+ foreach ($items as $item) {
407
+ $data = $item->getData();
408
+ if ($data['.tag'] === 'folder') {
409
+ $folders[$data['path_lower']] = $data['name'];
410
+ }
411
+ }
412
+ natcasesort($folders);
413
+
414
+ if ($options['pass'] === 'folders') {
415
+ return ['exit' => true, 'folders' => $folders];
416
+ }
417
+
418
+ $folders = ['/' => '/'] + $folders;
419
+ $folders = json_encode($folders);
420
+ $json = '{"protocol": "dropbox2", "mode": "done", "folders": ' . $folders . '}';
421
+ $options['pass'] = 'return';
422
+ $html = 'Dropbox.com';
423
+ $html .= '<script>
424
+ $("#' . $options['id'] . '").elfinder("instance").trigger("netmount", ' . $json . ');
425
+ </script>';
426
+ $this->session->set('Dropbox2AuthParams', $options);
427
+
428
+ return ['exit' => true, 'body' => $html];
429
+ }
430
+ }
431
+ } catch (DropboxClientException $e) {
432
+ $this->session->remove('Dropbox2AuthParams')->remove('Dropbox2Tokens');
433
+ if (empty($options['pass'])) {
434
+ return ['exit' => true, 'body' => '{msg:' . elFinder::ERROR_ACCESS_DENIED . '}' . ' ' . $e->getMessage()];
435
+ } else {
436
+ return ['exit' => true, 'error' => [elFinder::ERROR_ACCESS_DENIED, $e->getMessage()]];
437
+ }
438
+ }
439
+
440
+ if (!$aToken) {
441
+ return ['exit' => true, 'error' => elFinder::ERROR_REAUTH_REQUIRE];
442
+ }
443
+
444
+ if ($options['path'] === 'root') {
445
+ $options['path'] = '/';
446
+ }
447
+
448
+ try {
449
+ if ($options['path'] !== '/') {
450
+ $file = $dropbox->getMetadata($options['path']);
451
+ $name = $file->getName();
452
+ } else {
453
+ $name = 'root';
454
+ }
455
+ $options['alias'] = sprintf($this->options['aliasFormat'], $name);
456
+ } catch (DropboxClientException $e) {
457
+ return ['exit' => true, 'error' => $e->getMessage()];
458
+ }
459
+
460
+ foreach (['host', 'user', 'pass', 'id', 'offline'] as $key) {
461
+ unset($options[$key]);
462
+ }
463
+
464
+ return $options;
465
+ }
466
+
467
+ /**
468
+ * process of on netunmount
469
+ * Drop `Dropbox` & rm thumbs.
470
+ *
471
+ * @param array $options
472
+ *
473
+ * @return bool
474
+ */
475
+ public function netunmount($netVolumes, $key)
476
+ {
477
+ if ($tmbs = glob(rtrim($this->options['tmbPath'], '\\/') . DIRECTORY_SEPARATOR . $this->driverId . '_' . $this->options['tokens']['uid'] . '*.png')) {
478
+ foreach ($tmbs as $file) {
479
+ unlink($file);
480
+ }
481
+ }
482
+
483
+ return true;
484
+ }
485
+
486
+ /*********************************************************************/
487
+ /* INIT AND CONFIGURE */
488
+ /*********************************************************************/
489
+
490
+ /**
491
+ * Prepare Dropbox connection
492
+ * Connect to remote server and check if credentials are correct, if so, store the connection id in $this->service.
493
+ *
494
+ * @return bool
495
+ * @author Naoki Sawada
496
+ **/
497
+ protected function init()
498
+ {
499
+ if (empty($this->options['app_key'])) {
500
+ if (defined('ELFINDER_DROPBOX_APPKEY') && ELFINDER_DROPBOX_APPKEY) {
501
+ $this->options['app_key'] = ELFINDER_DROPBOX_APPKEY;
502
+ } else {
503
+ return $this->setError('Required option "app_key" is undefined.');
504
+ }
505
+ }
506
+ if (empty($this->options['app_secret'])) {
507
+ if (defined('ELFINDER_DROPBOX_APPSECRET') && ELFINDER_DROPBOX_APPSECRET) {
508
+ $this->options['app_secret'] = ELFINDER_DROPBOX_APPSECRET;
509
+ } else {
510
+ return $this->setError('Required option "app_secret" is undefined.');
511
+ }
512
+ }
513
+ if (isset($this->options['tokens']) && is_array($this->options['tokens']) && !empty($this->options['tokens']['access_token'])) {
514
+ $this->options['access_token'] = $this->options['tokens']['access_token'];
515
+ }
516
+ if (!$this->options['access_token']) {
517
+ return $this->setError('Required option "access_token" or "refresh_token" is undefined.');
518
+ }
519
+
520
+ try {
521
+ // make net mount key for network mount
522
+ $aToken = $this->options['access_token'];
523
+ $this->netMountKey = md5($aToken . '-' . $this->options['path']);
524
+
525
+ $errors = [];
526
+ if ($this->needOnline && !$this->service) {
527
+ $app = new DropboxApp($this->options['app_key'], $this->options['app_secret'], $aToken);
528
+ $this->service = new Dropbox($app);
529
+ // to check access_token
530
+ $this->service->getCurrentAccount();
531
+ }
532
+ } catch (DropboxClientException $e) {
533
+ $errors[] = 'Dropbox error: ' . $e->getMessage();
534
+ } catch (Exception $e) {
535
+ $errors[] = $e->getMessage();
536
+ }
537
+
538
+ if ($this->needOnline && !$this->service) {
539
+ $errors[] = 'Dropbox Service could not be loaded.';
540
+ }
541
+
542
+ if ($errors) {
543
+ return $this->setError($errors);
544
+ }
545
+
546
+ // normalize root path
547
+ $this->options['path'] = strtolower($this->options['path']);
548
+ if ($this->options['path'] == 'root') {
549
+ $this->options['path'] = '/';
550
+ }
551
+ $this->root = $this->options['path'] = $this->_normpath($this->options['path']);
552
+
553
+ if (empty($this->options['alias'])) {
554
+ $this->options['alias'] = sprintf($this->options['aliasFormat'], ($this->options['path'] === '/') ? 'Root' : $this->_basename($this->options['path']));
555
+ if (!empty($this->options['netkey'])) {
556
+ elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'alias', $this->options['alias']);
557
+ }
558
+ }
559
+
560
+ $this->rootName = $this->options['alias'];
561
+
562
+ if (!empty($this->options['tmpPath'])) {
563
+ if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($this->options['tmpPath'])) {
564
+ $this->tmp = $this->options['tmpPath'];
565
+ }
566
+ }
567
+
568
+ if (!$this->tmp && ($tmp = elFinder::getStaticVar('commonTempPath'))) {
569
+ $this->tmp = $tmp;
570
+ }
571
+
572
+ // This driver dose not support `syncChkAsTs`
573
+ $this->options['syncChkAsTs'] = false;
574
+
575
+ // 'lsPlSleep' minmum 10 sec
576
+ $this->options['lsPlSleep'] = max(10, $this->options['lsPlSleep']);
577
+
578
+ // enable command archive
579
+ $this->options['useRemoteArchive'] = true;
580
+
581
+ return true;
582
+ }
583
+
584
+ /**
585
+ * Configure after successfull mount.
586
+ *
587
+ * @author Naoki Sawada
588
+ * @throws elFinderAbortException
589
+ */
590
+ protected function configure()
591
+ {
592
+ parent::configure();
593
+
594
+ // fallback of $this->tmp
595
+ if (!$this->tmp && $this->tmbPathWritable) {
596
+ $this->tmp = $this->tmbPath;
597
+ }
598
+
599
+ if ($this->isMyReload()) {
600
+ //$this->_db_getDirectoryData(false);
601
+ }
602
+ }
603
+
604
+ /*********************************************************************/
605
+ /* FS API */
606
+ /*********************************************************************/
607
+
608
+ /**
609
+ * Close opened connection.
610
+ **/
611
+ public function umount()
612
+ {
613
+ }
614
+
615
+ /**
616
+ * Cache dir contents.
617
+ *
618
+ * @param string $path dir path
619
+ *
620
+ * @return
621
+ * @author Naoki Sawada
622
+ */
623
+ protected function cacheDir($path)
624
+ {
625
+ $this->dirsCache[$path] = [];
626
+ $hasDir = false;
627
+
628
+ $res = $this->service->listFolder($path, $this->FETCH_OPTIONS);
629
+
630
+ if ($res) {
631
+ $items = $res->getItems()->all();
632
+ foreach ($items as $raw) {
633
+ if ($stat = $this->_db_parseRaw($raw)) {
634
+ $mountPath = $this->_joinPath($path, $stat['name']);
635
+ $stat = $this->updateCache($mountPath, $stat);
636
+ if (empty($stat['hidden']) && $path !== $mountPath) {
637
+ if (!$hasDir && $stat['mime'] === 'directory') {
638
+ $hasDir = true;
639
+ }
640
+ $this->dirsCache[$path][] = $mountPath;
641
+ }
642
+ }
643
+ }
644
+ }
645
+
646
+ if (isset($this->sessionCache['subdirs'])) {
647
+ $this->sessionCache['subdirs'][$path] = $hasDir;
648
+ }
649
+
650
+ return $this->dirsCache[$path];
651
+ }
652
+
653
+ /**
654
+ * Recursive files search.
655
+ *
656
+ * @param string $path dir path
657
+ * @param string $q search string
658
+ * @param array $mimes
659
+ *
660
+ * @return array
661
+ * @throws elFinderAbortException
662
+ * @author Naoki Sawada
663
+ */
664
+ protected function doSearch($path, $q, $mimes)
665
+ {
666
+ if (!empty($this->doSearchCurrentQuery['matchMethod']) || $mimes) {
667
+ // has custom match method or mimes, use elFinderVolumeDriver::doSearch()
668
+ return parent::doSearch($path, $q, $mimes);
669
+ }
670
+
671
+ $timeout = $this->options['searchTimeout'] ? $this->searchStart + $this->options['searchTimeout'] : 0;
672
+
673
+ $searchRes = $this->service->search($path, $q, ['start' => 0, 'max_results' => 1000]);
674
+ $items = $searchRes->getItems();
675
+ $more = $searchRes->hasMoreItems();
676
+ while ($more) {
677
+ if ($timeout && $timeout < time()) {
678
+ $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->_path($path));
679
+ break;
680
+ }
681
+ $searchRes = $this->service->search($path, $q, ['start' => $searchRes->getCursor(), 'max_results' => 1000]);
682
+ $more = $searchRes->hasMoreItems();
683
+ $items = $items->merge($searchRes->getItems());
684
+ }
685
+
686
+ $result = [];
687
+ foreach ($items as $raw) {
688
+ if ($stat = $this->_db_parseRaw($raw->getMetadata())) {
689
+ $stat = $this->updateCache($stat['path'], $stat);
690
+ if (empty($stat['hidden'])) {
691
+ $result[] = $stat;
692
+ }
693
+ }
694
+ }
695
+
696
+ return $result;
697
+ }
698
+
699
+ /**
700
+ * Copy file/recursive copy dir only in current volume.
701
+ * Return new file path or false.
702
+ *
703
+ * @param string $src source path
704
+ * @param string $dst destination dir path
705
+ * @param string $name new file name (optionaly)
706
+ *
707
+ * @return string|false
708
+ * @throws elFinderAbortException
709
+ * @author Naoki Sawada
710
+ */
711
+ protected function copy($src, $dst, $name)
712
+ {
713
+ $srcStat = $this->stat($src);
714
+ $target = $this->_joinPath($dst, $name);
715
+ $tgtStat = $this->stat($target);
716
+ if ($tgtStat) {
717
+ if ($srcStat['mime'] === 'directory') {
718
+ return parent::copy($src, $dst, $name);
719
+ } else {
720
+ $this->_unlink($target);
721
+ }
722
+ }
723
+ $this->clearcache();
724
+ if ($res = $this->_copy($src, $dst, $name)) {
725
+ $this->added[] = $this->stat($target);
726
+ $res = $target;
727
+ }
728
+
729
+ return $res;
730
+ }
731
+
732
+ /**
733
+ * Remove file/ recursive remove dir.
734
+ *
735
+ * @param string $path file path
736
+ * @param bool $force try to remove even if file locked
737
+ * @param bool $recursive
738
+ *
739
+ * @return bool
740
+ * @throws elFinderAbortException
741
+ * @author Naoki Sawada
742
+ */
743
+ protected function remove($path, $force = false, $recursive = false)
744
+ {
745
+ $stat = $this->stat($path);
746
+ $stat['realpath'] = $path;
747
+ $this->rmTmb($stat);
748
+ $this->clearcache();
749
+
750
+ if (empty($stat)) {
751
+ return $this->setError(elFinder::ERROR_RM, $this->_path($path), elFinder::ERROR_FILE_NOT_FOUND);
752
+ }
753
+
754
+ if (!$force && !empty($stat['locked'])) {
755
+ return $this->setError(elFinder::ERROR_LOCKED, $this->_path($path));
756
+ }
757
+
758
+ if ($stat['mime'] == 'directory') {
759
+ if (!$recursive && !$this->_rmdir($path)) {
760
+ return $this->setError(elFinder::ERROR_RM, $this->_path($path));
761
+ }
762
+ } else {
763
+ if (!$recursive && !$this->_unlink($path)) {
764
+ return $this->setError(elFinder::ERROR_RM, $this->_path($path));
765
+ }
766
+ }
767
+
768
+ $this->removed[] = $stat;
769
+
770
+ return true;
771
+ }
772
+
773
+ /**
774
+ * Create thumnbnail and return it's URL on success.
775
+ *
776
+ * @param string $path file path
777
+ * @param $stat
778
+ *
779
+ * @return string|false
780
+ * @throws ImagickException
781
+ * @throws elFinderAbortException
782
+ * @author Naoki Sawada
783
+ */
784
+ protected function createTmb($path, $stat)
785
+ {
786
+ if (!$stat || !$this->canCreateTmb($path, $stat)) {
787
+ return false;
788
+ }
789
+
790
+ $name = $this->tmbname($stat);
791
+ $tmb = $this->tmbPath . DIRECTORY_SEPARATOR . $name;
792
+
793
+ // copy image into tmbPath so some drivers does not store files on local fs
794
+ if (!$data = $this->_db_getThumbnail($path)) {
795
+ return false;
796
+ }
797
+ if (!file_put_contents($tmb, $data)) {
798
+ return false;
799
+ }
800
+
801
+ $tmbSize = $this->tmbSize;
802
+
803
+ if (($s = getimagesize($tmb)) == false) {
804
+ return false;
805
+ }
806
+
807
+ $result = true;
808
+
809
+ /* If image smaller or equal thumbnail size - just fitting to thumbnail square */
810
+ if ($s[0] <= $tmbSize && $s[1] <= $tmbSize) {
811
+ $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png');
812
+ } else {
813
+ if ($this->options['tmbCrop']) {
814
+
815
+ /* Resize and crop if image bigger than thumbnail */
816
+ if (!(($s[0] > $tmbSize && $s[1] <= $tmbSize) || ($s[0] <= $tmbSize && $s[1] > $tmbSize)) || ($s[0] > $tmbSize && $s[1] > $tmbSize)) {
817
+ $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, false, 'png');
818
+ }
819
+
820
+ if ($result && ($s = getimagesize($tmb)) != false) {
821
+ $x = $s[0] > $tmbSize ? intval(($s[0] - $tmbSize) / 2) : 0;
822
+ $y = $s[1] > $tmbSize ? intval(($s[1] - $tmbSize) / 2) : 0;
823
+ $result = $this->imgCrop($tmb, $tmbSize, $tmbSize, $x, $y, 'png');
824
+ }
825
+ } else {
826
+ $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, true, 'png');
827
+ }
828
+
829
+ if ($result) {
830
+ $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png');
831
+
832
+ }
833
+ }
834
+
835
+ if (!$result) {
836
+ unlink($tmb);
837
+
838
+ return false;
839
+ }
840
+
841
+ return $name;
842
+ }
843
+
844
+ /**
845
+ * Return thumbnail file name for required file.
846
+ *
847
+ * @param array $stat file stat
848
+ *
849
+ * @return string
850
+ * @author Naoki Sawada
851
+ **/
852
+ protected function tmbname($stat)
853
+ {
854
+ $name = $this->driverId . '_';
855
+ if (isset($this->options['tokens']) && is_array($this->options['tokens'])) {
856
+ $name .= $this->options['tokens']['uid'];
857
+ }
858
+
859
+ return $name . md5($stat['iid']) . $stat['ts'] . '.png';
860
+ }
861
+
862
+ /**
863
+ * Return content URL (for netmout volume driver)
864
+ * If file.url == 1 requests from JavaScript client with XHR.
865
+ *
866
+ * @param string $hash file hash
867
+ * @param array $options options array
868
+ *
869
+ * @return bool|string
870
+ * @author Naoki Sawada
871
+ */
872
+ public function getContentUrl($hash, $options = [])
873
+ {
874
+ if (!empty($options['onetime']) && $this->options['onetimeUrl']) {
875
+ return parent::getContentUrl($hash, $options);
876
+ }
877
+ if (!empty($options['temporary'])) {
878
+ // try make temporary file
879
+ $url = parent::getContentUrl($hash, $options);
880
+ if ($url) {
881
+ return $url;
882
+ }
883
+ }
884
+ $file = $this->file($hash);
885
+ if (($file = $this->file($hash)) !== false && (!$file['url'] || $file['url'] == 1)) {
886
+ $path = $this->decode($hash);
887
+ $url = '';
888
+ try {
889
+ $res = $this->service->postToAPI('/sharing/list_shared_links', ['path' => $path, 'direct_only' => true])->getDecodedBody();
890
+ if ($res && !empty($res['links'])) {
891
+ foreach ($res['links'] as $link) {
892
+ if (isset($link['link_permissions'])
893
+ && isset($link['link_permissions']['requested_visibility'])
894
+ && $link['link_permissions']['requested_visibility']['.tag'] === $this->options['publishPermission']['requested_visibility']) {
895
+ $url = $link['url'];
896
+ break;
897
+ }
898
+ }
899
+ }
900
+ if (!$url) {
901
+ $res = $this->service->postToAPI('/sharing/create_shared_link_with_settings', ['path' => $path, 'settings' => $this->options['publishPermission']])->getDecodedBody();
902
+ if (isset($res['url'])) {
903
+ $url = $res['url'];
904
+ }
905
+ }
906
+ if ($url) {
907
+ $url = str_replace('www.dropbox.com', 'dl.dropboxusercontent.com', $url);
908
+ $url = str_replace('?dl=0', '', $url);
909
+
910
+ return $url;
911
+ }
912
+ } catch (DropboxClientException $e) {
913
+ return $this->setError('Dropbox error: ' . $e->getMessage());
914
+ }
915
+ }
916
+
917
+ return false;
918
+ }
919
+
920
+ /**
921
+ * Return debug info for client.
922
+ *
923
+ * @return array
924
+ **/
925
+ public function debug()
926
+ {
927
+ $res = parent::debug();
928
+ if (!empty($this->options['netkey']) && isset($this->options['tokens']) && !empty($this->options['tokens']['uid'])) {
929
+ $res['Dropbox uid'] = $this->options['tokens']['uid'];
930
+ $res['access_token'] = $this->options['tokens']['access_token'];
931
+ }
932
+
933
+ return $res;
934
+ }
935
+
936
+ /*********************** paths/urls *************************/
937
+
938
+ /**
939
+ * Return parent directory path.
940
+ *
941
+ * @param string $path file path
942
+ *
943
+ * @return string
944
+ * @author Naoki Sawada
945
+ **/
946
+ protected function _dirname($path)
947
+ {
948
+ list($dirname) = $this->_db_splitPath($path);
949
+
950
+ return $dirname;
951
+ }
952
+
953
+ /**
954
+ * Return file name.
955
+ *
956
+ * @param string $path file path
957
+ *
958
+ * @return string
959
+ * @author Naoki Sawada
960
+ **/
961
+ protected function _basename($path)
962
+ {
963
+ list(, $basename) = $this->_db_splitPath($path);
964
+
965
+ return $basename;
966
+ }
967
+
968
+ /**
969
+ * Join dir name and file name and retur full path.
970
+ *
971
+ * @param string $dir
972
+ * @param string $name
973
+ *
974
+ * @return string
975
+ * @author Dmitry (dio) Levashov
976
+ **/
977
+ protected function _joinPath($dir, $name)
978
+ {
979
+ return rtrim($dir, '/') . '/' . strtolower($name);
980
+ }
981
+
982
+ /**
983
+ * Return normalized path, this works the same as os.path.normpath() in Python.
984
+ *
985
+ * @param string $path path
986
+ *
987
+ * @return string
988
+ * @author Naoki Sawada
989
+ **/
990
+ protected function _normpath($path)
991
+ {
992
+ return '/' . ltrim($path, '/');
993
+ }
994
+
995
+ /**
996
+ * Return file path related to root dir.
997
+ *
998
+ * @param string $path file path
999
+ *
1000
+ * @return string
1001
+ * @author Dmitry (dio) Levashov
1002
+ **/
1003
+ protected function _relpath($path)
1004
+ {
1005
+ if ($path === $this->root) {
1006
+ return '';
1007
+ } else {
1008
+ return ltrim(substr($path, strlen($this->root)), '/');
1009
+ }
1010
+ }
1011
+
1012
+ /**
1013
+ * Convert path related to root dir into real path.
1014
+ *
1015
+ * @param string $path file path
1016
+ *
1017
+ * @return string
1018
+ * @author Naoki Sawada
1019
+ **/
1020
+ protected function _abspath($path)
1021
+ {
1022
+ if ($path === '/') {
1023
+ return $this->root;
1024
+ } else {
1025
+ return $this->_joinPath($this->root, $path);
1026
+ }
1027
+ }
1028
+
1029
+ /**
1030
+ * Return fake path started from root dir.
1031
+ *
1032
+ * @param string $path file path
1033
+ *
1034
+ * @return string
1035
+ * @author Naoki Sawada
1036
+ **/
1037
+ protected function _path($path)
1038
+ {
1039
+ $path = $this->_normpath(substr($path, strlen($this->root)));
1040
+
1041
+ return $path;
1042
+ }
1043
+
1044
+ /**
1045
+ * Return true if $path is children of $parent.
1046
+ *
1047
+ * @param string $path path to check
1048
+ * @param string $parent parent path
1049
+ *
1050
+ * @return bool
1051
+ * @author Naoki Sawada
1052
+ **/
1053
+ protected function _inpath($path, $parent)
1054
+ {
1055
+ return $path == $parent || strpos($path, $parent . '/') === 0;
1056
+ }
1057
+
1058
+ /***************** file stat ********************/
1059
+ /**
1060
+ * Return stat for given path.
1061
+ * Stat contains following fields:
1062
+ * - (int) size file size in b. required
1063
+ * - (int) ts file modification time in unix time. required
1064
+ * - (string) mime mimetype. required for folders, others - optionally
1065
+ * - (bool) read read permissions. required
1066
+ * - (bool) write write permissions. required
1067
+ * - (bool) locked is object locked. optionally
1068
+ * - (bool) hidden is object hidden. optionally
1069
+ * - (string) alias for symlinks - link target path relative to root path. optionally
1070
+ * - (string) target for symlinks - link target path. optionally.
1071
+ * If file does not exists - returns empty array or false.
1072
+ *
1073
+ * @param string $path file path
1074
+ *
1075
+ * @return array|false
1076
+ * @author Dmitry (dio) Levashov
1077
+ **/
1078
+ protected function _stat($path)
1079
+ {
1080
+ if ($raw = $this->_db_getFile($path)) {
1081
+ return $this->_db_parseRaw($raw);
1082
+ }
1083
+
1084
+ return false;
1085
+ }
1086
+
1087
+ /**
1088
+ * Return true if path is dir and has at least one childs directory.
1089
+ *
1090
+ * @param string $path dir path
1091
+ *
1092
+ * @return bool
1093
+ * @author Naoki Sawada
1094
+ **/
1095
+ protected function _subdirs($path)
1096
+ {
1097
+ $hasdir = false;
1098
+
1099
+ try {
1100
+ $res = $this->service->listFolder($path);
1101
+ if ($res) {
1102
+ $items = $res->getItems();
1103
+ foreach ($items as $raw) {
1104
+ if ($raw instanceof FolderMetadata) {
1105
+ $hasdir = true;
1106
+ break;
1107
+ }
1108
+ }
1109
+ }
1110
+ } catch (DropboxClientException $e) {
1111
+ $this->setError('Dropbox error: ' . $e->getMessage());
1112
+ }
1113
+
1114
+ return $hasdir;
1115
+ }
1116
+
1117
+ /**
1118
+ * Return object width and height
1119
+ * Ususaly used for images, but can be realize for video etc...
1120
+ *
1121
+ * @param string $path file path
1122
+ * @param string $mime file mime type
1123
+ *
1124
+ * @return string
1125
+ * @throws ImagickException
1126
+ * @throws elFinderAbortException
1127
+ * @author Naoki Sawada
1128
+ */
1129
+ protected function _dimensions($path, $mime)
1130
+ {
1131
+ if (strpos($mime, 'image') !== 0) {
1132
+ return '';
1133
+ }
1134
+ $ret = '';
1135
+
1136
+ if ($data = $this->_getContents($path)) {
1137
+ $tmp = $this->getTempFile();
1138
+ file_put_contents($tmp, $data);
1139
+ $size = getimagesize($tmp);
1140
+ if ($size) {
1141
+ $ret = array('dim' => $size[0] . 'x' . $size[1]);
1142
+ $srcfp = fopen($tmp, 'rb');
1143
+ $target = isset(elFinder::$currentArgs['target'])? elFinder::$currentArgs['target'] : '';
1144
+ if ($subImgLink = $this->getSubstituteImgLink($target, $size, $srcfp)) {
1145
+ $ret['url'] = $subImgLink;
1146
+ }
1147
+ }
1148
+ }
1149
+
1150
+ return $ret;
1151
+ }
1152
+
1153
+ /******************** file/dir content *********************/
1154
+
1155
+ /**
1156
+ * Return files list in directory.
1157
+ *
1158
+ * @param string $path dir path
1159
+ *
1160
+ * @return array
1161
+ * @author Naoki Sawada
1162
+ **/
1163
+ protected function _scandir($path)
1164
+ {
1165
+ return isset($this->dirsCache[$path])
1166
+ ? $this->dirsCache[$path]
1167
+ : $this->cacheDir($path);
1168
+ }
1169
+
1170
+ /**
1171
+ * Open file and return file pointer.
1172
+ *
1173
+ * @param string $path file path
1174
+ * @param bool $write open file for writing
1175
+ *
1176
+ * @return resource|false
1177
+ * @author Naoki Sawada
1178
+ **/
1179
+ protected function _fopen($path, $mode = 'rb')
1180
+ {
1181
+ if ($mode === 'rb' || $mode === 'r') {
1182
+ if ($link = $this->service->getTemporaryLink($path)) {
1183
+ $access_token = $this->service->getAccessToken();
1184
+ if ($access_token) {
1185
+ $data = array(
1186
+ 'target' => $link->getLink(),
1187
+ 'headers' => array('Authorization: Bearer ' . $access_token),
1188
+ );
1189
+
1190
+ // to support range request
1191
+ if (func_num_args() > 2) {
1192
+ $opts = func_get_arg(2);
1193
+ } else {
1194
+ $opts = array();
1195
+ }
1196
+ if (!empty($opts['httpheaders'])) {
1197
+ $data['headers'] = array_merge($opts['httpheaders'], $data['headers']);
1198
+ }
1199
+
1200
+ return elFinder::getStreamByUrl($data);
1201
+ }
1202
+ }
1203
+ }
1204
+
1205
+ return false;
1206
+ }
1207
+
1208
+ /**
1209
+ * Close opened file.
1210
+ *
1211
+ * @param resource $fp file pointer
1212
+ *
1213
+ * @return bool
1214
+ * @author Naoki Sawada
1215
+ **/
1216
+ protected function _fclose($fp, $path = '')
1217
+ {
1218
+ is_resource($fp) && fclose($fp);
1219
+ }
1220
+
1221
+ /******************** file/dir manipulations *************************/
1222
+
1223
+ /**
1224
+ * Create dir and return created dir path or false on failed.
1225
+ *
1226
+ * @param string $path parent dir path
1227
+ * @param string $name new directory name
1228
+ *
1229
+ * @return string|bool
1230
+ * @author Naoki Sawada
1231
+ **/
1232
+ protected function _mkdir($path, $name)
1233
+ {
1234
+ try {
1235
+ return $this->service->createFolder($this->_db_joinName($path, $name))->getPathLower();
1236
+ } catch (DropboxClientException $e) {
1237
+ return $this->setError('Dropbox error: ' . $e->getMessage());
1238
+ }
1239
+ }
1240
+
1241
+ /**
1242
+ * Create file and return it's path or false on failed.
1243
+ *
1244
+ * @param string $path parent dir path
1245
+ * @param string $name new file name
1246
+ *
1247
+ * @return string|bool
1248
+ * @author Naoki Sawada
1249
+ **/
1250
+ protected function _mkfile($path, $name)
1251
+ {
1252
+ return $this->_save($this->tmpfile(), $path, $name, []);
1253
+ }
1254
+
1255
+ /**
1256
+ * Create symlink. FTP driver does not support symlinks.
1257
+ *
1258
+ * @param string $target link target
1259
+ * @param string $path symlink path
1260
+ *
1261
+ * @return bool
1262
+ * @author Naoki Sawada
1263
+ **/
1264
+ protected function _symlink($target, $path, $name)
1265
+ {
1266
+ return false;
1267
+ }
1268
+
1269
+ /**
1270
+ * Copy file into another file.
1271
+ *
1272
+ * @param string $source source file path
1273
+ * @param string $targetDir target directory path
1274
+ * @param string $name new file name
1275
+ *
1276
+ * @return bool
1277
+ * @author Naoki Sawada
1278
+ **/
1279
+ protected function _copy($source, $targetDir, $name)
1280
+ {
1281
+ try {
1282
+ $this->service->copy($source, $this->_db_joinName($targetDir, $name))->getPathLower();
1283
+ } catch (DropboxClientException $e) {
1284
+ return $this->setError('Dropbox error: ' . $e->getMessage());
1285
+ }
1286
+
1287
+ return true;
1288
+ }
1289
+
1290
+ /**
1291
+ * Move file into another parent dir.
1292
+ * Return new file path or false.
1293
+ *
1294
+ * @param string $source source file path
1295
+ * @param string $target target dir path
1296
+ * @param string $name file name
1297
+ *
1298
+ * @return string|bool
1299
+ * @author Naoki Sawada
1300
+ **/
1301
+ protected function _move($source, $targetDir, $name)
1302
+ {
1303
+ try {
1304
+ return $this->service->move($source, $this->_db_joinName($targetDir, $name))->getPathLower();
1305
+ } catch (DropboxClientException $e) {
1306
+ return $this->setError('Dropbox error: ' . $e->getMessage());
1307
+ }
1308
+ }
1309
+
1310
+ /**
1311
+ * Remove file.
1312
+ *
1313
+ * @param string $path file path
1314
+ *
1315
+ * @return bool
1316
+ * @author Naoki Sawada
1317
+ **/
1318
+ protected function _unlink($path)
1319
+ {
1320
+ try {
1321
+ $this->service->delete($path);
1322
+
1323
+ return true;
1324
+ } catch (DropboxClientException $e) {
1325
+ return $this->setError('Dropbox error: ' . $e->getMessage());
1326
+ }
1327
+
1328
+ return true;
1329
+ }
1330
+
1331
+ /**
1332
+ * Remove dir.
1333
+ *
1334
+ * @param string $path dir path
1335
+ *
1336
+ * @return bool
1337
+ * @author Naoki Sawada
1338
+ **/
1339
+ protected function _rmdir($path)
1340
+ {
1341
+ return $this->_unlink($path);
1342
+ }
1343
+
1344
+ /**
1345
+ * Create new file and write into it from file pointer.
1346
+ * Return new file path or false on error.
1347
+ *
1348
+ * @param resource $fp file pointer
1349
+ * @param string $dir target dir path
1350
+ * @param string $name file name
1351
+ * @param array $stat file stat (required by some virtual fs)
1352
+ *
1353
+ * @return bool|string
1354
+ * @author Naoki Sawada
1355
+ **/
1356
+ protected function _save($fp, $path, $name, $stat)
1357
+ {
1358
+ try {
1359
+ $info = stream_get_meta_data($fp);
1360
+ if (empty($info['uri']) || preg_match('#^[a-z0-9.-]+://#', $info['uri'])) {
1361
+ if ($filepath = $this->getTempFile()) {
1362
+ $_fp = fopen($filepath, 'wb');
1363
+ stream_copy_to_stream($fp, $_fp);
1364
+ fclose($_fp);
1365
+ }
1366
+ } else {
1367
+ $filepath = $info['uri'];
1368
+ }
1369
+ $dropboxFile = new DropboxFile($filepath);
1370
+ if ($name === '') {
1371
+ $fullpath = $path;
1372
+ } else {
1373
+ $fullpath = $this->_db_joinName($path, $name);
1374
+ }
1375
+
1376
+ return $this->service->upload($dropboxFile, $fullpath, ['mode' => 'overwrite'])->getPathLower();
1377
+ } catch (DropboxClientException $e) {
1378
+ return $this->setError('Dropbox error: ' . $e->getMessage());
1379
+ }
1380
+ }
1381
+
1382
+ /**
1383
+ * Get file contents.
1384
+ *
1385
+ * @param string $path file path
1386
+ *
1387
+ * @return string|false
1388
+ * @author Naoki Sawada
1389
+ **/
1390
+ protected function _getContents($path)
1391
+ {
1392
+ $contents = '';
1393
+
1394
+ try {
1395
+ $file = $this->service->download($path);
1396
+ $contents = $file->getContents();
1397
+ } catch (Exception $e) {
1398
+ return $this->setError('Dropbox error: ' . $e->getMessage());
1399
+ }
1400
+
1401
+ return $contents;
1402
+ }
1403
+
1404
+ /**
1405
+ * Write a string to a file.
1406
+ *
1407
+ * @param string $path file path
1408
+ * @param string $content new file content
1409
+ *
1410
+ * @return bool
1411
+ * @author Naoki Sawada
1412
+ **/
1413
+ protected function _filePutContents($path, $content)
1414
+ {
1415
+ $res = false;
1416
+
1417
+ if ($local = $this->getTempFile($path)) {
1418
+ if (file_put_contents($local, $content, LOCK_EX) !== false
1419
+ && ($fp = fopen($local, 'rb'))) {
1420
+ clearstatcache();
1421
+ $name = '';
1422
+ $stat = $this->stat($path);
1423
+ if ($stat) {
1424
+ // keep real name
1425
+ $path = $this->_dirname($path);
1426
+ $name = $stat['name'];
1427
+ }
1428
+ $res = $this->_save($fp, $path, $name, []);
1429
+ fclose($fp);
1430
+ }
1431
+ file_exists($local) && unlink($local);
1432
+ }
1433
+
1434
+ return $res;
1435
+ }
1436
+
1437
+ /**
1438
+ * Detect available archivers.
1439
+ **/
1440
+ protected function _checkArchivers()
1441
+ {
1442
+ // die('Not yet implemented. (_checkArchivers)');
1443
+ return [];
1444
+ }
1445
+
1446
+ /**
1447
+ * chmod implementation.
1448
+ *
1449
+ * @return bool
1450
+ **/
1451
+ protected function _chmod($path, $mode)
1452
+ {
1453
+ return false;
1454
+ }
1455
+
1456
+ /**
1457
+ * Unpack archive.
1458
+ *
1459
+ * @param string $path archive path
1460
+ * @param array $arc archiver command and arguments (same as in $this->archivers)
1461
+ *
1462
+ * @return true
1463
+ * @author Dmitry (dio) Levashov
1464
+ * @author Alexey Sukhotin
1465
+ **/
1466
+ protected function _unpack($path, $arc)
1467
+ {
1468
+ die('Not yet implemented. (_unpack)');
1469
+ //return false;
1470
+ }
1471
+
1472
+ /**
1473
+ * Recursive symlinks search.
1474
+ *
1475
+ * @param string $path file/dir path
1476
+ *
1477
+ * @return bool
1478
+ * @author Dmitry (dio) Levashov
1479
+ **/
1480
+ protected function _findSymlinks($path)
1481
+ {
1482
+ die('Not yet implemented. (_findSymlinks)');
1483
+ }
1484
+
1485
+ /**
1486
+ * Extract files from archive.
1487
+ *
1488
+ * @param string $path archive path
1489
+ * @param array $arc archiver command and arguments (same as in $this->archivers)
1490
+ *
1491
+ * @return true
1492
+ * @author Dmitry (dio) Levashov,
1493
+ * @author Alexey Sukhotin
1494
+ **/
1495
+ protected function _extract($path, $arc)
1496
+ {
1497
+ die('Not yet implemented. (_extract)');
1498
+ }
1499
+
1500
+ /**
1501
+ * Create archive and return its path.
1502
+ *
1503
+ * @param string $dir target dir
1504
+ * @param array $files files names list
1505
+ * @param string $name archive name
1506
+ * @param array $arc archiver options
1507
+ *
1508
+ * @return string|bool
1509
+ * @author Dmitry (dio) Levashov,
1510
+ * @author Alexey Sukhotin
1511
+ **/
1512
+ protected function _archive($dir, $files, $name, $arc)
1513
+ {
1514
+ die('Not yet implemented. (_archive)');
1515
+ }
1516
+ } // END class