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,2131 @@
1
+ <?php
2
+
3
+ /**
4
+ * Simple elFinder driver for OneDrive
5
+ * onedrive api v5.0.
6
+ *
7
+ * @author Dmitry (dio) Levashov
8
+ * @author Cem (discofever)
9
+ **/
10
+ class elFinderVolumeOneDrive extends elFinderVolumeDriver
11
+ {
12
+ /**
13
+ * Driver id
14
+ * Must be started from letter and contains [a-z0-9]
15
+ * Used as part of volume id.
16
+ *
17
+ * @var string
18
+ **/
19
+ protected $driverId = 'od';
20
+
21
+ /**
22
+ * @var string The base URL for API requests
23
+ **/
24
+ const API_URL = 'https://graph.microsoft.com/v1.0/me/drive/items/';
25
+
26
+ /**
27
+ * @var string The base URL for authorization requests
28
+ */
29
+ const AUTH_URL = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize';
30
+
31
+ /**
32
+ * @var string The base URL for token requests
33
+ */
34
+ const TOKEN_URL = 'https://login.microsoftonline.com/common/oauth2/v2.0/token';
35
+
36
+ /**
37
+ * OneDrive token object.
38
+ *
39
+ * @var object
40
+ **/
41
+ protected $token = null;
42
+
43
+ /**
44
+ * Directory for tmp files
45
+ * If not set driver will try to use tmbDir as tmpDir.
46
+ *
47
+ * @var string
48
+ **/
49
+ protected $tmp = '';
50
+
51
+ /**
52
+ * Net mount key.
53
+ *
54
+ * @var string
55
+ **/
56
+ public $netMountKey = '';
57
+
58
+ /**
59
+ * Thumbnail prefix.
60
+ *
61
+ * @var string
62
+ **/
63
+ protected $tmbPrefix = '';
64
+
65
+ /**
66
+ * hasCache by folders.
67
+ *
68
+ * @var array
69
+ **/
70
+ protected $HasdirsCache = array();
71
+
72
+ /**
73
+ * Query options of API call.
74
+ *
75
+ * @var array
76
+ */
77
+ protected $queryOptions = array();
78
+
79
+ /**
80
+ * Current token expires
81
+ *
82
+ * @var integer
83
+ **/
84
+ private $expires;
85
+
86
+ /**
87
+ * Path to access token file for permanent mount
88
+ *
89
+ * @var string
90
+ */
91
+ private $aTokenFile = '';
92
+
93
+ /**
94
+ * Constructor
95
+ * Extend options with required fields.
96
+ *
97
+ * @author Dmitry (dio) Levashov
98
+ * @author Cem (DiscoFever)
99
+ **/
100
+ public function __construct()
101
+ {
102
+ $opts = array(
103
+ 'client_id' => '',
104
+ 'client_secret' => '',
105
+ 'accessToken' => '',
106
+ 'root' => 'OneDrive.com',
107
+ 'OneDriveApiClient' => '',
108
+ 'path' => '/',
109
+ 'separator' => '/',
110
+ 'tmbPath' => '',
111
+ 'tmbURL' => '',
112
+ 'tmpPath' => '',
113
+ 'acceptedName' => '#^[^/\\?*:|"<>]*[^./\\?*:|"<>]$#',
114
+ 'rootCssClass' => 'elfinder-navbar-root-onedrive',
115
+ 'useApiThumbnail' => true,
116
+ );
117
+ $this->options = array_merge($this->options, $opts);
118
+ $this->options['mimeDetect'] = 'internal';
119
+ }
120
+
121
+ /*********************************************************************/
122
+ /* ORIGINAL FUNCTIONS */
123
+ /*********************************************************************/
124
+
125
+ /**
126
+ * Obtains a new access token from OAuth. This token is valid for one hour.
127
+ *
128
+ * @param $client_id
129
+ * @param $client_secret
130
+ * @param string $code The code returned by OneDrive after
131
+ * successful log in
132
+ *
133
+ * @return object|string
134
+ * @throws Exception Thrown if the redirect URI of this Client instance's
135
+ * state is not set
136
+ */
137
+ protected function _od_obtainAccessToken($client_id, $client_secret, $code, $nodeid)
138
+ {
139
+ if (null === $client_id) {
140
+ return 'The client ID must be set to call obtainAccessToken()';
141
+ }
142
+
143
+ if (null === $client_secret) {
144
+ return 'The client Secret must be set to call obtainAccessToken()';
145
+ }
146
+
147
+ $redirect = elFinder::getConnectorUrl();
148
+ if (strpos($redirect, '/netmount/onedrive/') === false) {
149
+ $redirect .= '/netmount/onedrive/' . ($nodeid === 'elfinder'? '1' : $nodeid);
150
+ }
151
+
152
+ $url = self::TOKEN_URL;
153
+
154
+ $curl = curl_init();
155
+
156
+ $fields = http_build_query(
157
+ array(
158
+ 'client_id' => $client_id,
159
+ 'redirect_uri' => $redirect,
160
+ 'client_secret' => $client_secret,
161
+ 'code' => $code,
162
+ 'grant_type' => 'authorization_code',
163
+ )
164
+ );
165
+
166
+ curl_setopt_array($curl, array(
167
+ // General options.
168
+ CURLOPT_RETURNTRANSFER => true,
169
+ CURLOPT_POST => true,
170
+ CURLOPT_POSTFIELDS => $fields,
171
+
172
+ CURLOPT_HTTPHEADER => array(
173
+ 'Content-Length: ' . strlen($fields),
174
+ ),
175
+
176
+ CURLOPT_URL => $url,
177
+ ));
178
+
179
+ $result = elFinder::curlExec($curl);
180
+
181
+ $decoded = json_decode($result);
182
+
183
+ if (null === $decoded) {
184
+ throw new \Exception('json_decode() failed');
185
+ }
186
+
187
+ if (!empty($decoded->error)) {
188
+ $error = $decoded->error;
189
+ if (!empty($decoded->error_description)) {
190
+ $error .= ': ' . $decoded->error_description;
191
+ }
192
+ throw new \Exception($error);
193
+ }
194
+
195
+ $res = (object)array(
196
+ 'expires' => time() + $decoded->expires_in - 30,
197
+ 'initialToken' => '',
198
+ 'data' => $decoded
199
+ );
200
+ if (!empty($decoded->refresh_token)) {
201
+ $res->initialToken = md5($client_id . $decoded->refresh_token);
202
+ }
203
+ return $res;
204
+ }
205
+
206
+ /**
207
+ * Get token and auto refresh.
208
+ *
209
+ * @return true
210
+ * @throws Exception
211
+ */
212
+ protected function _od_refreshToken()
213
+ {
214
+ if (!property_exists($this->token, 'expires') || $this->token->expires < time()) {
215
+ if (!$this->options['client_id']) {
216
+ $this->options['client_id'] = ELFINDER_ONEDRIVE_CLIENTID;
217
+ }
218
+
219
+ if (!$this->options['client_secret']) {
220
+ $this->options['client_secret'] = ELFINDER_ONEDRIVE_CLIENTSECRET;
221
+ }
222
+
223
+ if (empty($this->token->data->refresh_token)) {
224
+ throw new \Exception(elFinder::ERROR_REAUTH_REQUIRE);
225
+ } else {
226
+ $refresh_token = $this->token->data->refresh_token;
227
+ $initialToken = $this->_od_getInitialToken();
228
+ }
229
+
230
+ $url = self::TOKEN_URL;
231
+
232
+ $curl = curl_init();
233
+
234
+ curl_setopt_array($curl, array(
235
+ // General options.
236
+ CURLOPT_RETURNTRANSFER => true,
237
+ CURLOPT_POST => true, // i am sending post data
238
+ CURLOPT_POSTFIELDS => 'client_id=' . urlencode($this->options['client_id'])
239
+ . '&client_secret=' . urlencode($this->options['client_secret'])
240
+ . '&grant_type=refresh_token'
241
+ . '&refresh_token=' . urlencode($this->token->data->refresh_token),
242
+
243
+ CURLOPT_URL => $url,
244
+ ));
245
+
246
+ $result = elFinder::curlExec($curl);
247
+
248
+ $decoded = json_decode($result);
249
+
250
+ if (!$decoded) {
251
+ throw new \Exception('json_decode() failed');
252
+ }
253
+
254
+ if (empty($decoded->access_token)) {
255
+ if ($this->aTokenFile) {
256
+ if (is_file($this->aTokenFile)) {
257
+ unlink($this->aTokenFile);
258
+ }
259
+ }
260
+ $err = property_exists($decoded, 'error')? ' ' . $decoded->error : '';
261
+ $err .= property_exists($decoded, 'error_description')? ' ' . $decoded->error_description : '';
262
+ throw new \Exception($err? $err : elFinder::ERROR_REAUTH_REQUIRE);
263
+ }
264
+
265
+ $token = (object)array(
266
+ 'expires' => time() + $decoded->expires_in - 30,
267
+ 'initialToken' => $initialToken,
268
+ 'data' => $decoded,
269
+ );
270
+
271
+ $this->token = $token;
272
+ $json = json_encode($token);
273
+
274
+ if (!empty($decoded->refresh_token)) {
275
+ if (empty($this->options['netkey']) && $this->aTokenFile) {
276
+ file_put_contents($this->aTokenFile, json_encode($token));
277
+ $this->options['accessToken'] = $json;
278
+ } else if (!empty($this->options['netkey'])) {
279
+ // OAuth2 refresh token can be used only once,
280
+ // so update it if it is the same as the token file
281
+ $aTokenFile = $this->_od_getATokenFile();
282
+ if ($aTokenFile && is_file($aTokenFile)) {
283
+ if ($_token = json_decode(file_get_contents($aTokenFile))) {
284
+ if ($_token->data->refresh_token === $refresh_token) {
285
+ file_put_contents($aTokenFile, $json);
286
+ }
287
+ }
288
+ }
289
+ $this->options['accessToken'] = $json;
290
+ // update session value
291
+ elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'accessToken', $this->options['accessToken']);
292
+ $this->session->set('OneDriveTokens', $token);
293
+ } else {
294
+ throw new \Exception(elFinder::ERROR_CREATING_TEMP_DIR);
295
+ }
296
+ }
297
+ }
298
+
299
+ return true;
300
+ }
301
+
302
+ /**
303
+ * Get Parent ID, Item ID, Parent Path as an array from path.
304
+ *
305
+ * @param string $path
306
+ *
307
+ * @return array
308
+ */
309
+ protected function _od_splitPath($path)
310
+ {
311
+ $path = trim($path, '/');
312
+ $pid = '';
313
+ if ($path === '') {
314
+ $id = 'root';
315
+ $parent = '';
316
+ } else {
317
+ $paths = explode('/', trim($path, '/'));
318
+ $id = array_pop($paths);
319
+ if ($paths) {
320
+ $parent = '/' . implode('/', $paths);
321
+ $pid = array_pop($paths);
322
+ } else {
323
+ $pid = 'root';
324
+ $parent = '/';
325
+ }
326
+ }
327
+
328
+ return array($pid, $id, $parent);
329
+ }
330
+
331
+ /**
332
+ * Creates a base cURL object which is compatible with the OneDrive API.
333
+ *
334
+ * @return resource A compatible cURL object
335
+ */
336
+ protected function _od_prepareCurl($url = null)
337
+ {
338
+ $curl = curl_init($url);
339
+
340
+ $defaultOptions = array(
341
+ // General options.
342
+ CURLOPT_RETURNTRANSFER => true,
343
+ CURLOPT_HTTPHEADER => array(
344
+ 'Content-Type: application/json',
345
+ 'Authorization: Bearer ' . $this->token->data->access_token,
346
+ ),
347
+ );
348
+
349
+ curl_setopt_array($curl, $defaultOptions);
350
+
351
+ return $curl;
352
+ }
353
+
354
+ /**
355
+ * Creates a base cURL object which is compatible with the OneDrive API.
356
+ *
357
+ * @param string $path The path of the API call (eg. me/skydrive)
358
+ * @param bool $contents
359
+ *
360
+ * @return resource A compatible cURL object
361
+ * @throws elFinderAbortException
362
+ */
363
+ protected function _od_createCurl($path, $contents = false)
364
+ {
365
+ elFinder::checkAborted();
366
+ $curl = $this->_od_prepareCurl($path);
367
+
368
+ if ($contents) {
369
+ $res = elFinder::curlExec($curl);
370
+ } else {
371
+ $result = json_decode(elFinder::curlExec($curl));
372
+ if (isset($result->value)) {
373
+ $res = $result->value;
374
+ unset($result->value);
375
+ $result = (array)$result;
376
+ if (!empty($result['@odata.nextLink'])) {
377
+ $nextRes = $this->_od_createCurl($result['@odata.nextLink'], false);
378
+ if (is_array($nextRes)) {
379
+ $res = array_merge($res, $nextRes);
380
+ }
381
+ }
382
+ } else {
383
+ $res = $result;
384
+ }
385
+ }
386
+
387
+ return $res;
388
+ }
389
+
390
+ /**
391
+ * Drive query and fetchAll.
392
+ *
393
+ * @param $itemId
394
+ * @param bool $fetch_self
395
+ * @param bool $recursive
396
+ * @param array $options
397
+ *
398
+ * @return object|array
399
+ * @throws elFinderAbortException
400
+ */
401
+ protected function _od_query($itemId, $fetch_self = false, $recursive = false, $options = array())
402
+ {
403
+ $result = array();
404
+
405
+ if (null === $itemId) {
406
+ $itemId = 'root';
407
+ }
408
+
409
+ if ($fetch_self == true) {
410
+ $path = $itemId;
411
+ } else {
412
+ $path = $itemId . '/children';
413
+ }
414
+
415
+ if (isset($options['query'])) {
416
+ $path .= '?' . http_build_query($options['query']);
417
+ }
418
+
419
+ $url = self::API_URL . $path;
420
+
421
+ $res = $this->_od_createCurl($url);
422
+ if (!$fetch_self && $recursive && is_array($res)) {
423
+ foreach ($res as $file) {
424
+ $result[] = $file;
425
+ if (!empty($file->folder)) {
426
+ $result = array_merge($result, $this->_od_query($file->id, false, true, $options));
427
+ }
428
+ }
429
+ } else {
430
+ $result = $res;
431
+ }
432
+
433
+ return isset($result->error) ? array() : $result;
434
+ }
435
+
436
+ /**
437
+ * Parse line from onedrive metadata output and return file stat (array).
438
+ *
439
+ * @param object $raw line from ftp_rawlist() output
440
+ *
441
+ * @return array
442
+ * @author Dmitry Levashov
443
+ **/
444
+ protected function _od_parseRaw($raw)
445
+ {
446
+ $stat = array();
447
+
448
+ $folder = isset($raw->folder) ? $raw->folder : null;
449
+
450
+ $stat['rev'] = isset($raw->id) ? $raw->id : 'root';
451
+ $stat['name'] = $raw->name;
452
+ if (isset($raw->lastModifiedDateTime)) {
453
+ $stat['ts'] = strtotime($raw->lastModifiedDateTime);
454
+ }
455
+
456
+ if ($folder) {
457
+ $stat['mime'] = 'directory';
458
+ $stat['size'] = 0;
459
+ if (empty($folder->childCount)) {
460
+ $stat['dirs'] = 0;
461
+ } else {
462
+ $stat['dirs'] = -1;
463
+ }
464
+ } else {
465
+ if (isset($raw->file->mimeType)) {
466
+ $stat['mime'] = $raw->file->mimeType;
467
+ }
468
+ $stat['size'] = (int)$raw->size;
469
+ if (!$this->disabledGetUrl) {
470
+ $stat['url'] = '1';
471
+ }
472
+ if (isset($raw->image) && $img = $raw->image) {
473
+ isset($img->width) ? $stat['width'] = $img->width : $stat['width'] = 0;
474
+ isset($img->height) ? $stat['height'] = $img->height : $stat['height'] = 0;
475
+ }
476
+ if (!empty($raw->thumbnails)) {
477
+ if ($raw->thumbnails[0]->small->url) {
478
+ $stat['tmb'] = substr($raw->thumbnails[0]->small->url, 8); // remove "https://"
479
+ }
480
+ } elseif (!empty($raw->file->processingMetadata)) {
481
+ $stat['tmb'] = '1';
482
+ }
483
+ }
484
+
485
+ return $stat;
486
+ }
487
+
488
+ /**
489
+ * Get raw data(onedrive metadata) from OneDrive.
490
+ *
491
+ * @param string $path
492
+ *
493
+ * @return array|object onedrive metadata
494
+ */
495
+ protected function _od_getFileRaw($path)
496
+ {
497
+ list(, $itemId) = $this->_od_splitPath($path);
498
+ try {
499
+ $res = $this->_od_query($itemId, true, false, $this->queryOptions);
500
+
501
+ return $res;
502
+ } catch (Exception $e) {
503
+ return array();
504
+ }
505
+ }
506
+
507
+ /**
508
+ * Get thumbnail from OneDrive.com.
509
+ *
510
+ * @param string $path
511
+ *
512
+ * @return string | boolean
513
+ */
514
+ protected function _od_getThumbnail($path)
515
+ {
516
+ list(, $itemId) = $this->_od_splitPath($path);
517
+
518
+ try {
519
+ $url = self::API_URL . $itemId . '/thumbnails/0/medium/content';
520
+
521
+ return $this->_od_createCurl($url, $contents = true);
522
+ } catch (Exception $e) {
523
+ return false;
524
+ }
525
+ }
526
+
527
+ /**
528
+ * Upload large files with an upload session.
529
+ *
530
+ * @param resource $fp source file pointer
531
+ * @param number $size total size
532
+ * @param string $name item name
533
+ * @param string $itemId item identifier
534
+ * @param string $parent parent
535
+ * @param string $parentId parent identifier
536
+ *
537
+ * @return string The item path
538
+ */
539
+ protected function _od_uploadSession($fp, $size, $name, $itemId, $parent, $parentId)
540
+ {
541
+ try {
542
+ $send = $this->_od_getChunkData($fp);
543
+ if ($send === false) {
544
+ throw new Exception('Data can not be acquired from the source.');
545
+ }
546
+
547
+ // create upload session
548
+ if ($itemId) {
549
+ $url = self::API_URL . $itemId . '/createUploadSession';
550
+ } else {
551
+ $url = self::API_URL . $parentId . ':/' . rawurlencode($name) . ':/createUploadSession';
552
+ }
553
+ $curl = $this->_od_prepareCurl($url);
554
+ curl_setopt_array($curl, array(
555
+ CURLOPT_POST => true,
556
+ CURLOPT_POSTFIELDS => '{}',
557
+ ));
558
+ $sess = json_decode(elFinder::curlExec($curl));
559
+
560
+ if ($sess) {
561
+ if (isset($sess->error)) {
562
+ throw new Exception($sess->error->message);
563
+ }
564
+ $next = strlen($send);
565
+ $range = '0-' . ($next - 1) . '/' . $size;
566
+ } else {
567
+ throw new Exception('API response can not be obtained.');
568
+ }
569
+
570
+ $id = null;
571
+ $retry = 0;
572
+ while ($sess) {
573
+ elFinder::extendTimeLimit();
574
+ $putFp = tmpfile();
575
+ fwrite($putFp, $send);
576
+ rewind($putFp);
577
+ $_size = strlen($send);
578
+ $url = $sess->uploadUrl;
579
+ $curl = curl_init();
580
+ $options = array(
581
+ CURLOPT_URL => $url,
582
+ CURLOPT_PUT => true,
583
+ CURLOPT_RETURNTRANSFER => true,
584
+ CURLOPT_INFILE => $putFp,
585
+ CURLOPT_INFILESIZE => $_size,
586
+ CURLOPT_HTTPHEADER => array(
587
+ 'Content-Length: ' . $_size,
588
+ 'Content-Range: bytes ' . $range,
589
+ ),
590
+ );
591
+ curl_setopt_array($curl, $options);
592
+ $sess = json_decode(elFinder::curlExec($curl));
593
+ if ($sess) {
594
+ if (isset($sess->error)) {
595
+ throw new Exception($sess->error->message);
596
+ }
597
+ if (isset($sess->id)) {
598
+ $id = $sess->id;
599
+ break;
600
+ }
601
+ if (isset($sess->nextExpectedRanges)) {
602
+ list($_next) = explode('-', $sess->nextExpectedRanges[0]);
603
+ if ($next == $_next) {
604
+ $send = $this->_od_getChunkData($fp);
605
+ if ($send === false) {
606
+ throw new Exception('Data can not be acquired from the source.');
607
+ }
608
+ $next += strlen($send);
609
+ $range = $_next . '-' . ($next - 1) . '/' . $size;
610
+ $retry = 0;
611
+ } else {
612
+ if (++$retry > 3) {
613
+ throw new Exception('Retry limit exceeded with uploadSession API call.');
614
+ }
615
+ }
616
+ $sess->uploadUrl = $url;
617
+ }
618
+ } else {
619
+ throw new Exception('API response can not be obtained.');
620
+ }
621
+ }
622
+
623
+ if ($id) {
624
+ return $this->_joinPath($parent, $id);
625
+ } else {
626
+ throw new Exception('An error occurred in the uploadSession API call.');
627
+ }
628
+ } catch (Exception $e) {
629
+ return $this->setError('OneDrive error: ' . $e->getMessage());
630
+ }
631
+ }
632
+
633
+ /**
634
+ * Get chunk data by file pointer to upload session.
635
+ *
636
+ * @param resource $fp source file pointer
637
+ *
638
+ * @return bool|string chunked data
639
+ */
640
+ protected function _od_getChunkData($fp)
641
+ {
642
+ static $chunkSize = null;
643
+ if ($chunkSize === null) {
644
+ $mem = elFinder::getIniBytes('memory_limit');
645
+ if ($mem < 1) {
646
+ $mem = 10485760; // 10 MiB
647
+ } else {
648
+ $mem -= memory_get_usage() - 1061548;
649
+ $mem = min($mem, 10485760);
650
+ }
651
+ if ($mem > 327680) {
652
+ $chunkSize = floor($mem / 327680) * 327680;
653
+ } else {
654
+ $chunkSize = $mem;
655
+ }
656
+ }
657
+ if ($chunkSize < 8192) {
658
+ return false;
659
+ }
660
+
661
+ $contents = '';
662
+ while (!feof($fp) && strlen($contents) < $chunkSize) {
663
+ $contents .= fread($fp, 8192);
664
+ }
665
+
666
+ return $contents;
667
+ }
668
+
669
+ /**
670
+ * Get AccessToken file path
671
+ *
672
+ * @return string ( description_of_the_return_value )
673
+ */
674
+ protected function _od_getATokenFile()
675
+ {
676
+ $tmp = $aTokenFile = '';
677
+ if (!empty($this->token->data->refresh_token)) {
678
+ if (!$this->tmp) {
679
+ $tmp = elFinder::getStaticVar('commonTempPath');
680
+ if (!$tmp) {
681
+ $tmp = $this->getTempPath();
682
+ }
683
+ $this->tmp = $tmp;
684
+ }
685
+ if ($tmp) {
686
+ $aTokenFile = $tmp . DIRECTORY_SEPARATOR . $this->_od_getInitialToken() . '.otoken';
687
+ }
688
+ }
689
+ return $aTokenFile;
690
+ }
691
+
692
+ /**
693
+ * Get Initial Token (MD5 hash)
694
+ *
695
+ * @return string
696
+ */
697
+ protected function _od_getInitialToken()
698
+ {
699
+ return (empty($this->token->initialToken)? md5($this->options['client_id'] . (!empty($this->token->data->refresh_token)? $this->token->data->refresh_token : $this->token->data->access_token)) : $this->token->initialToken);
700
+ }
701
+
702
+ /*********************************************************************/
703
+ /* OVERRIDE FUNCTIONS */
704
+ /*********************************************************************/
705
+
706
+ /**
707
+ * Prepare
708
+ * Call from elFinder::netmout() before volume->mount().
709
+ *
710
+ * @return array
711
+ * @author Naoki Sawada
712
+ * @author Raja Sharma updating for OneDrive
713
+ **/
714
+ public function netmountPrepare($options)
715
+ {
716
+ if (empty($options['client_id']) && defined('ELFINDER_ONEDRIVE_CLIENTID')) {
717
+ $options['client_id'] = ELFINDER_ONEDRIVE_CLIENTID;
718
+ }
719
+ if (empty($options['client_secret']) && defined('ELFINDER_ONEDRIVE_CLIENTSECRET')) {
720
+ $options['client_secret'] = ELFINDER_ONEDRIVE_CLIENTSECRET;
721
+ }
722
+
723
+ if (isset($options['pass']) && $options['pass'] === 'reauth') {
724
+ $options['user'] = 'init';
725
+ $options['pass'] = '';
726
+ $this->session->remove('OneDriveTokens');
727
+ }
728
+
729
+ if (isset($options['id'])) {
730
+ $this->session->set('nodeId', $options['id']);
731
+ } elseif ($_id = $this->session->get('nodeId')) {
732
+ $options['id'] = $_id;
733
+ $this->session->set('nodeId', $_id);
734
+ }
735
+
736
+ if (!empty($options['tmpPath'])) {
737
+ if ((is_dir($options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($options['tmpPath'])) {
738
+ $this->tmp = $options['tmpPath'];
739
+ }
740
+ }
741
+
742
+ try {
743
+ if (empty($options['client_id']) || empty($options['client_secret'])) {
744
+ return array('exit' => true, 'body' => '{msg:errNetMountNoDriver}');
745
+ }
746
+
747
+ $itpCare = isset($options['code']);
748
+ $code = $itpCare? $options['code'] : (isset($_GET['code'])? $_GET['code'] : '');
749
+ if ($code) {
750
+ try {
751
+ if (!empty($options['id'])) {
752
+ // Obtain the token using the code received by the OneDrive API
753
+ $this->session->set('OneDriveTokens',
754
+ $this->_od_obtainAccessToken($options['client_id'], $options['client_secret'], $code, $options['id']));
755
+
756
+ $out = array(
757
+ 'node' => $options['id'],
758
+ 'json' => '{"protocol": "onedrive", "mode": "done", "reset": 1}',
759
+ 'bind' => 'netmount',
760
+ );
761
+ } else {
762
+ $nodeid = ($_GET['host'] === '1')? 'elfinder' : $_GET['host'];
763
+ $out = array(
764
+ 'node' => $nodeid,
765
+ 'json' => json_encode(array(
766
+ 'protocol' => 'onedrive',
767
+ 'host' => $nodeid,
768
+ 'mode' => 'redirect',
769
+ 'options' => array(
770
+ 'id' => $nodeid,
771
+ 'code'=> $code
772
+ )
773
+ )),
774
+ 'bind' => 'netmount'
775
+ );
776
+ }
777
+ if (!$itpCare) {
778
+ return array('exit' => 'callback', 'out' => $out);
779
+ } else {
780
+ return array('exit' => true, 'body' => $out['json']);
781
+ }
782
+ } catch (Exception $e) {
783
+ $out = array(
784
+ 'node' => $options['id'],
785
+ 'json' => json_encode(array('error' => elFinder::ERROR_ACCESS_DENIED . ' ' . $e->getMessage())),
786
+ );
787
+
788
+ return array('exit' => 'callback', 'out' => $out);
789
+ }
790
+ } elseif (!empty($_GET['error'])) {
791
+ $out = array(
792
+ 'node' => $options['id'],
793
+ 'json' => json_encode(array('error' => elFinder::ERROR_ACCESS_DENIED)),
794
+ );
795
+
796
+ return array('exit' => 'callback', 'out' => $out);
797
+ }
798
+
799
+ if ($options['user'] === 'init') {
800
+ $this->token = $this->session->get('OneDriveTokens');
801
+
802
+ if ($this->token) {
803
+ try {
804
+ $this->_od_refreshToken();
805
+ } catch (Exception $e) {
806
+ $this->setError($e->getMessage());
807
+ $this->token = null;
808
+ $this->session->remove('OneDriveTokens');
809
+ }
810
+ }
811
+
812
+ if (empty($this->token)) {
813
+ $result = false;
814
+ } else {
815
+ $path = $options['path'];
816
+ if ($path === '/') {
817
+ $path = 'root';
818
+ }
819
+ $result = $this->_od_query($path, false, false, array(
820
+ 'query' => array(
821
+ 'select' => 'id,name',
822
+ 'filter' => 'folder ne null',
823
+ ),
824
+ ));
825
+ }
826
+
827
+ if ($result === false) {
828
+ try {
829
+ $this->session->set('OneDriveTokens', (object)array('token' => null));
830
+
831
+ $offline = '';
832
+ // Gets a log in URL with sufficient privileges from the OneDrive API
833
+ if (!empty($options['offline'])) {
834
+ $offline = ' offline_access';
835
+ }
836
+
837
+ $redirect_uri = elFinder::getConnectorUrl() . '/netmount/onedrive/' . ($options['id'] === 'elfinder'? '1' : $options['id']);
838
+ $url = self::AUTH_URL
839
+ . '?client_id=' . urlencode($options['client_id'])
840
+ . '&scope=' . urlencode('files.readwrite.all' . $offline)
841
+ . '&response_type=code'
842
+ . '&redirect_uri=' . urlencode($redirect_uri);
843
+
844
+ } catch (Exception $e) {
845
+ return array('exit' => true, 'body' => '{msg:errAccess}');
846
+ }
847
+
848
+ $html = '<input id="elf-volumedriver-onedrive-host-btn" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" value="{msg:btnApprove}" type="button">';
849
+ $html .= '<script>
850
+ $("#' . $options['id'] . '").elfinder("instance").trigger("netmount", {protocol: "onedrive", mode: "makebtn", url: "' . $url . '"});
851
+ </script>';
852
+
853
+ return array('exit' => true, 'body' => $html);
854
+ } else {
855
+ $folders = [];
856
+
857
+ if ($result) {
858
+ foreach ($result as $res) {
859
+ $folders[$res->id] = $res->name;
860
+ }
861
+ natcasesort($folders);
862
+ }
863
+
864
+ if ($options['pass'] === 'folders') {
865
+ return ['exit' => true, 'folders' => $folders];
866
+ }
867
+
868
+ $folders = ['root' => 'My OneDrive'] + $folders;
869
+ $folders = json_encode($folders);
870
+
871
+ $expires = empty($this->token->data->refresh_token) ? (int)$this->token->expires : 0;
872
+ $mnt2res = empty($this->token->data->refresh_token) ? '' : ', "mnt2res": 1';
873
+ $json = '{"protocol": "onedrive", "mode": "done", "folders": ' . $folders . ', "expires": ' . $expires . $mnt2res .'}';
874
+ $html = 'OneDrive.com';
875
+ $html .= '<script>
876
+ $("#' . $options['id'] . '").elfinder("instance").trigger("netmount", ' . $json . ');
877
+ </script>';
878
+
879
+ return array('exit' => true, 'body' => $html);
880
+ }
881
+ }
882
+ } catch (Exception $e) {
883
+ return array('exit' => true, 'body' => '{msg:errNetMountNoDriver}');
884
+ }
885
+
886
+ if ($_aToken = $this->session->get('OneDriveTokens')) {
887
+ $options['accessToken'] = json_encode($_aToken);
888
+ if ($this->options['path'] === 'root' || !$this->options['path']) {
889
+ $this->options['path'] = '/';
890
+ }
891
+ } else {
892
+ $this->session->remove('OneDriveTokens');
893
+ $this->setError(elFinder::ERROR_NETMOUNT, $options['host'], implode(' ', $this->error()));
894
+
895
+ return array('exit' => true, 'error' => $this->error());
896
+ }
897
+
898
+ $this->session->remove('nodeId');
899
+ unset($options['user'], $options['pass'], $options['id']);
900
+
901
+ return $options;
902
+ }
903
+
904
+ /**
905
+ * process of on netunmount
906
+ * Drop `onedrive` & rm thumbs.
907
+ *
908
+ * @param array $options
909
+ *
910
+ * @return bool
911
+ */
912
+ public function netunmount($netVolumes, $key)
913
+ {
914
+ if (!$this->options['useApiThumbnail'] && ($tmbs = glob(rtrim($this->options['tmbPath'], '\\/') . DIRECTORY_SEPARATOR . $this->tmbPrefix . '*.png'))) {
915
+ foreach ($tmbs as $file) {
916
+ unlink($file);
917
+ }
918
+ }
919
+
920
+ return true;
921
+ }
922
+
923
+ /**
924
+ * Return debug info for client.
925
+ *
926
+ * @return array
927
+ **/
928
+ public function debug()
929
+ {
930
+ $res = parent::debug();
931
+ if (!empty($this->options['netkey']) && !empty($this->options['accessToken'])) {
932
+ $res['accessToken'] = $this->options['accessToken'];
933
+ }
934
+
935
+ return $res;
936
+ }
937
+
938
+ /*********************************************************************/
939
+ /* INIT AND CONFIGURE */
940
+ /*********************************************************************/
941
+
942
+ /**
943
+ * Prepare FTP connection
944
+ * Connect to remote server and check if credentials are correct, if so, store the connection id in $ftp_conn.
945
+ *
946
+ * @return bool
947
+ * @throws elFinderAbortException
948
+ * @author Dmitry (dio) Levashov
949
+ * @author Cem (DiscoFever)
950
+ */
951
+ protected function init()
952
+ {
953
+ if (!$this->options['accessToken']) {
954
+ return $this->setError('Required option `accessToken` is undefined.');
955
+ }
956
+
957
+ if (!empty($this->options['tmpPath'])) {
958
+ if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($this->options['tmpPath'])) {
959
+ $this->tmp = $this->options['tmpPath'];
960
+ }
961
+ }
962
+
963
+ $error = false;
964
+ try {
965
+ $this->token = json_decode($this->options['accessToken']);
966
+ if (!is_object($this->token)) {
967
+ throw new Exception('Required option `accessToken` is invalid JSON.');
968
+ }
969
+
970
+ // make net mount key
971
+ if (empty($this->options['netkey'])) {
972
+ $this->netMountKey = $this->_od_getInitialToken();
973
+ } else {
974
+ $this->netMountKey = $this->options['netkey'];
975
+ }
976
+
977
+ if ($this->aTokenFile = $this->_od_getATokenFile()) {
978
+ if (empty($this->options['netkey'])) {
979
+ if ($this->aTokenFile) {
980
+ if (is_file($this->aTokenFile)) {
981
+ $this->token = json_decode(file_get_contents($this->aTokenFile));
982
+ if (!is_object($this->token)) {
983
+ unlink($this->aTokenFile);
984
+ throw new Exception('Required option `accessToken` is invalid JSON.');
985
+ }
986
+ } else {
987
+ file_put_contents($this->aTokenFile, $this->token);
988
+ }
989
+ }
990
+ } else if (is_file($this->aTokenFile)) {
991
+ // If the refresh token is the same as the permanent volume
992
+ $this->token = json_decode(file_get_contents($this->aTokenFile));
993
+ }
994
+ }
995
+
996
+ if ($this->needOnline) {
997
+ $this->_od_refreshToken();
998
+
999
+ $this->expires = empty($this->token->data->refresh_token) ? (int)$this->token->expires : 0;
1000
+ }
1001
+ } catch (Exception $e) {
1002
+ $this->token = null;
1003
+ $error = true;
1004
+ $this->setError($e->getMessage());
1005
+ }
1006
+
1007
+ if ($this->netMountKey) {
1008
+ $this->tmbPrefix = 'onedrive' . base_convert($this->netMountKey, 16, 32);
1009
+ }
1010
+
1011
+ if ($error) {
1012
+ if (empty($this->options['netkey']) && $this->tmbPrefix) {
1013
+ // for delete thumbnail
1014
+ $this->netunmount(null, null);
1015
+ }
1016
+ return false;
1017
+ }
1018
+
1019
+ // normalize root path
1020
+ if ($this->options['path'] == 'root') {
1021
+ $this->options['path'] = '/';
1022
+ }
1023
+
1024
+ $this->root = $this->options['path'] = $this->_normpath($this->options['path']);
1025
+
1026
+ $this->options['root'] = ($this->options['root'] == '')? 'OneDrive.com' : $this->options['root'];
1027
+
1028
+ if (empty($this->options['alias'])) {
1029
+ if ($this->needOnline) {
1030
+ $this->options['alias'] = ($this->options['path'] === '/') ? $this->options['root'] :
1031
+ $this->_od_query(basename($this->options['path']), $fetch_self = true)->name . '@OneDrive';
1032
+ if (!empty($this->options['netkey'])) {
1033
+ elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'alias', $this->options['alias']);
1034
+ }
1035
+ } else {
1036
+ $this->options['alias'] = $this->options['root'];
1037
+ }
1038
+ }
1039
+
1040
+ $this->rootName = $this->options['alias'];
1041
+
1042
+ // This driver dose not support `syncChkAsTs`
1043
+ $this->options['syncChkAsTs'] = false;
1044
+
1045
+ // 'lsPlSleep' minmum 10 sec
1046
+ $this->options['lsPlSleep'] = max(10, $this->options['lsPlSleep']);
1047
+
1048
+ $this->queryOptions = array(
1049
+ 'query' => array(
1050
+ 'select' => 'id,name,lastModifiedDateTime,file,folder,size,image',
1051
+ ),
1052
+ );
1053
+
1054
+ if ($this->options['useApiThumbnail']) {
1055
+ $this->options['tmbURL'] = 'https://';
1056
+ $this->options['tmbPath'] = '';
1057
+ $this->queryOptions['query']['expand'] = 'thumbnails(select=small)';
1058
+ }
1059
+
1060
+ // enable command archive
1061
+ $this->options['useRemoteArchive'] = true;
1062
+
1063
+ return true;
1064
+ }
1065
+
1066
+ /**
1067
+ * Configure after successfull mount.
1068
+ *
1069
+ * @author Dmitry (dio) Levashov
1070
+ **/
1071
+ protected function configure()
1072
+ {
1073
+ parent::configure();
1074
+
1075
+ // fallback of $this->tmp
1076
+ if (!$this->tmp && $this->tmbPathWritable) {
1077
+ $this->tmp = $this->tmbPath;
1078
+ }
1079
+ }
1080
+
1081
+ /*********************************************************************/
1082
+ /* FS API */
1083
+ /*********************************************************************/
1084
+
1085
+ /**
1086
+ * Close opened connection.
1087
+ *
1088
+ * @author Dmitry (dio) Levashov
1089
+ **/
1090
+ public function umount()
1091
+ {
1092
+ }
1093
+
1094
+ protected function isNameExists($path)
1095
+ {
1096
+ list($pid, $name) = $this->_od_splitPath($path);
1097
+
1098
+ $raw = $this->_od_query($pid . '/children/' . rawurlencode($name), true);
1099
+ return $raw ? $this->_od_parseRaw($raw) : false;
1100
+ }
1101
+
1102
+ /**
1103
+ * Cache dir contents.
1104
+ *
1105
+ * @param string $path dir path
1106
+ *
1107
+ * @return array
1108
+ * @throws elFinderAbortException
1109
+ * @author Dmitry Levashov
1110
+ */
1111
+ protected function cacheDir($path)
1112
+ {
1113
+ $this->dirsCache[$path] = array();
1114
+ $hasDir = false;
1115
+
1116
+ list(, $itemId) = $this->_od_splitPath($path);
1117
+
1118
+ $res = $this->_od_query($itemId, false, false, $this->queryOptions);
1119
+
1120
+ if ($res) {
1121
+ foreach ($res as $raw) {
1122
+ if ($stat = $this->_od_parseRaw($raw)) {
1123
+ $itemPath = $this->_joinPath($path, $raw->id);
1124
+ $stat = $this->updateCache($itemPath, $stat);
1125
+ if (empty($stat['hidden'])) {
1126
+ if (!$hasDir && $stat['mime'] === 'directory') {
1127
+ $hasDir = true;
1128
+ }
1129
+ $this->dirsCache[$path][] = $itemPath;
1130
+ }
1131
+ }
1132
+ }
1133
+ }
1134
+
1135
+ if (isset($this->sessionCache['subdirs'])) {
1136
+ $this->sessionCache['subdirs'][$path] = $hasDir;
1137
+ }
1138
+
1139
+ return $this->dirsCache[$path];
1140
+ }
1141
+
1142
+ /**
1143
+ * Copy file/recursive copy dir only in current volume.
1144
+ * Return new file path or false.
1145
+ *
1146
+ * @param string $src source path
1147
+ * @param string $dst destination dir path
1148
+ * @param string $name new file name (optionaly)
1149
+ *
1150
+ * @return string|false
1151
+ * @throws elFinderAbortException
1152
+ * @author Dmitry (dio) Levashov
1153
+ * @author Naoki Sawada
1154
+ */
1155
+ protected function copy($src, $dst, $name)
1156
+ {
1157
+ $itemId = '';
1158
+ if ($this->options['copyJoin']) {
1159
+ $test = $this->joinPathCE($dst, $name);
1160
+ if ($testStat = $this->isNameExists($test)) {
1161
+ $this->remove($test);
1162
+ }
1163
+ }
1164
+
1165
+ if ($path = $this->_copy($src, $dst, $name)) {
1166
+ $this->added[] = $this->stat($path);
1167
+ } else {
1168
+ $this->setError(elFinder::ERROR_COPY, $this->_path($src));
1169
+ }
1170
+
1171
+ return $path;
1172
+ }
1173
+
1174
+ /**
1175
+ * Remove file/ recursive remove dir.
1176
+ *
1177
+ * @param string $path file path
1178
+ * @param bool $force try to remove even if file locked
1179
+ *
1180
+ * @return bool
1181
+ * @throws elFinderAbortException
1182
+ * @author Dmitry (dio) Levashov
1183
+ * @author Naoki Sawada
1184
+ */
1185
+ protected function remove($path, $force = false)
1186
+ {
1187
+ $stat = $this->stat($path);
1188
+ $stat['realpath'] = $path;
1189
+ $this->rmTmb($stat);
1190
+ $this->clearcache();
1191
+
1192
+ if (empty($stat)) {
1193
+ return $this->setError(elFinder::ERROR_RM, $this->_path($path), elFinder::ERROR_FILE_NOT_FOUND);
1194
+ }
1195
+
1196
+ if (!$force && !empty($stat['locked'])) {
1197
+ return $this->setError(elFinder::ERROR_LOCKED, $this->_path($path));
1198
+ }
1199
+
1200
+ if ($stat['mime'] == 'directory') {
1201
+ if (!$this->_rmdir($path)) {
1202
+ return $this->setError(elFinder::ERROR_RM, $this->_path($path));
1203
+ }
1204
+ } else {
1205
+ if (!$this->_unlink($path)) {
1206
+ return $this->setError(elFinder::ERROR_RM, $this->_path($path));
1207
+ }
1208
+ }
1209
+
1210
+ $this->removed[] = $stat;
1211
+
1212
+ return true;
1213
+ }
1214
+
1215
+ /**
1216
+ * Create thumnbnail and return it's URL on success.
1217
+ *
1218
+ * @param string $path file path
1219
+ * @param $stat
1220
+ *
1221
+ * @return string|false
1222
+ * @throws ImagickException
1223
+ * @throws elFinderAbortException
1224
+ * @author Dmitry (dio) Levashov
1225
+ * @author Naoki Sawada
1226
+ */
1227
+ protected function createTmb($path, $stat)
1228
+ {
1229
+ if ($this->options['useApiThumbnail']) {
1230
+ if (func_num_args() > 2) {
1231
+ list(, , $count) = func_get_args();
1232
+ } else {
1233
+ $count = 0;
1234
+ }
1235
+ if ($count < 10) {
1236
+ if (isset($stat['tmb']) && $stat['tmb'] != '1') {
1237
+ return $stat['tmb'];
1238
+ } else {
1239
+ sleep(2);
1240
+ elFinder::extendTimeLimit();
1241
+ $this->clearcache();
1242
+ $stat = $this->stat($path);
1243
+
1244
+ return $this->createTmb($path, $stat, ++$count);
1245
+ }
1246
+ }
1247
+
1248
+ return false;
1249
+ }
1250
+ if (!$stat || !$this->canCreateTmb($path, $stat)) {
1251
+ return false;
1252
+ }
1253
+
1254
+ $name = $this->tmbname($stat);
1255
+ $tmb = $this->tmbPath . DIRECTORY_SEPARATOR . $name;
1256
+
1257
+ // copy image into tmbPath so some drivers does not store files on local fs
1258
+ if (!$data = $this->_od_getThumbnail($path)) {
1259
+ return false;
1260
+ }
1261
+ if (!file_put_contents($tmb, $data)) {
1262
+ return false;
1263
+ }
1264
+
1265
+ $result = false;
1266
+
1267
+ $tmbSize = $this->tmbSize;
1268
+
1269
+ if (($s = getimagesize($tmb)) == false) {
1270
+ return false;
1271
+ }
1272
+
1273
+ /* If image smaller or equal thumbnail size - just fitting to thumbnail square */
1274
+ if ($s[0] <= $tmbSize && $s[1] <= $tmbSize) {
1275
+ $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png');
1276
+ } else {
1277
+ if ($this->options['tmbCrop']) {
1278
+
1279
+ /* Resize and crop if image bigger than thumbnail */
1280
+ if (!(($s[0] > $tmbSize && $s[1] <= $tmbSize) || ($s[0] <= $tmbSize && $s[1] > $tmbSize)) || ($s[0] > $tmbSize && $s[1] > $tmbSize)) {
1281
+ $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, false, 'png');
1282
+ }
1283
+
1284
+ if (($s = getimagesize($tmb)) != false) {
1285
+ $x = $s[0] > $tmbSize ? intval(($s[0] - $tmbSize) / 2) : 0;
1286
+ $y = $s[1] > $tmbSize ? intval(($s[1] - $tmbSize) / 2) : 0;
1287
+ $result = $this->imgCrop($tmb, $tmbSize, $tmbSize, $x, $y, 'png');
1288
+ }
1289
+ } else {
1290
+ $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, true, 'png');
1291
+ }
1292
+
1293
+ $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png');
1294
+ }
1295
+
1296
+ if (!$result) {
1297
+ unlink($tmb);
1298
+
1299
+ return false;
1300
+ }
1301
+
1302
+ return $name;
1303
+ }
1304
+
1305
+ /**
1306
+ * Return thumbnail file name for required file.
1307
+ *
1308
+ * @param array $stat file stat
1309
+ *
1310
+ * @return string
1311
+ * @author Dmitry (dio) Levashov
1312
+ **/
1313
+ protected function tmbname($stat)
1314
+ {
1315
+ return $this->tmbPrefix . $stat['rev'] . $stat['ts'] . '.png';
1316
+ }
1317
+
1318
+ /**
1319
+ * Return content URL.
1320
+ *
1321
+ * @param string $hash file hash
1322
+ * @param array $options options
1323
+ *
1324
+ * @return string
1325
+ * @author Naoki Sawada
1326
+ **/
1327
+ public function getContentUrl($hash, $options = array())
1328
+ {
1329
+ if (!empty($options['onetime']) && $this->options['onetimeUrl']) {
1330
+ return parent::getContentUrl($hash, $options);
1331
+ }
1332
+ if (!empty($options['temporary'])) {
1333
+ // try make temporary file
1334
+ $url = parent::getContentUrl($hash, $options);
1335
+ if ($url) {
1336
+ return $url;
1337
+ }
1338
+ }
1339
+ $res = '';
1340
+ if (($file = $this->file($hash)) == false || !$file['url'] || $file['url'] == 1) {
1341
+ $path = $this->decode($hash);
1342
+
1343
+ list(, $itemId) = $this->_od_splitPath($path);
1344
+ try {
1345
+ $url = self::API_URL . $itemId . '/createLink';
1346
+ $data = (object)array(
1347
+ 'type' => 'embed',
1348
+ 'scope' => 'anonymous',
1349
+ );
1350
+ $curl = $this->_od_prepareCurl($url);
1351
+ curl_setopt_array($curl, array(
1352
+ CURLOPT_POST => true,
1353
+ CURLOPT_POSTFIELDS => json_encode($data),
1354
+ ));
1355
+
1356
+ $result = elFinder::curlExec($curl);
1357
+ if ($result) {
1358
+ $result = json_decode($result);
1359
+ if (isset($result->link)) {
1360
+ list(, $res) = explode('?', $result->link->webUrl);
1361
+ $res = 'https://onedrive.live.com/download.aspx?' . $res;
1362
+ }
1363
+ }
1364
+ } catch (Exception $e) {
1365
+ $res = '';
1366
+ }
1367
+ }
1368
+
1369
+ return $res;
1370
+ }
1371
+
1372
+ /*********************** paths/urls *************************/
1373
+
1374
+ /**
1375
+ * Return parent directory path.
1376
+ *
1377
+ * @param string $path file path
1378
+ *
1379
+ * @return string
1380
+ * @author Dmitry (dio) Levashov
1381
+ **/
1382
+ protected function _dirname($path)
1383
+ {
1384
+ list(, , $dirname) = $this->_od_splitPath($path);
1385
+
1386
+ return $dirname;
1387
+ }
1388
+
1389
+ /**
1390
+ * Return file name.
1391
+ *
1392
+ * @param string $path file path
1393
+ *
1394
+ * @return string
1395
+ * @author Dmitry (dio) Levashov
1396
+ **/
1397
+ protected function _basename($path)
1398
+ {
1399
+ list(, $basename) = $this->_od_splitPath($path);
1400
+
1401
+ return $basename;
1402
+ }
1403
+
1404
+ /**
1405
+ * Join dir name and file name and retur full path.
1406
+ *
1407
+ * @param string $dir
1408
+ * @param string $name
1409
+ *
1410
+ * @return string
1411
+ * @author Dmitry (dio) Levashov
1412
+ **/
1413
+ protected function _joinPath($dir, $name)
1414
+ {
1415
+ if ($dir === 'root') {
1416
+ $dir = '';
1417
+ }
1418
+
1419
+ return $this->_normpath($dir . '/' . $name);
1420
+ }
1421
+
1422
+ /**
1423
+ * Return normalized path, this works the same as os.path.normpath() in Python.
1424
+ *
1425
+ * @param string $path path
1426
+ *
1427
+ * @return string
1428
+ * @author Troex Nevelin
1429
+ **/
1430
+ protected function _normpath($path)
1431
+ {
1432
+ if (DIRECTORY_SEPARATOR !== '/') {
1433
+ $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
1434
+ }
1435
+ $path = '/' . ltrim($path, '/');
1436
+
1437
+ return $path;
1438
+ }
1439
+
1440
+ /**
1441
+ * Return file path related to root dir.
1442
+ *
1443
+ * @param string $path file path
1444
+ *
1445
+ * @return string
1446
+ * @author Dmitry (dio) Levashov
1447
+ **/
1448
+ protected function _relpath($path)
1449
+ {
1450
+ return $path;
1451
+ }
1452
+
1453
+ /**
1454
+ * Convert path related to root dir into real path.
1455
+ *
1456
+ * @param string $path file path
1457
+ *
1458
+ * @return string
1459
+ * @author Dmitry (dio) Levashov
1460
+ **/
1461
+ protected function _abspath($path)
1462
+ {
1463
+ return $path;
1464
+ }
1465
+
1466
+ /**
1467
+ * Return fake path started from root dir.
1468
+ *
1469
+ * @param string $path file path
1470
+ *
1471
+ * @return string
1472
+ * @author Dmitry (dio) Levashov
1473
+ **/
1474
+ protected function _path($path)
1475
+ {
1476
+ return $this->rootName . $this->_normpath(substr($path, strlen($this->root)));
1477
+ }
1478
+
1479
+ /**
1480
+ * Return true if $path is children of $parent.
1481
+ *
1482
+ * @param string $path path to check
1483
+ * @param string $parent parent path
1484
+ *
1485
+ * @return bool
1486
+ * @author Dmitry (dio) Levashov
1487
+ **/
1488
+ protected function _inpath($path, $parent)
1489
+ {
1490
+ return $path == $parent || strpos($path, $parent . '/') === 0;
1491
+ }
1492
+
1493
+ /***************** file stat ********************/
1494
+ /**
1495
+ * Return stat for given path.
1496
+ * Stat contains following fields:
1497
+ * - (int) size file size in b. required
1498
+ * - (int) ts file modification time in unix time. required
1499
+ * - (string) mime mimetype. required for folders, others - optionally
1500
+ * - (bool) read read permissions. required
1501
+ * - (bool) write write permissions. required
1502
+ * - (bool) locked is object locked. optionally
1503
+ * - (bool) hidden is object hidden. optionally
1504
+ * - (string) alias for symlinks - link target path relative to root path. optionally
1505
+ * - (string) target for symlinks - link target path. optionally.
1506
+ * If file does not exists - returns empty array or false.
1507
+ *
1508
+ * @param string $path file path
1509
+ *
1510
+ * @return array|false
1511
+ * @author Dmitry (dio) Levashov
1512
+ **/
1513
+ protected function _stat($path)
1514
+ {
1515
+ if ($raw = $this->_od_getFileRaw($path)) {
1516
+ $stat = $this->_od_parseRaw($raw);
1517
+ if ($path === $this->root) {
1518
+ $stat['expires'] = $this->expires;
1519
+ }
1520
+ return $stat;
1521
+ }
1522
+
1523
+ return false;
1524
+ }
1525
+
1526
+ /**
1527
+ * Return true if path is dir and has at least one childs directory.
1528
+ *
1529
+ * @param string $path dir path
1530
+ *
1531
+ * @return bool
1532
+ * @throws elFinderAbortException
1533
+ * @author Dmitry (dio) Levashov
1534
+ */
1535
+ protected function _subdirs($path)
1536
+ {
1537
+ list(, $itemId) = $this->_od_splitPath($path);
1538
+
1539
+ return (bool)$this->_od_query($itemId, false, false, array(
1540
+ 'query' => array(
1541
+ 'top' => 1,
1542
+ 'select' => 'id',
1543
+ 'filter' => 'folder ne null',
1544
+ ),
1545
+ ));
1546
+ }
1547
+
1548
+ /**
1549
+ * Return object width and height
1550
+ * Ususaly used for images, but can be realize for video etc...
1551
+ *
1552
+ * @param string $path file path
1553
+ * @param string $mime file mime type
1554
+ *
1555
+ * @return string
1556
+ * @throws elFinderAbortException
1557
+ * @author Dmitry (dio) Levashov
1558
+ */
1559
+ protected function _dimensions($path, $mime)
1560
+ {
1561
+ if (strpos($mime, 'image') !== 0) {
1562
+ return '';
1563
+ }
1564
+
1565
+ //$cache = $this->_od_getFileRaw($path);
1566
+ if (func_num_args() > 2) {
1567
+ $args = func_get_arg(2);
1568
+ } else {
1569
+ $args = array();
1570
+ }
1571
+ if (!empty($args['substitute'])) {
1572
+ $tmbSize = intval($args['substitute']);
1573
+ } else {
1574
+ $tmbSize = null;
1575
+ }
1576
+ list(, $itemId) = $this->_od_splitPath($path);
1577
+ $options = array(
1578
+ 'query' => array(
1579
+ 'select' => 'id,image',
1580
+ ),
1581
+ );
1582
+ if ($tmbSize) {
1583
+ $tmb = 'c' . $tmbSize . 'x' . $tmbSize;
1584
+ $options['query']['expand'] = 'thumbnails(select=' . $tmb . ')';
1585
+ }
1586
+ $raw = $this->_od_query($itemId, true, false, $options);
1587
+
1588
+ if ($raw && property_exists($raw, 'image') && $img = $raw->image) {
1589
+ if (isset($img->width) && isset($img->height)) {
1590
+ $ret = array('dim' => $img->width . 'x' . $img->height);
1591
+ if ($tmbSize) {
1592
+ $srcSize = explode('x', $ret['dim']);
1593
+ if (min(($tmbSize / $srcSize[0]), ($tmbSize / $srcSize[1])) < 1) {
1594
+ if (!empty($raw->thumbnails)) {
1595
+ $tmbArr = (array)$raw->thumbnails[0];
1596
+ if (!empty($tmbArr[$tmb]->url)) {
1597
+ $ret['url'] = $tmbArr[$tmb]->url;
1598
+ }
1599
+ }
1600
+ }
1601
+ }
1602
+
1603
+ return $ret;
1604
+ }
1605
+ }
1606
+
1607
+ $ret = '';
1608
+ if ($work = $this->getWorkFile($path)) {
1609
+ if ($size = @getimagesize($work)) {
1610
+ $cache['width'] = $size[0];
1611
+ $cache['height'] = $size[1];
1612
+ $ret = $size[0] . 'x' . $size[1];
1613
+ }
1614
+ }
1615
+ is_file($work) && @unlink($work);
1616
+
1617
+ return $ret;
1618
+ }
1619
+
1620
+ /******************** file/dir content *********************/
1621
+
1622
+ /**
1623
+ * Return files list in directory.
1624
+ *
1625
+ * @param string $path dir path
1626
+ *
1627
+ * @return array
1628
+ * @throws elFinderAbortException
1629
+ * @author Dmitry (dio) Levashov
1630
+ * @author Cem (DiscoFever)
1631
+ */
1632
+ protected function _scandir($path)
1633
+ {
1634
+ return isset($this->dirsCache[$path])
1635
+ ? $this->dirsCache[$path]
1636
+ : $this->cacheDir($path);
1637
+ }
1638
+
1639
+ /**
1640
+ * Open file and return file pointer.
1641
+ *
1642
+ * @param string $path file path
1643
+ * @param bool $write open file for writing
1644
+ *
1645
+ * @return resource|false
1646
+ * @author Dmitry (dio) Levashov
1647
+ **/
1648
+ protected function _fopen($path, $mode = 'rb')
1649
+ {
1650
+ if ($mode === 'rb' || $mode === 'r') {
1651
+ list(, $itemId) = $this->_od_splitPath($path);
1652
+ $data = array(
1653
+ 'target' => self::API_URL . $itemId . '/content',
1654
+ 'headers' => array('Authorization: Bearer ' . $this->token->data->access_token),
1655
+ );
1656
+
1657
+ // to support range request
1658
+ if (func_num_args() > 2) {
1659
+ $opts = func_get_arg(2);
1660
+ } else {
1661
+ $opts = array();
1662
+ }
1663
+ if (!empty($opts['httpheaders'])) {
1664
+ $data['headers'] = array_merge($opts['httpheaders'], $data['headers']);
1665
+ }
1666
+
1667
+ return elFinder::getStreamByUrl($data);
1668
+ }
1669
+
1670
+ return false;
1671
+ }
1672
+
1673
+ /**
1674
+ * Close opened file.
1675
+ *
1676
+ * @param resource $fp file pointer
1677
+ *
1678
+ * @return bool
1679
+ * @author Dmitry (dio) Levashov
1680
+ **/
1681
+ protected function _fclose($fp, $path = '')
1682
+ {
1683
+ is_resource($fp) && fclose($fp);
1684
+ if ($path) {
1685
+ unlink($this->getTempFile($path));
1686
+ }
1687
+ }
1688
+
1689
+ /******************** file/dir manipulations *************************/
1690
+
1691
+ /**
1692
+ * Create dir and return created dir path or false on failed.
1693
+ *
1694
+ * @param string $path parent dir path
1695
+ * @param string $name new directory name
1696
+ *
1697
+ * @return string|bool
1698
+ * @author Dmitry (dio) Levashov
1699
+ **/
1700
+ protected function _mkdir($path, $name)
1701
+ {
1702
+ $namePath = $this->_joinPath($path, $name);
1703
+ list($parentId) = $this->_od_splitPath($namePath);
1704
+
1705
+ try {
1706
+ $properties = array(
1707
+ 'name' => (string)$name,
1708
+ 'folder' => (object)array(),
1709
+ );
1710
+
1711
+ $data = (object)$properties;
1712
+
1713
+ $url = self::API_URL . $parentId . '/children';
1714
+
1715
+ $curl = $this->_od_prepareCurl($url);
1716
+
1717
+ curl_setopt_array($curl, array(
1718
+ CURLOPT_POST => true,
1719
+ CURLOPT_POSTFIELDS => json_encode($data),
1720
+ ));
1721
+
1722
+ //create the Folder in the Parent
1723
+ $result = elFinder::curlExec($curl);
1724
+ $folder = json_decode($result);
1725
+
1726
+ return $this->_joinPath($path, $folder->id);
1727
+ } catch (Exception $e) {
1728
+ return $this->setError('OneDrive error: ' . $e->getMessage());
1729
+ }
1730
+ }
1731
+
1732
+ /**
1733
+ * Create file and return it's path or false on failed.
1734
+ *
1735
+ * @param string $path parent dir path
1736
+ * @param string $name new file name
1737
+ *
1738
+ * @return string|bool
1739
+ * @author Dmitry (dio) Levashov
1740
+ **/
1741
+ protected function _mkfile($path, $name)
1742
+ {
1743
+ return $this->_save($this->tmpfile(), $path, $name, array());
1744
+ }
1745
+
1746
+ /**
1747
+ * Create symlink. FTP driver does not support symlinks.
1748
+ *
1749
+ * @param string $target link target
1750
+ * @param string $path symlink path
1751
+ *
1752
+ * @return bool
1753
+ * @author Dmitry (dio) Levashov
1754
+ **/
1755
+ protected function _symlink($target, $path, $name)
1756
+ {
1757
+ return false;
1758
+ }
1759
+
1760
+ /**
1761
+ * Copy file into another file.
1762
+ *
1763
+ * @param string $source source file path
1764
+ * @param string $targetDir target directory path
1765
+ * @param string $name new file name
1766
+ *
1767
+ * @return bool
1768
+ * @author Dmitry (dio) Levashov
1769
+ **/
1770
+ protected function _copy($source, $targetDir, $name)
1771
+ {
1772
+ $path = $this->_joinPath($targetDir, $name);
1773
+
1774
+ try {
1775
+ //Set the Parent id
1776
+ list(, $parentId) = $this->_od_splitPath($targetDir);
1777
+ list(, $itemId) = $this->_od_splitPath($source);
1778
+
1779
+ $url = self::API_URL . $itemId . '/copy';
1780
+
1781
+ $properties = array(
1782
+ 'name' => (string)$name,
1783
+ );
1784
+ if ($parentId === 'root') {
1785
+ $properties['parentReference'] = (object)array('path' => '/drive/root:');
1786
+ } else {
1787
+ $properties['parentReference'] = (object)array('id' => (string)$parentId);
1788
+ }
1789
+ $data = (object)$properties;
1790
+ $curl = $this->_od_prepareCurl($url);
1791
+ curl_setopt_array($curl, array(
1792
+ CURLOPT_POST => true,
1793
+ CURLOPT_HEADER => true,
1794
+ CURLOPT_HTTPHEADER => array(
1795
+ 'Content-Type: application/json',
1796
+ 'Authorization: Bearer ' . $this->token->data->access_token,
1797
+ 'Prefer: respond-async',
1798
+ ),
1799
+ CURLOPT_POSTFIELDS => json_encode($data),
1800
+ ));
1801
+ $result = elFinder::curlExec($curl);
1802
+
1803
+ $res = new stdClass();
1804
+ if (preg_match('/Location: (.+)/', $result, $m)) {
1805
+ $monUrl = trim($m[1]);
1806
+ while ($res) {
1807
+ usleep(200000);
1808
+ $curl = curl_init($monUrl);
1809
+ curl_setopt_array($curl, array(
1810
+ CURLOPT_RETURNTRANSFER => true,
1811
+ CURLOPT_HTTPHEADER => array(
1812
+ 'Content-Type: application/json',
1813
+ ),
1814
+ ));
1815
+ $res = json_decode(elFinder::curlExec($curl));
1816
+ if (isset($res->status)) {
1817
+ if ($res->status === 'completed' || $res->status === 'failed') {
1818
+ break;
1819
+ }
1820
+ } elseif (isset($res->error)) {
1821
+ return $this->setError('OneDrive error: ' . $res->error->message);
1822
+ }
1823
+ }
1824
+ }
1825
+
1826
+ if ($res && isset($res->resourceId)) {
1827
+ if (isset($res->folder) && isset($this->sessionCache['subdirs'])) {
1828
+ $this->sessionCache['subdirs'][$targetDir] = true;
1829
+ }
1830
+
1831
+ return $this->_joinPath($targetDir, $res->resourceId);
1832
+ }
1833
+
1834
+ return false;
1835
+ } catch (Exception $e) {
1836
+ return $this->setError('OneDrive error: ' . $e->getMessage());
1837
+ }
1838
+
1839
+ return true;
1840
+ }
1841
+
1842
+ /**
1843
+ * Move file into another parent dir.
1844
+ * Return new file path or false.
1845
+ *
1846
+ * @param string $source source file path
1847
+ * @param $targetDir
1848
+ * @param string $name file name
1849
+ *
1850
+ * @return string|bool
1851
+ * @author Dmitry (dio) Levashov
1852
+ */
1853
+ protected function _move($source, $targetDir, $name)
1854
+ {
1855
+ try {
1856
+ list(, $targetParentId) = $this->_od_splitPath($targetDir);
1857
+ list($sourceParentId, $itemId, $srcParent) = $this->_od_splitPath($source);
1858
+
1859
+ $properties = array(
1860
+ 'name' => (string)$name,
1861
+ );
1862
+ if ($targetParentId !== $sourceParentId) {
1863
+ $properties['parentReference'] = (object)array('id' => (string)$targetParentId);
1864
+ }
1865
+
1866
+ $url = self::API_URL . $itemId;
1867
+ $data = (object)$properties;
1868
+
1869
+ $curl = $this->_od_prepareCurl($url);
1870
+
1871
+ curl_setopt_array($curl, array(
1872
+ CURLOPT_CUSTOMREQUEST => 'PATCH',
1873
+ CURLOPT_POSTFIELDS => json_encode($data),
1874
+ ));
1875
+
1876
+ $result = json_decode(elFinder::curlExec($curl));
1877
+ if ($result && isset($result->id)) {
1878
+ return $targetDir . '/' . $result->id;
1879
+ } else {
1880
+ return false;
1881
+ }
1882
+ } catch (Exception $e) {
1883
+ return $this->setError('OneDrive error: ' . $e->getMessage());
1884
+ }
1885
+
1886
+ return false;
1887
+ }
1888
+
1889
+ /**
1890
+ * Remove file.
1891
+ *
1892
+ * @param string $path file path
1893
+ *
1894
+ * @return bool
1895
+ * @author Dmitry (dio) Levashov
1896
+ **/
1897
+ protected function _unlink($path)
1898
+ {
1899
+ $stat = $this->stat($path);
1900
+ try {
1901
+ list(, $itemId) = $this->_od_splitPath($path);
1902
+
1903
+ $url = self::API_URL . $itemId;
1904
+
1905
+ $curl = $this->_od_prepareCurl($url);
1906
+ curl_setopt_array($curl, array(
1907
+ CURLOPT_CUSTOMREQUEST => 'DELETE',
1908
+ ));
1909
+
1910
+ //unlink or delete File or Folder in the Parent
1911
+ $result = elFinder::curlExec($curl);
1912
+ } catch (Exception $e) {
1913
+ return $this->setError('OneDrive error: ' . $e->getMessage());
1914
+ }
1915
+
1916
+ return true;
1917
+ }
1918
+
1919
+ /**
1920
+ * Remove dir.
1921
+ *
1922
+ * @param string $path dir path
1923
+ *
1924
+ * @return bool
1925
+ * @author Dmitry (dio) Levashov
1926
+ **/
1927
+ protected function _rmdir($path)
1928
+ {
1929
+ return $this->_unlink($path);
1930
+ }
1931
+
1932
+ /**
1933
+ * Create new file and write into it from file pointer.
1934
+ * Return new file path or false on error.
1935
+ *
1936
+ * @param resource $fp file pointer
1937
+ * @param $path
1938
+ * @param string $name file name
1939
+ * @param array $stat file stat (required by some virtual fs)
1940
+ *
1941
+ * @return bool|string
1942
+ * @author Dmitry (dio) Levashov
1943
+ */
1944
+ protected function _save($fp, $path, $name, $stat)
1945
+ {
1946
+ $itemId = '';
1947
+ $size = null;
1948
+ if ($name === '') {
1949
+ list($parentId, $itemId, $parent) = $this->_od_splitPath($path);
1950
+ } else {
1951
+ if ($stat) {
1952
+ if (isset($stat['name'])) {
1953
+ $name = $stat['name'];
1954
+ }
1955
+ if (isset($stat['rev']) && strpos($stat['hash'], $this->id) === 0) {
1956
+ $itemId = $stat['rev'];
1957
+ }
1958
+ }
1959
+ list(, $parentId) = $this->_od_splitPath($path);
1960
+ $parent = $path;
1961
+ }
1962
+
1963
+ if ($stat && isset($stat['size'])) {
1964
+ $size = $stat['size'];
1965
+ } else {
1966
+ $stats = fstat($fp);
1967
+ if (isset($stats[7])) {
1968
+ $size = $stats[7];
1969
+ }
1970
+ }
1971
+
1972
+ if ($size > 4194304) {
1973
+ return $this->_od_uploadSession($fp, $size, $name, $itemId, $parent, $parentId);
1974
+ }
1975
+
1976
+ try {
1977
+ // for unseekable file pointer
1978
+ if (!elFinder::isSeekableStream($fp)) {
1979
+ if ($tfp = tmpfile()) {
1980
+ if (stream_copy_to_stream($fp, $tfp, $size? $size : -1) !== false) {
1981
+ rewind($tfp);
1982
+ $fp = $tfp;
1983
+ }
1984
+ }
1985
+ }
1986
+
1987
+ //Create or Update a file
1988
+ if ($itemId === '') {
1989
+ $url = self::API_URL . $parentId . ':/' . rawurlencode($name) . ':/content';
1990
+ } else {
1991
+ $url = self::API_URL . $itemId . '/content';
1992
+ }
1993
+ $curl = $this->_od_prepareCurl();
1994
+
1995
+ $options = array(
1996
+ CURLOPT_URL => $url,
1997
+ CURLOPT_PUT => true,
1998
+ CURLOPT_INFILE => $fp,
1999
+ );
2000
+ // Size
2001
+ if ($size !== null) {
2002
+ $options[CURLOPT_INFILESIZE] = $size;
2003
+ }
2004
+
2005
+ curl_setopt_array($curl, $options);
2006
+
2007
+ //create or update File in the Target
2008
+ $file = json_decode(elFinder::curlExec($curl));
2009
+
2010
+ return $this->_joinPath($parent, $file->id);
2011
+ } catch (Exception $e) {
2012
+ return $this->setError('OneDrive error: ' . $e->getMessage());
2013
+ }
2014
+ }
2015
+
2016
+ /**
2017
+ * Get file contents.
2018
+ *
2019
+ * @param string $path file path
2020
+ *
2021
+ * @return string|false
2022
+ * @author Dmitry (dio) Levashov
2023
+ **/
2024
+ protected function _getContents($path)
2025
+ {
2026
+ $contents = '';
2027
+
2028
+ try {
2029
+ list(, $itemId) = $this->_od_splitPath($path);
2030
+ $url = self::API_URL . $itemId . '/content';
2031
+ $contents = $this->_od_createCurl($url, $contents = true);
2032
+ } catch (Exception $e) {
2033
+ return $this->setError('OneDrive error: ' . $e->getMessage());
2034
+ }
2035
+
2036
+ return $contents;
2037
+ }
2038
+
2039
+ /**
2040
+ * Write a string to a file.
2041
+ *
2042
+ * @param string $path file path
2043
+ * @param string $content new file content
2044
+ *
2045
+ * @return bool
2046
+ * @author Dmitry (dio) Levashov
2047
+ **/
2048
+ protected function _filePutContents($path, $content)
2049
+ {
2050
+ $res = false;
2051
+
2052
+ if ($local = $this->getTempFile($path)) {
2053
+ if (file_put_contents($local, $content, LOCK_EX) !== false
2054
+ && ($fp = fopen($local, 'rb'))) {
2055
+ clearstatcache();
2056
+ $res = $this->_save($fp, $path, '', array());
2057
+ fclose($fp);
2058
+ }
2059
+ file_exists($local) && unlink($local);
2060
+ }
2061
+
2062
+ return $res;
2063
+ }
2064
+
2065
+ /**
2066
+ * Detect available archivers.
2067
+ **/
2068
+ protected function _checkArchivers()
2069
+ {
2070
+ // die('Not yet implemented. (_checkArchivers)');
2071
+ return array();
2072
+ }
2073
+
2074
+ /**
2075
+ * chmod implementation.
2076
+ *
2077
+ * @return bool
2078
+ **/
2079
+ protected function _chmod($path, $mode)
2080
+ {
2081
+ return false;
2082
+ }
2083
+
2084
+ /**
2085
+ * Unpack archive.
2086
+ *
2087
+ * @param string $path archive path
2088
+ * @param array $arc archiver command and arguments (same as in $this->archivers)
2089
+ *
2090
+ * @return void
2091
+ * @author Dmitry (dio) Levashov
2092
+ * @author Alexey Sukhotin
2093
+ */
2094
+ protected function _unpack($path, $arc)
2095
+ {
2096
+ die('Not yet implemented. (_unpack)');
2097
+ //return false;
2098
+ }
2099
+
2100
+ /**
2101
+ * Extract files from archive.
2102
+ *
2103
+ * @param string $path archive path
2104
+ * @param array $arc archiver command and arguments (same as in $this->archivers)
2105
+ *
2106
+ * @return void
2107
+ * @author Dmitry (dio) Levashov,
2108
+ * @author Alexey Sukhotin
2109
+ */
2110
+ protected function _extract($path, $arc)
2111
+ {
2112
+ die('Not yet implemented. (_extract)');
2113
+ }
2114
+
2115
+ /**
2116
+ * Create archive and return its path.
2117
+ *
2118
+ * @param string $dir target dir
2119
+ * @param array $files files names list
2120
+ * @param string $name archive name
2121
+ * @param array $arc archiver options
2122
+ *
2123
+ * @return string|bool
2124
+ * @author Dmitry (dio) Levashov,
2125
+ * @author Alexey Sukhotin
2126
+ **/
2127
+ protected function _archive($dir, $files, $name, $arc)
2128
+ {
2129
+ die('Not yet implemented. (_archive)');
2130
+ }
2131
+ } // END class