drg_elfinder 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +28 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/config/drg_elfinder_manifest.js +1 -0
  6. data/app/assets/javascripts/drg_elfinder.js +15 -0
  7. data/app/assets/javascripts/elfinder/Changelog +1283 -0
  8. data/app/assets/javascripts/elfinder/LICENSE.md +15 -0
  9. data/app/assets/javascripts/elfinder/README.md +216 -0
  10. data/app/assets/javascripts/elfinder/bower.json +28 -0
  11. data/app/assets/javascripts/elfinder/composer.json +39 -0
  12. data/app/assets/javascripts/elfinder/css/elfinder.full.css +5350 -0
  13. data/app/assets/javascripts/elfinder/css/elfinder.min.css +9 -0
  14. data/app/assets/javascripts/elfinder/css/theme.css +430 -0
  15. data/app/assets/javascripts/elfinder/elfinder.html +74 -0
  16. data/app/assets/javascripts/elfinder/elfinder.legacy.html +94 -0
  17. data/app/assets/javascripts/elfinder/img/arrows-active.png +0 -0
  18. data/app/assets/javascripts/elfinder/img/arrows-normal.png +0 -0
  19. data/app/assets/javascripts/elfinder/img/crop.gif +0 -0
  20. data/app/assets/javascripts/elfinder/img/dialogs.png +0 -0
  21. data/app/assets/javascripts/elfinder/img/edit_aceeditor.png +0 -0
  22. data/app/assets/javascripts/elfinder/img/edit_ckeditor.png +0 -0
  23. data/app/assets/javascripts/elfinder/img/edit_ckeditor5.png +0 -0
  24. data/app/assets/javascripts/elfinder/img/edit_codemirror.png +0 -0
  25. data/app/assets/javascripts/elfinder/img/edit_creativecloud.png +0 -0
  26. data/app/assets/javascripts/elfinder/img/edit_onlineconvert.png +0 -0
  27. data/app/assets/javascripts/elfinder/img/edit_pixlreditor.png +0 -0
  28. data/app/assets/javascripts/elfinder/img/edit_pixlrexpress.png +0 -0
  29. data/app/assets/javascripts/elfinder/img/edit_simplemde.png +0 -0
  30. data/app/assets/javascripts/elfinder/img/edit_tinymce.png +0 -0
  31. data/app/assets/javascripts/elfinder/img/edit_tuiimgedit.png +0 -0
  32. data/app/assets/javascripts/elfinder/img/edit_zohooffice.png +0 -0
  33. data/app/assets/javascripts/elfinder/img/editor-icons.png +0 -0
  34. data/app/assets/javascripts/elfinder/img/icons-big.png +0 -0
  35. data/app/assets/javascripts/elfinder/img/icons-big.svg +1 -0
  36. data/app/assets/javascripts/elfinder/img/icons-small.png +0 -0
  37. data/app/assets/javascripts/elfinder/img/logo.png +0 -0
  38. data/app/assets/javascripts/elfinder/img/progress.gif +0 -0
  39. data/app/assets/javascripts/elfinder/img/quicklook-bg.png +0 -0
  40. data/app/assets/javascripts/elfinder/img/quicklook-icons.png +0 -0
  41. data/app/assets/javascripts/elfinder/img/resize.png +0 -0
  42. data/app/assets/javascripts/elfinder/img/spinner-mini.gif +0 -0
  43. data/app/assets/javascripts/elfinder/img/toolbar.png +0 -0
  44. data/app/assets/javascripts/elfinder/img/trashmesh.png +0 -0
  45. data/app/assets/javascripts/elfinder/img/tui-icon-a.svg +235 -0
  46. data/app/assets/javascripts/elfinder/img/tui-icon-b.svg +224 -0
  47. data/app/assets/javascripts/elfinder/img/tui-icon-c.svg +224 -0
  48. data/app/assets/javascripts/elfinder/img/tui-icon-d.svg +224 -0
  49. data/app/assets/javascripts/elfinder/img/ui-icons_ffffff_256x240.png +0 -0
  50. data/app/assets/javascripts/elfinder/img/volume_icon_box.png +0 -0
  51. data/app/assets/javascripts/elfinder/img/volume_icon_box.svg +1 -0
  52. data/app/assets/javascripts/elfinder/img/volume_icon_dropbox.png +0 -0
  53. data/app/assets/javascripts/elfinder/img/volume_icon_dropbox.svg +1 -0
  54. data/app/assets/javascripts/elfinder/img/volume_icon_ftp.png +0 -0
  55. data/app/assets/javascripts/elfinder/img/volume_icon_ftp.svg +1 -0
  56. data/app/assets/javascripts/elfinder/img/volume_icon_googledrive.png +0 -0
  57. data/app/assets/javascripts/elfinder/img/volume_icon_googledrive.svg +1 -0
  58. data/app/assets/javascripts/elfinder/img/volume_icon_local.png +0 -0
  59. data/app/assets/javascripts/elfinder/img/volume_icon_local.svg +1 -0
  60. data/app/assets/javascripts/elfinder/img/volume_icon_network.png +0 -0
  61. data/app/assets/javascripts/elfinder/img/volume_icon_network.svg +1 -0
  62. data/app/assets/javascripts/elfinder/img/volume_icon_onedrive.png +0 -0
  63. data/app/assets/javascripts/elfinder/img/volume_icon_onedrive.svg +1 -0
  64. data/app/assets/javascripts/elfinder/img/volume_icon_sql.png +0 -0
  65. data/app/assets/javascripts/elfinder/img/volume_icon_sql.svg +1 -0
  66. data/app/assets/javascripts/elfinder/img/volume_icon_trash.png +0 -0
  67. data/app/assets/javascripts/elfinder/img/volume_icon_trash.svg +1 -0
  68. data/app/assets/javascripts/elfinder/img/volume_icon_zip.png +0 -0
  69. data/app/assets/javascripts/elfinder/img/volume_icon_zip.svg +1 -0
  70. data/app/assets/javascripts/elfinder/js/elfinder.full.js +36019 -0
  71. data/app/assets/javascripts/elfinder/js/elfinder.min.js +25 -0
  72. data/app/assets/javascripts/elfinder/js/extras/editors.default.js +2643 -0
  73. data/app/assets/javascripts/elfinder/js/extras/editors.default.min.js +2 -0
  74. data/app/assets/javascripts/elfinder/js/extras/quicklook.googledocs.js +75 -0
  75. data/app/assets/javascripts/elfinder/js/extras/quicklook.googledocs.min.js +1 -0
  76. data/app/assets/javascripts/elfinder/js/i18n/elfinder.LANG.js +587 -0
  77. data/app/assets/javascripts/elfinder/js/i18n/elfinder.ar.js +580 -0
  78. data/app/assets/javascripts/elfinder/js/i18n/elfinder.bg.js +559 -0
  79. data/app/assets/javascripts/elfinder/js/i18n/elfinder.ca.js +375 -0
  80. data/app/assets/javascripts/elfinder/js/i18n/elfinder.cs.js +581 -0
  81. data/app/assets/javascripts/elfinder/js/i18n/elfinder.da.js +580 -0
  82. data/app/assets/javascripts/elfinder/js/i18n/elfinder.de.js +582 -0
  83. data/app/assets/javascripts/elfinder/js/i18n/elfinder.el.js +374 -0
  84. data/app/assets/javascripts/elfinder/js/i18n/elfinder.es.js +546 -0
  85. data/app/assets/javascripts/elfinder/js/i18n/elfinder.fa.js +580 -0
  86. data/app/assets/javascripts/elfinder/js/i18n/elfinder.fallback.js +11 -0
  87. data/app/assets/javascripts/elfinder/js/i18n/elfinder.fo.js +419 -0
  88. data/app/assets/javascripts/elfinder/js/i18n/elfinder.fr.js +578 -0
  89. data/app/assets/javascripts/elfinder/js/i18n/elfinder.fr_CA.js +580 -0
  90. data/app/assets/javascripts/elfinder/js/i18n/elfinder.he.js +375 -0
  91. data/app/assets/javascripts/elfinder/js/i18n/elfinder.hr.js +434 -0
  92. data/app/assets/javascripts/elfinder/js/i18n/elfinder.hu.js +580 -0
  93. data/app/assets/javascripts/elfinder/js/i18n/elfinder.id.js +498 -0
  94. data/app/assets/javascripts/elfinder/js/i18n/elfinder.it.js +552 -0
  95. data/app/assets/javascripts/elfinder/js/i18n/elfinder.ja.js +581 -0
  96. data/app/assets/javascripts/elfinder/js/i18n/elfinder.ko.js +582 -0
  97. data/app/assets/javascripts/elfinder/js/i18n/elfinder.nl.js +581 -0
  98. data/app/assets/javascripts/elfinder/js/i18n/elfinder.no.js +374 -0
  99. data/app/assets/javascripts/elfinder/js/i18n/elfinder.pl.js +580 -0
  100. data/app/assets/javascripts/elfinder/js/i18n/elfinder.pt_BR.js +580 -0
  101. data/app/assets/javascripts/elfinder/js/i18n/elfinder.ro.js +417 -0
  102. data/app/assets/javascripts/elfinder/js/i18n/elfinder.ru.js +582 -0
  103. data/app/assets/javascripts/elfinder/js/i18n/elfinder.si.js +537 -0
  104. data/app/assets/javascripts/elfinder/js/i18n/elfinder.sk.js +581 -0
  105. data/app/assets/javascripts/elfinder/js/i18n/elfinder.sl.js +374 -0
  106. data/app/assets/javascripts/elfinder/js/i18n/elfinder.sr.js +374 -0
  107. data/app/assets/javascripts/elfinder/js/i18n/elfinder.sv.js +375 -0
  108. data/app/assets/javascripts/elfinder/js/i18n/elfinder.tr.js +583 -0
  109. data/app/assets/javascripts/elfinder/js/i18n/elfinder.ug_CN.js +374 -0
  110. data/app/assets/javascripts/elfinder/js/i18n/elfinder.uk.js +580 -0
  111. data/app/assets/javascripts/elfinder/js/i18n/elfinder.vi.js +579 -0
  112. data/app/assets/javascripts/elfinder/js/i18n/elfinder.zh_CN.js +585 -0
  113. data/app/assets/javascripts/elfinder/js/i18n/elfinder.zh_TW.js +582 -0
  114. data/app/assets/javascripts/elfinder/js/i18n/help/cs.html.js +10 -0
  115. data/app/assets/javascripts/elfinder/js/i18n/help/de.html.js +15 -0
  116. data/app/assets/javascripts/elfinder/js/i18n/help/en.html.js +10 -0
  117. data/app/assets/javascripts/elfinder/js/i18n/help/es.html.js +10 -0
  118. data/app/assets/javascripts/elfinder/js/i18n/help/ja.html.js +10 -0
  119. data/app/assets/javascripts/elfinder/js/i18n/help/ko.html.js +10 -0
  120. data/app/assets/javascripts/elfinder/js/i18n/help/pl.html.js +10 -0
  121. data/app/assets/javascripts/elfinder/js/i18n/help/ru.html.js +10 -0
  122. data/app/assets/javascripts/elfinder/js/i18n/help/sk.html.js +10 -0
  123. data/app/assets/javascripts/elfinder/js/i18n/help/tr.html.js +10 -0
  124. data/app/assets/javascripts/elfinder/js/proxy/elFinderSupportVer1.js +408 -0
  125. data/app/assets/javascripts/elfinder/js/worker/calcfilehash.js +20 -0
  126. data/app/assets/javascripts/elfinder/js/worker/quicklook.tiff.js +7 -0
  127. data/app/assets/javascripts/elfinder/js/worker/quicklook.unzip.js +55 -0
  128. data/app/assets/javascripts/elfinder/main.default.js +175 -0
  129. data/app/assets/javascripts/elfinder/package.json +13 -0
  130. data/app/assets/javascripts/elfinder/php/MySQLStorage.sql +47 -0
  131. data/app/assets/javascripts/elfinder/php/autoload.php +56 -0
  132. data/app/assets/javascripts/elfinder/php/connector.maximal.php-dist +449 -0
  133. data/app/assets/javascripts/elfinder/php/connector.minimal.php-dist +180 -0
  134. data/app/assets/javascripts/elfinder/php/editors/OnlineConvert/editor.php +113 -0
  135. data/app/assets/javascripts/elfinder/php/editors/ZipArchive/editor.php +12 -0
  136. data/app/assets/javascripts/elfinder/php/editors/ZohoOffice/editor.php +206 -0
  137. data/app/assets/javascripts/elfinder/php/editors/editor.php +79 -0
  138. data/app/assets/javascripts/elfinder/php/elFinder.class.php +5401 -0
  139. data/app/assets/javascripts/elfinder/php/elFinderConnector.class.php +380 -0
  140. data/app/assets/javascripts/elfinder/php/elFinderFlysystemGoogleDriveNetmount.php +380 -0
  141. data/app/assets/javascripts/elfinder/php/elFinderPlugin.php +113 -0
  142. data/app/assets/javascripts/elfinder/php/elFinderSession.php +335 -0
  143. data/app/assets/javascripts/elfinder/php/elFinderSessionInterface.php +57 -0
  144. data/app/assets/javascripts/elfinder/php/elFinderVolumeBox.class.php +1972 -0
  145. data/app/assets/javascripts/elfinder/php/elFinderVolumeDriver.class.php +7651 -0
  146. data/app/assets/javascripts/elfinder/php/elFinderVolumeDropbox.class.php +1464 -0
  147. data/app/assets/javascripts/elfinder/php/elFinderVolumeDropbox2.class.php +1516 -0
  148. data/app/assets/javascripts/elfinder/php/elFinderVolumeFTP.class.php +1810 -0
  149. data/app/assets/javascripts/elfinder/php/elFinderVolumeGoogleDrive.class.php +2163 -0
  150. data/app/assets/javascripts/elfinder/php/elFinderVolumeGroup.class.php +315 -0
  151. data/app/assets/javascripts/elfinder/php/elFinderVolumeLocalFileSystem.class.php +1477 -0
  152. data/app/assets/javascripts/elfinder/php/elFinderVolumeMySQL.class.php +1022 -0
  153. data/app/assets/javascripts/elfinder/php/elFinderVolumeOneDrive.class.php +2131 -0
  154. data/app/assets/javascripts/elfinder/php/elFinderVolumeSFTPphpseclib.class.php +838 -0
  155. data/app/assets/javascripts/elfinder/php/elFinderVolumeTrash.class.php +51 -0
  156. data/app/assets/javascripts/elfinder/php/elFinderVolumeTrashMySQL.class.php +51 -0
  157. data/app/assets/javascripts/elfinder/php/libs/GdBmp.php +473 -0
  158. data/app/assets/javascripts/elfinder/php/mime.types +781 -0
  159. data/app/assets/javascripts/elfinder/php/plugins/AutoResize/plugin.php +151 -0
  160. data/app/assets/javascripts/elfinder/php/plugins/AutoRotate/plugin.php +148 -0
  161. data/app/assets/javascripts/elfinder/php/plugins/Normalizer/plugin.php +204 -0
  162. data/app/assets/javascripts/elfinder/php/plugins/Sanitizer/plugin.php +157 -0
  163. data/app/assets/javascripts/elfinder/php/plugins/Watermark/logo.png +0 -0
  164. data/app/assets/javascripts/elfinder/php/plugins/Watermark/plugin.php +432 -0
  165. data/app/assets/javascripts/elfinder/php/plugins/WinRemoveTailDots/plugin.php +114 -0
  166. data/app/assets/javascripts/elfinder/php/resources/image.png +0 -0
  167. data/app/assets/javascripts/elfinder/php/resources/video.png +0 -0
  168. data/app/assets/javascripts/elfinder/sounds/rm.wav +0 -0
  169. data/app/controllers/dc_elfinder_controller.rb +63 -0
  170. data/app/models/drgcms_form_fields/elfinder.rb +85 -0
  171. data/changelog.md +0 -0
  172. data/lib/drg_elfinder/engine.rb +5 -0
  173. data/lib/drg_elfinder/version.rb +3 -0
  174. data/lib/drg_elfinder.rb +9 -0
  175. data/lib/el_finder/action.rb +19 -0
  176. data/lib/el_finder/base64.rb +24 -0
  177. data/lib/el_finder/connector.rb +625 -0
  178. data/lib/el_finder/image.rb +33 -0
  179. data/lib/el_finder/mime_type.rb +86 -0
  180. data/lib/el_finder/pathname.rb +185 -0
  181. data/lib/el_finder/version.rb +5 -0
  182. data/lib/el_finder.rb +8 -0
  183. data/lib/patches/patch_for_elfinder.rb +115 -0
  184. data/lib/tasks/drg_elfinder_tasks.rake +10 -0
  185. metadata +245 -0
@@ -0,0 +1,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