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