elFinderVolumeBox   D
last analyzed

Complexity

Total Complexity 247

Size/Duplication

Total Lines 1825
Duplicated Lines 20.11 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
dl 367
loc 1825
rs 4.4102
c 0
b 0
f 0
wmc 247
lcom 1
cbo 3

55 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 18 18 1
F netmountPrepare() 93 158 33
A netunmount() 10 10 3
A umount() 0 3 1
C getContentUrl() 7 34 7
A _bd_splitPath() 21 21 3
B _bd_obtainAccessToken() 0 42 4
B _bd_refreshToken() 3 57 8
A _bd_prepareCurl() 0 13 1
D _bd_fetch() 7 39 10
C _bd_curlExec() 0 44 11
D _bd_query() 0 36 9
A _bd_getRawItem() 0 14 3
C _bd_parseRaw() 0 27 8
A _bd_getThumbnail() 14 14 2
B _bd_unlink() 0 24 3
C init() 12 61 15
A configure() 0 12 3
B isNameExists() 0 34 2
D cacheDir() 0 35 9
A copy() 5 8 2
C remove() 29 29 7
C createTmb() 56 56 19
A tmbname() 0 4 1
C getSharedWebContentLink() 10 29 12
A _dirname() 0 6 1
A _basename() 0 6 1
A _joinPath() 0 8 2
A _normpath() 9 9 2
A _relpath() 0 4 1
A _abspath() 0 4 1
A _path() 0 4 1
A _inpath() 0 4 2
A _stat() 0 8 2
A _subdirs() 0 16 3
B _dimensions() 7 18 5
A _scandir() 0 6 2
A _fopen() 14 14 3
A _fclose() 0 7 2
A _mkdir() 0 22 2
A _mkfile() 0 4 1
A _symlink() 0 4 1
B _copy() 7 37 6
B _move() 0 37 5
A _unlink() 0 4 1
A _rmdir() 0 4 1
F _save() 14 59 12
A _getContents() 15 15 2
B _filePutContents() 16 16 5
A _checkArchivers() 0 5 1
A _chmod() 0 4 1
A _unpack() 0 5 1
A _findSymlinks() 0 4 1
A _extract() 0 4 1
A _archive() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like elFinderVolumeBox often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use elFinderVolumeBox, and based on these observations, apply Extract Interface, too.

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 12 and the first side effect is on line 3.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
3
elFinder::$netDrivers['box'] = 'Box';
4
5
/**
6
 * Simple elFinder driver for BoxDrive
7
 * Box.com API v2.0.
8
 *
9
 * @author Dmitry (dio) Levashov
10
 * @author Cem (discofever)
11
 **/
12
class elFinderVolumeBox extends elFinderVolumeDriver
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
13
{
14
    /**
15
     * @var string The base URL for API requests
16
     */
17
    const API_URL = 'https://api.box.com/2.0';
18
19
    /**
20
     * @var string The base URL for authorization requests
21
     */
22
    const AUTH_URL = 'https://www.box.com/api/oauth2/authorize';
23
24
    /**
25
     * @var string The base URL for token requests
26
     */
27
    const TOKEN_URL = 'https://www.box.com/api/oauth2/token';
28
29
    /**
30
     * @var string The base URL for upload requests
31
     */
32
    const UPLOAD_URL = 'https://upload.box.com/api/2.0';
33
34
    /**
35
     * Fetch fields list.
36
     *
37
     * @var string
38
     */
39
    const FETCHFIELDS = 'type,id,name,created_at,modified_at,description,size,parent,permissions,file_version,shared_link';
40
41
    /**
42
     * Net mount key.
43
     *
44
     * @var string
45
     **/
46
    public $netMountKey = '';
47
    /**
48
     * Driver id
49
     * Must be started from letter and contains [a-z0-9]
50
     * Used as part of volume id.
51
     *
52
     * @var string
53
     **/
54
    protected $driverId = 'bd';
55
56
    /**
57
     * Box.com token object.
58
     *
59
     * @var object
60
     **/
61
    protected $token = null;
62
63
    /**
64
     * Directory for tmp files
65
     * If not set driver will try to use tmbDir as tmpDir.
66
     *
67
     * @var string
68
     **/
69
    protected $tmp = '';
70
71
    /**
72
     * hasCache by folders.
73
     *
74
     * @var array
75
     **/
76
    protected $HasdirsCache = [];
77
78
    /**
79
     * Thumbnail prefix.
80
     *
81
     * @var string
82
     **/
83
    private $tmbPrefix = '';
84
85
    /**
86
     * Constructor
87
     * Extend options with required fields.
88
     *
89
     * @author Dmitry (dio) Levashov
90
     * @author Cem (DiscoFever)
91
     **/
92 View Code Duplication
    public function __construct()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
93
    {
94
        $opts = [
95
            'client_id' => '',
96
            'client_secret' => '',
97
            'accessToken' => '',
98
            'root' => 'Box.com',
99
            'path' => '/',
100
            'separator' => '/',
101
            'tmbPath' => '',
102
            'tmbURL' => '',
103
            'tmpPath' => '',
104
            'acceptedName' => '#^[^/\\?*:|"<>]*[^./\\?*:|"<>]$#',
105
            'rootCssClass' => 'elfinder-navbar-root-box',
106
        ];
107
        $this->options = array_merge($this->options, $opts);
108
        $this->options['mimeDetect'] = 'internal';
109
    }
110
111
    /*********************************************************************/
112
    /*                        OVERRIDE FUNCTIONS                         */
113
    /*********************************************************************/
114
115
    /**
116
     * Prepare
117
     * Call from elFinder::netmout() before volume->mount().
118
     *
119
     * @return array
120
     *
121
     * @author Naoki Sawada
122
     * @author Raja Sharma updating for Box
123
     **/
124
    public function netmountPrepare($options)
0 ignored issues
show
Coding Style introduced by
netmountPrepare uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
netmountPrepare uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
netmountPrepare uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
125
    {
126
        if (empty($options['client_id']) && defined('ELFINDER_BOX_CLIENTID')) {
127
            $options['client_id'] = ELFINDER_BOX_CLIENTID;
128
        }
129
        if (empty($options['client_secret']) && defined('ELFINDER_BOX_CLIENTSECRET')) {
130
            $options['client_secret'] = ELFINDER_BOX_CLIENTSECRET;
131
        }
132
133 View Code Duplication
        if (isset($options['pass']) && $options['pass'] === 'reauth') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
134
            $options['user'] = 'init';
135
            $options['pass'] = '';
136
            $this->session->remove('BoxTokens');
137
        }
138
139 View Code Duplication
        if (isset($options['id'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
140
            $this->session->set('nodeId', $options['id']);
141
        } elseif ($_id = $this->session->get('nodeId')) {
142
            $options['id'] = $_id;
143
            $this->session->set('nodeId', $_id);
144
        }
145
146
        try {
147 View Code Duplication
            if (empty($options['client_id']) || empty($options['client_secret'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
148
                return ['exit' => true, 'body' => '{msg:errNetMountNoDriver}'];
149
            }
150
151 View Code Duplication
            if (isset($_GET['code'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
152
                try {
153
                    // Obtain the token using the code received by the Box.com API
154
                    $this->session->set('BoxTokens',
155
                                        $this->_bd_obtainAccessToken($options['client_id'], $options['client_secret'], $_GET['code']));
156
157
                    $out = [
158
                            'node' => $options['id'],
159
                            'json' => '{"protocol": "box", "mode": "done", "reset": 1}',
160
                            'bind' => 'netmount',
161
162
                    ];
163
164
                    return ['exit' => 'callback', 'out' => $out];
165
                } catch (Exception $e) {
166
                    $out = [
167
                            'node' => $options['id'],
168
                            'json' => json_encode(['error' => $e->getMessage()]),
169
                    ];
170
171
                    return ['exit' => 'callback', 'out' => $out];
172
                }
173
            } elseif (! empty($_GET['error'])) {
174
                $out = [
175
                        'node' => $options['id'],
176
                        'json' => json_encode(['error' => elFinder::ERROR_ACCESS_DENIED]),
177
                ];
178
179
                return ['exit' => 'callback', 'out' => $out];
180
            }
181
182
            if ($options['user'] === 'init') {
183
                $this->token = $this->session->get('BoxTokens');
184
185 View Code Duplication
                if ($this->token) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
186
                    try {
187
                        $this->_bd_refreshToken();
188
                    } catch (Exception $e) {
189
                        $this->setError($e->getMessage());
190
                        $this->token = null;
191
                        $this->session->remove('BoxTokens');
192
                    }
193
                }
194
195
                if (empty($this->token)) {
196
                    $result = false;
197
                } else {
198
                    $path = $options['path'];
199
                    if ($path === '/' || $path === 'root') {
200
                        $path = '0';
201
                    }
202
                    $result = $this->_bd_query($path, $fetch_self = false, $recursive = false);
203
                }
204
205
                if ($result === false) {
206
                    $cdata = '';
207
                    $innerKeys = ['cmd', 'host', 'options', 'pass', 'protocol', 'user'];
208
                    $this->ARGS = $_SERVER['REQUEST_METHOD'] === 'POST' ? $_POST : $_GET;
209 View Code Duplication
                    foreach ($this->ARGS as $k => $v) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
210
                        if (! in_array($k, $innerKeys)) {
211
                            $cdata .= '&'.$k.'='.rawurlencode($v);
212
                        }
213
                    }
214
                    if (empty($options['url'])) {
215
                        $options['url'] = elFinder::getConnectorUrl();
216
                    }
217
                    $callback = $options['url']
218
                        .'?cmd=netmount&protocol=box&host=box.com&user=init&pass=return&node='.$options['id'].$cdata;
219
220
                    try {
221
                        $this->session->set('BoxTokens', (object) ['token' => null]);
222
223
                        $url = self::AUTH_URL.'?'.http_build_query(['response_type' => 'code', 'client_id' => $options['client_id'], 'redirect_uri' => elFinder::getConnectorUrl().'?cmd=netmount&protocol=box&host=1']);
224
225
                        $url .= '&oauth_callback='.rawurlencode($callback);
226
                    } catch (Exception $e) {
227
                        return ['exit' => true, 'body' => '{msg:errAccess}'];
228
                    }
229
230
                    $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" onclick="window.open(\''.$url.'\')">';
231
                    $html .= '<script>
232
							$("#'.$options['id'].'").elfinder("instance").trigger("netmount", {protocol: "box", mode: "makebtn"});
233
						</script>';
234
235
                    return ['exit' => true, 'body' => $html];
236 View Code Duplication
                } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
237
                    $folders = [];
238
239
                    if ($result) {
240
                        foreach ($result as $res) {
241
                            if ($res->type == 'folder') {
242
                                $folders[$res->id.' '] = $res->name;
243
                            }
244
                        }
245
                        natcasesort($folders);
246
                    }
247
248
                    if ($options['pass'] === 'folders') {
249
                        return ['exit' => true, 'folders' => $folders];
250
                    }
251
252
                    $folders = ['root' => 'My Box'] + $folders;
253
                    $folders = json_encode($folders);
254
255
                    $expires = empty($this->token->data->refresh_token) ? (int) $this->token->expires : 0;
256
                    $json = '{"protocol": "box", "mode": "done", "folders": '.$folders.', "expires": '.$expires.'}';
257
                    $html = 'Box.com';
258
                    $html .= '<script>
259
							$("#'.$options['id'].'").elfinder("instance").trigger("netmount", '.$json.');
260
							</script>';
261
262
                    return ['exit' => true, 'body' => $html];
263
                }
264
            }
265
        } catch (Exception $e) {
266
            return ['exit' => true, 'body' => '{msg:errNetMountNoDriver}'];
267
        }
268
269 View Code Duplication
        if ($_aToken = $this->session->get('BoxTokens')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
270
            $options['accessToken'] = json_encode($_aToken);
271
        } else {
272
            $this->setError(elFinder::ERROR_NETMOUNT, $options['host'], implode(' ', $this->error()));
273
274
            return ['exit' => true, 'error' => $this->error()];
275
        }
276
277
        $this->session->remove('nodeId');
278
        unset($options['user'], $options['pass'], $options['id']);
279
280
        return $options;
281
    }
282
283
    /**
284
     * process of on netunmount
285
     * Drop `box` & rm thumbs.
286
     *
287
     * @param array $options
0 ignored issues
show
Bug introduced by
There is no parameter named $options. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
288
     *
289
     * @return bool
290
     */
291 View Code Duplication
    public function netunmount($netVolumes, $key)
0 ignored issues
show
Unused Code introduced by
The parameter $netVolumes is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $key is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
292
    {
293
        if ($tmbs = glob(rtrim($this->options['tmbPath'], '\\/').DIRECTORY_SEPARATOR.$this->tmbPrefix.'*.png')) {
294
            foreach ($tmbs as $file) {
295
                unlink($file);
296
            }
297
        }
298
299
        return true;
300
    }
301
302
    /*********************************************************************/
303
    /*                               FS API                              */
304
    /*********************************************************************/
305
306
    /**
307
     * Close opened connection.
308
     *
309
     * @author Dmitry (dio) Levashov
310
     **/
311
    public function umount()
312
    {
313
    }
314
315
    /**
316
     * Return content URL.
317
     *
318
     * @param string $hash    file hash
319
     * @param array  $options options
320
     *
321
     * @return string
322
     *
323
     * @author Naoki Sawada
324
     **/
325
    public function getContentUrl($hash, $options = [])
326
    {
327 View Code Duplication
        if (! empty($options['temporary'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
328
            // try make temporary file
329
            $url = parent::getContentUrl($hash, $options);
330
            if ($url) {
331
                return $url;
332
            }
333
        }
334
        if (($file = $this->file($hash)) == false || ! $file['url'] || $file['url'] == 1) {
335
            $path = $this->decode($hash);
336
337
            list(, $itemId) = $this->_bd_splitPath($path);
338
            $params['shared_link']['access'] = 'open'; //open|company|collaborators
0 ignored issues
show
Coding Style Comprehensibility introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
339
340
            $url = self::API_URL.'/files/'.$itemId;
341
342
            $curl = $this->_bd_prepareCurl([
343
                CURLOPT_URL => $url,
344
                CURLOPT_CUSTOMREQUEST => 'PUT',
345
                CURLOPT_POSTFIELDS => json_encode($params),
346
            ]);
347
            $res = $this->_bd_curlExec($curl, true, [
348
                    // The data is sent as JSON as per Box documentation.
349
                    'Content-Type: application/json',
350
                ]);
351
352
            if ($url = $this->getSharedWebContentLink($res)) {
353
                return $url;
354
            }
355
        }
356
357
        return '';
358
    }
359
360
    /*********************************************************************/
361
    /*                        ORIGINAL FUNCTIONS                         */
362
    /*********************************************************************/
363
364
    /**
365
     * Get Parent ID, Item ID, Parent Path as an array from path.
366
     *
367
     * @param string $path
368
     *
369
     * @return array
370
     */
371 View Code Duplication
    protected function _bd_splitPath($path)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
372
    {
373
        $path = trim($path, '/');
374
        $pid = '';
375
        if ($path === '') {
376
            $id = '0';
377
            $parent = '';
378
        } else {
379
            $paths = explode('/', trim($path, '/'));
380
            $id = array_pop($paths);
381
            if ($paths) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $paths of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
382
                $parent = '/'.implode('/', $paths);
383
                $pid = array_pop($paths);
384
            } else {
385
                $pid = '0';
386
                $parent = '/';
387
            }
388
        }
389
390
        return [$pid, $id, $parent];
391
    }
392
393
    /**
394
     * Obtains a new access token from OAuth. This token is valid for one hour.
395
     *
396
     * @param string $clientSecret The Box client secret
0 ignored issues
show
Bug introduced by
There is no parameter named $clientSecret. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
397
     * @param string $code         The code returned by Box after
398
     *                             successful log in
399
     * @param string $redirectUri  Must be the same as the redirect URI passed
0 ignored issues
show
Bug introduced by
There is no parameter named $redirectUri. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
400
     *                             to LoginUrl
401
     *
402
     * @throws \Exception Thrown if this Client instance's clientId is not set
403
     * @throws \Exception Thrown if the redirect URI of this Client instance's
404
     *                    state is not set
405
     */
406
    protected function _bd_obtainAccessToken($client_id, $client_secret, $code)
407
    {
408
        if (null === $client_id) {
409
            return $this->setError('The client ID must be set to call obtainAccessToken()');
410
        }
411
412
        if (null === $client_secret) {
413
            return $this->setError('The client Secret must be set to call obtainAccessToken()');
414
        }
415
416
        if (null === $code) {
417
            return $this->setError('Authorization code must be set to call obtainAccessToken()');
418
        }
419
420
        $url = self::TOKEN_URL;
421
422
        $curl = curl_init();
423
424
        $fields = http_build_query(
425
            [
426
                'client_id' => $client_id,
427
                'client_secret' => $client_secret,
428
                'code' => $code,
429
                'grant_type' => 'authorization_code',
430
            ]
431
        );
432
433
        curl_setopt_array($curl, [
434
            // General options.
435
            CURLOPT_RETURNTRANSFER => true,
436
            CURLOPT_POST => true,
437
            CURLOPT_POSTFIELDS => $fields,
438
            CURLOPT_URL => $url,
439
        ]);
440
441
        $decoded = $this->_bd_curlExec($curl, true, ['Content-Length: '.strlen($fields)]);
442
443
        return (object) [
444
                'expires' => time() + $decoded->expires_in - 30,
445
                'data' => $decoded,
446
        ];
447
    }
448
449
    /**
450
     * Get token and auto refresh.
451
     *
452
     * @return true|string error message
453
     */
454
    protected function _bd_refreshToken()
455
    {
456
        if ($this->token->expires < time()) {
457
            if (! $token = $this->session->get('BoxTokens')) {
458
                $token = $this->token;
459
            }
460
            if (empty($token->data->refresh_token)) {
461
                $this->session->remove('BoxTokens');
462
                throw new \Exception(elFinder::ERROR_REAUTH_REQUIRE);
463
            }
464
465
            if (! $this->options['client_id']) {
466
                $this->options['client_id'] = ELFINDER_BOX_CLIENTID;
467
            }
468
469
            if (! $this->options['client_secret']) {
470
                $this->options['client_secret'] = ELFINDER_BOX_CLIENTSECRET;
471
            }
472
473
            $url = self::TOKEN_URL;
474
475
            $curl = curl_init();
476
477
            curl_setopt_array($curl, [
478
                    // General options.
479
                    CURLOPT_RETURNTRANSFER => true,
480
                    CURLOPT_POST => true, // i am sending post data
481
                    CURLOPT_POSTFIELDS => 'client_id='.urlencode($this->options['client_id'])
482
                        .'&client_secret='.urlencode($this->options['client_secret'])
483
                        .'&grant_type=refresh_token'
484
                        .'&refresh_token='.urlencode($token->data->refresh_token),
485
486
                    CURLOPT_URL => $url,
487
                ]);
488
489
            $decoded = $this->_bd_curlExec($curl);
490
491
            if (empty($decoded->access_token)) {
492
                throw new \Exception(elFinder::ERROR_REAUTH_REQUIRE);
493
            }
494
495
            $token = (object) [
496
                    'expires' => time() + $decoded->expires_in - 30,
497
                    'data' => $decoded,
498
                ];
499
500
            $this->session->set('BoxTokens', $token);
501
            $this->options['accessToken'] = json_encode($token);
502
            $this->token = $token;
503
504 View Code Duplication
            if (! empty($this->options['netkey'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
505
                elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'accessToken', $this->options['accessToken']);
506
            }
507
        }
508
509
        return true;
510
    }
511
512
    /**
513
     * Creates a base cURL object which is compatible with the Box.com API.
514
     *
515
     * @param array $options cURL options
516
     *
517
     * @return resource A compatible cURL object
518
     */
519
    protected function _bd_prepareCurl($options = [])
520
    {
521
        $curl = curl_init();
522
523
        $defaultOptions = [
524
            // General options.
525
            CURLOPT_RETURNTRANSFER => true,
526
        ];
527
528
        curl_setopt_array($curl, $options + $defaultOptions);
529
530
        return $curl;
531
    }
532
533
    /**
534
     * Creates a base cURL object which is compatible with the Box.com API.
535
     *
536
     * @param string $path The path of the API call (eg. /folders/0)
0 ignored issues
show
Bug introduced by
There is no parameter named $path. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
537
     *
538
     * @return resource A compatible cURL object
539
     */
540
    protected function _bd_fetch($url, $contents = false)
541
    {
542
        $curl = curl_init($url);
543
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
544
545
        if ($contents) {
546
            return $this->_bd_curlExec($curl, false);
547
        } else {
548
            $result = $this->_bd_curlExec($curl);
549
550
            if (isset($result->entries)) {
551
                $res = $result->entries;
552
                $cnt = count($res);
553
                $total = $result->total_count;
554
                $offset = $result->offset;
555
                $single = ($result->limit == 1) ? true : false;
556
                if (! $single && $total > ($offset + $cnt)) {
557
                    $offset = $offset + $cnt;
558
                    if (strpos($url, 'offset=') === false) {
559
                        $url .= '&offset='.$offset;
560
                    } else {
561
                        $url = preg_replace('/^(.+?offset=)\d+(.*)$/', '${1}'.$offset.'$2', $url);
562
                    }
563
                    $more = $this->_bd_fetch($url);
564
                    if (is_array($more)) {
565
                        $res = array_merge($res, $more);
566
                    }
567
                }
568
569
                return $res;
570 View Code Duplication
            } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
571
                if (isset($result->type) && $result->type === 'error') {
572
                    return false;
573
                } else {
574
                    return $result;
575
                }
576
            }
577
        }
578
    }
579
580
    /**
581
     * Call curl_exec().
582
     *
583
     * @param resource    $curl
584
     * @param bool|string $decodeOrParent
585
     * @param array       $headers
586
     *
587
     * @throws \Exception
588
     *
589
     * @return mixed
590
     */
591
    protected function _bd_curlExec($curl, $decodeOrParent = true, $headers = [])
592
    {
593
        $headers = array_merge([
594
            'Authorization: Bearer '.$this->token->data->access_token,
595
        ], $headers);
596
597
        $result = elFinder::curlExec($curl, [], $headers);
598
599
        if (! $decodeOrParent) {
600
            return $result;
601
        }
602
603
        $decoded = json_decode($result);
604
605
        if (! empty($decoded->error_code)) {
606
            $errmsg = $decoded->error_code;
607
            if (! empty($decoded->message)) {
608
                $errmsg .= ': '.$decoded->message;
609
            }
610
            throw new \Exception($errmsg);
611
        }
612
613
        // make catch
614
        if ($decodeOrParent && $decodeOrParent !== true) {
615
            $raws = null;
616
            list(, $parentId) = $this->_bd_splitPath($decodeOrParent);
0 ignored issues
show
Bug introduced by
It seems like $decodeOrParent can also be of type boolean; however, elFinderVolumeBox::_bd_splitPath() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Unused Code introduced by
The assignment to $parentId is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
617
            if (isset($decoded->entries)) {
618
                $raws = $decoded->entries;
619
            } elseif (isset($decoded->id)) {
620
                $raws = [$decoded];
621
            }
622
            if ($raws) {
623
                foreach ($raws as $raw) {
624
                    if (isset($raw->id)) {
625
                        $stat = $this->_bd_parseRaw($raw);
626
                        $itemPath = $this->_joinPath($decodeOrParent, $raw->id);
0 ignored issues
show
Bug introduced by
It seems like $decodeOrParent defined by parameter $decodeOrParent on line 591 can also be of type boolean; however, elFinderVolumeBox::_joinPath() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
627
                        $this->updateCache($itemPath, $stat);
628
                    }
629
                }
630
            }
631
        }
632
633
        return $decoded;
634
    }
635
636
    /**
637
     * Drive query and fetchAll.
638
     *
639
     * @param string $sql
0 ignored issues
show
Bug introduced by
There is no parameter named $sql. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
640
     *
641
     * @return bool|array
642
     */
643
    protected function _bd_query($itemId, $fetch_self = false, $recursive = false)
644
    {
645
        $result = [];
646
647
        if (null === $itemId) {
648
            $itemId = '0';
649
        }
650
651
        if ($fetch_self) {
652
            $path = '/folders/'.$itemId.'?fields='.self::FETCHFIELDS;
653
        } else {
654
            $path = '/folders/'.$itemId.'/items?limit=1000&fields='.self::FETCHFIELDS;
655
        }
656
657
        $url = self::API_URL.$path;
658
659
        if ($recursive) {
660
            foreach ($this->_bd_fetch($url) as $file) {
0 ignored issues
show
Bug introduced by
The expression $this->_bd_fetch($url) of type resource is not traversable.
Loading history...
661
                if ($file->type == 'folder') {
662
                    $result[] = $file;
663
                    $result = array_merge($result, $this->_bd_query($file->id, $fetch_self = false, $recursive = true));
664
                } elseif ($file->type == 'file') {
665
                    $result[] = $file;
666
                }
667
            }
668
        } else {
669
            $result = $this->_bd_fetch($url);
670
            if ($fetch_self && ! $result) {
671
                $path = '/files/'.$itemId.'?fields='.self::FETCHFIELDS;
672
                $url = self::API_URL.$path;
673
                $result = $this->_bd_fetch($url);
674
            }
675
        }
676
677
        return $result;
678
    }
679
680
    /**
681
     * Get dat(box metadata) from Box.com.
682
     *
683
     * @param string $path
684
     *
685
     * @return array box metadata
686
     */
687
    protected function _bd_getRawItem($path)
688
    {
689
        if ($path == '/') {
690
            return $this->_bd_query('0', $fetch_self = true);
691
        }
692
693
        list(, $itemId) = $this->_bd_splitPath($path);
694
695
        try {
696
            return $this->_bd_query($itemId, $fetch_self = true);
697
        } catch (Exception $e) {
698
            return [];
699
        }
700
    }
701
702
    /**
703
     * Parse line from box metadata output and return file stat (array).
704
     *
705
     * @param string $raw line from ftp_rawlist() output
706
     *
707
     * @return array
708
     *
709
     * @author Dmitry Levashov
710
     **/
711
    protected function _bd_parseRaw($raw)
712
    {
713
        $stat = [];
714
715
        $stat['rev'] = isset($raw->id) ? $raw->id : 'root';
716
        $stat['name'] = $raw->name;
717
        if (! empty($raw->modified_at)) {
718
            $stat['ts'] = strtotime($raw->modified_at);
719
        }
720
721
        if ($raw->type === 'folder') {
722
            $stat['mime'] = 'directory';
723
            $stat['size'] = 0;
724
            $stat['dirs'] = -1;
725
        } else {
726
            $stat['size'] = (int) $raw->size;
727
            if (! empty($raw->shared_link->url) && $raw->shared_link->access == 'open') {
728
                if ($url = $this->getSharedWebContentLink($raw)) {
0 ignored issues
show
Documentation introduced by
$raw is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
729
                    $stat['url'] = $url;
730
                }
731
            } elseif (! $this->disabledGetUrl) {
732
                $stat['url'] = '1';
733
            }
734
        }
735
736
        return $stat;
737
    }
738
739
    /**
740
     * Get thumbnail from Box.com.
741
     *
742
     * @param string $path
743
     * @param string $size
0 ignored issues
show
Bug introduced by
There is no parameter named $size. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
744
     *
745
     * @return string | boolean
746
     */
747 View Code Duplication
    protected function _bd_getThumbnail($path)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
748
    {
749
        list(, $itemId) = $this->_bd_splitPath($path);
750
751
        try {
752
            $url = self::API_URL.'/files/'.$itemId.'/content';
753
754
            $contents = $this->_bd_fetch($url, true);
755
756
            return $contents;
757
        } catch (Exception $e) {
758
            return false;
759
        }
760
    }
761
762
    /**
763
     * Remove item.
764
     *
765
     * @param string $path file path
766
     *
767
     * @return bool
768
     **/
769
    protected function _bd_unlink($path, $type = null)
770
    {
771
        try {
772
            list(, $itemId) = $this->_bd_splitPath($path);
773
774
            if ($type == 'folders') {
775
                $url = self::API_URL.'/'.$type.'/'.$itemId.'?recursive=true';
776
            } else {
777
                $url = self::API_URL.'/'.$type.'/'.$itemId;
778
            }
779
780
            $curl = $this->_bd_prepareCurl([
781
                    CURLOPT_URL => $url,
782
                    CURLOPT_CUSTOMREQUEST => 'DELETE',
783
            ]);
784
785
            //unlink or delete File or Folder in the Parent
786
            $this->_bd_curlExec($curl);
787
        } catch (Exception $e) {
788
            return $this->setError('Box error: '.$e->getMessage());
789
        }
790
791
        return true;
792
    }
793
794
    /*********************************************************************/
795
    /*                        INIT AND CONFIGURE                         */
796
    /*********************************************************************/
797
798
    /**
799
     * Prepare FTP connection
800
     * Connect to remote server and check if credentials are correct, if so, store the connection id in $ftp_conn.
801
     *
802
     * @return bool
803
     *
804
     * @author Dmitry (dio) Levashov
805
     * @author Cem (DiscoFever)
806
     **/
807
    protected function init()
808
    {
809
        if (! $this->options['accessToken']) {
810
            return $this->setError('Required option `accessToken` is undefined.');
811
        }
812
813
        try {
814
            $this->token = json_decode($this->options['accessToken']);
815
            $this->_bd_refreshToken();
816
        } catch (Exception $e) {
817
            $this->token = null;
818
            $this->session->remove('BoxTokens');
819
820
            return $this->setError($e->getMessage());
821
        }
822
823 View Code Duplication
        if (empty($options['netkey'])) {
0 ignored issues
show
Bug introduced by
The variable $options seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
824
            // make net mount key
825
            $_tokenKey = isset($this->token->data->refresh_token) ? $this->token->data->refresh_token : $this->token->data->access_token;
826
            $this->netMountKey = md5(implode('-', ['box', $this->options['path'], $_tokenKey]));
827
        } else {
828
            $this->netMountKey = $options['netkey'];
829
        }
830
831
        // normalize root path
832
        if ($this->options['path'] == 'root') {
833
            $this->options['path'] = '/';
834
        }
835
836
        $this->root = $this->options['path'] = $this->_normpath($this->options['path']);
837
838
        $this->options['root'] == '' ? $this->options['root'] = 'Box.com' : $this->options['root'];
839
840
        if (empty($this->options['alias'])) {
841
            list(, $itemId) = $this->_bd_splitPath($this->options['path']);
842
            $this->options['alias'] = ($this->options['path'] === '/') ? $this->options['root'] :
843
                                      $this->_bd_query($itemId, $fetch_self = true)->name.'@Box.com';
844
        }
845
846
        $this->rootName = $this->options['alias'];
847
848
        $this->tmbPrefix = 'box'.base_convert($this->netMountKey, 10, 32);
849
850 View Code Duplication
        if (! empty($this->options['tmpPath'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
851
            if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($this->options['tmpPath'])) {
852
                $this->tmp = $this->options['tmpPath'];
853
            }
854
        }
855
856
        if (! $this->tmp && ($tmp = elFinder::getStaticVar('commonTempPath'))) {
857
            $this->tmp = $tmp;
858
        }
859
860
        // This driver dose not support `syncChkAsTs`
861
        $this->options['syncChkAsTs'] = false;
862
863
        // 'lsPlSleep' minmum 10 sec
864
        $this->options['lsPlSleep'] = max(10, $this->options['lsPlSleep']);
865
866
        return true;
867
    }
868
869
    /**
870
     * Configure after successfull mount.
871
     *
872
     * @author Dmitry (dio) Levashov
873
     **/
874
    protected function configure()
875
    {
876
        parent::configure();
877
878
        // fallback of $this->tmp
879
        if (! $this->tmp && $this->tmbPathWritable) {
880
            $this->tmp = $this->tmbPath;
881
        }
882
883
        $this->disabled[] = 'archive';
884
        $this->disabled[] = 'extract';
885
    }
886
887
    /**
888
     * Return fileinfo based on filename
889
     * For item ID based path file system
890
     * Please override if needed on each drivers.
891
     *
892
     * @param string $path file cache
893
     *
894
     * @return array
895
     */
896
    protected function isNameExists($path)
897
    {
898
        list($pid, $name, $parent) = $this->_bd_splitPath($path);
0 ignored issues
show
Unused Code introduced by
The assignment to $pid is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
899
900
        // We can not use it because the search of Box.com there is a time lag.
901
        // ref. https://docs.box.com/reference#searching-for-content
902
        // > Note: If an item is added to Box then it becomes accessible through the search endpoint after ten minutes.
903
904
        /***
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
905
        $url = self::API_URL.'/search?limit=1&offset=0&content_types=name&ancestor_folder_ids='.rawurlencode($pid)
906
        .'&query='.rawurlencode('"'.$name.'"')
907
        .'fields='.self::FETCHFIELDS;
908
909
        $raw = $this->_bd_fetch($url);
910
911
        if (is_array($raw) && count($raw)) {
912
            return $this->_bd_parseRaw($raw);
913
        }
914
        ***/
915
916
        $phash = $this->encode($parent);
917
918
        // do not recursive search
919
        $searchExDirReg = $this->options['searchExDirReg'];
920
        $this->options['searchExDirReg'] = '/.*/';
921
        $search = $this->search($name, [], $phash);
0 ignored issues
show
Bug introduced by
It seems like $phash defined by $this->encode($parent) on line 916 can also be of type string; however, elFinderVolumeDriver::search() does only seem to accept null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
922
        $this->options['searchExDirReg'] = $searchExDirReg;
923
924
        if ($search) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $search of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
925
            return $search[0];
926
        }
927
928
        return false;
929
    }
930
931
    /**
932
     * Cache dir contents.
933
     *
934
     * @param string $path dir path
935
     *
936
     * @author Dmitry Levashov
937
     **/
938
    protected function cacheDir($path)
939
    {
940
        $this->dirsCache[$path] = [];
941
        $hasDir = false;
942
943
        if ($path == '/') {
944
            $items = $this->_bd_query('0', $fetch_self = true);   // get root directory with folder & files
945
            $itemId = $items->id;
946
        } else {
947
            list(, $itemId) = $this->_bd_splitPath($path);
948
        }
949
950
        $res = $this->_bd_query($itemId);
951
952
        if ($res) {
953
            foreach ($res as $raw) {
954
                if ($stat = $this->_bd_parseRaw($raw)) {
955
                    $itemPath = $this->_joinPath($path, $raw->id);
956
                    $stat = $this->updateCache($itemPath, $stat);
957
                    if (empty($stat['hidden'])) {
958
                        if (! $hasDir && $stat['mime'] === 'directory') {
959
                            $hasDir = true;
960
                        }
961
                        $this->dirsCache[$path][] = $itemPath;
962
                    }
963
                }
964
            }
965
        }
966
967
        if (isset($this->sessionCache['subdirs'])) {
968
            $this->sessionCache['subdirs'][$path] = $hasDir;
969
        }
970
971
        return $this->dirsCache[$path];
972
    }
973
974
    /**
975
     * Copy file/recursive copy dir only in current volume.
976
     * Return new file path or false.
977
     *
978
     * @param string $src  source path
979
     * @param string $dst  destination dir path
980
     * @param string $name new file name (optionaly)
981
     *
982
     * @return string|false
983
     *
984
     * @author Dmitry (dio) Levashov
985
     * @author Naoki Sawada
986
     **/
987
    protected function copy($src, $dst, $name)
988
    {
989 View Code Duplication
        if ($res = $this->_copy($src, $dst, $name)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
990
            return $res;
991
        } else {
992
            return $this->setError(elFinder::ERROR_COPY, $this->_path($src));
993
        }
994
    }
995
996
    /**
997
     * Remove file/ recursive remove dir.
998
     *
999
     * @param string $path  file path
1000
     * @param bool   $force try to remove even if file locked
1001
     *
1002
     * @return bool
1003
     *
1004
     * @author Dmitry (dio) Levashov
1005
     * @author Naoki Sawada
1006
     **/
1007 View Code Duplication
    protected function remove($path, $force = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1008
    {
1009
        $stat = $this->stat($path);
1010
        $stat['realpath'] = $path;
1011
        $this->rmTmb($stat);
0 ignored issues
show
Documentation introduced by
$stat is of type array<string,string,{"realpath":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1012
        $this->clearcache();
1013
1014
        if (empty($stat)) {
1015
            return $this->setError(elFinder::ERROR_RM, $this->_path($path), elFinder::ERROR_FILE_NOT_FOUND);
1016
        }
1017
1018
        if (! $force && ! empty($stat['locked'])) {
1019
            return $this->setError(elFinder::ERROR_LOCKED, $this->_path($path));
1020
        }
1021
1022
        if ($stat['mime'] == 'directory') {
1023
            if (! $this->_rmdir($path)) {
1024
                return $this->setError(elFinder::ERROR_RM, $this->_path($path));
1025
            }
1026
        } else {
1027
            if (! $this->_unlink($path)) {
1028
                return $this->setError(elFinder::ERROR_RM, $this->_path($path));
1029
            }
1030
        }
1031
1032
        $this->removed[] = $stat;
1033
1034
        return true;
1035
    }
1036
1037
    /**
1038
     * Create thumnbnail and return it's URL on success.
1039
     *
1040
     * @param string $path file path
1041
     * @param string $mime file mime type
0 ignored issues
show
Bug introduced by
There is no parameter named $mime. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1042
     *
1043
     * @return string|false
1044
     *
1045
     * @author Dmitry (dio) Levashov
1046
     * @author Naoki Sawada
1047
     **/
1048 View Code Duplication
    protected function createTmb($path, $stat)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1049
    {
1050
        if (! $stat || ! $this->canCreateTmb($path, $stat)) {
1051
            return false;
1052
        }
1053
1054
        $name = $this->tmbname($stat);
1055
        $tmb = $this->tmbPath.DIRECTORY_SEPARATOR.$name;
1056
1057
        // copy image into tmbPath so some drivers does not store files on local fs
1058
        if (! $data = $this->_bd_getThumbnail($path)) {
1059
            return false;
1060
        }
1061
        if (! file_put_contents($tmb, $data)) {
1062
            return false;
1063
        }
1064
1065
        $result = false;
0 ignored issues
show
Unused Code introduced by
$result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1066
1067
        $tmbSize = $this->tmbSize;
1068
1069
        if (($s = getimagesize($tmb)) == false) {
1070
            return false;
1071
        }
1072
1073
        /* If image smaller or equal thumbnail size - just fitting to thumbnail square */
1074
        if ($s[0] <= $tmbSize && $s[1] <= $tmbSize) {
1075
            $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png');
1076
        } else {
1077
            if ($this->options['tmbCrop']) {
1078
1079
                /* Resize and crop if image bigger than thumbnail */
1080
                if (! (($s[0] > $tmbSize && $s[1] <= $tmbSize) || ($s[0] <= $tmbSize && $s[1] > $tmbSize)) || ($s[0] > $tmbSize && $s[1] > $tmbSize)) {
1081
                    $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, false, 'png');
0 ignored issues
show
Unused Code introduced by
$result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1082
                }
1083
1084
                if (($s = getimagesize($tmb)) != false) {
1085
                    $x = $s[0] > $tmbSize ? intval(($s[0] - $tmbSize) / 2) : 0;
1086
                    $y = $s[1] > $tmbSize ? intval(($s[1] - $tmbSize) / 2) : 0;
1087
                    $result = $this->imgCrop($tmb, $tmbSize, $tmbSize, $x, $y, 'png');
0 ignored issues
show
Documentation introduced by
$x is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
$y is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Unused Code introduced by
$result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1088
                }
1089
            } else {
1090
                $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, true, 'png');
0 ignored issues
show
Unused Code introduced by
$result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1091
            }
1092
1093
            $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png');
1094
        }
1095
1096
        if (! $result) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $result of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1097
            unlink($tmb);
1098
1099
            return false;
1100
        }
1101
1102
        return $name;
1103
    }
1104
1105
    /**
1106
     * Return thumbnail file name for required file.
1107
     *
1108
     * @param array $stat file stat
1109
     *
1110
     * @return string
1111
     *
1112
     * @author Dmitry (dio) Levashov
1113
     **/
1114
    protected function tmbname($stat)
1115
    {
1116
        return $this->tmbPrefix.$stat['rev'].$stat['ts'].'.png';
1117
    }
1118
1119
    /**
1120
     * Return content URL.
1121
     *
1122
     * @param array $raw data
1123
     *
1124
     * @return array
1125
     *
1126
     * @author Naoki Sawada
1127
     **/
1128
    protected function getSharedWebContentLink($raw)
1129
    {
1130
        $fExtension = pathinfo($raw->name, PATHINFO_EXTENSION);
1131
        list($fType) = explode('/', self::mimetypeInternalDetect($raw->name));
1132
1133
        if ($raw->shared_link->url && ($fType == 'image' || $fType == 'video' || $fType == 'audio')) {
1134
            if ($fExtension == 'jpg' && $fType == 'image') {
1135
                $url = 'https://app.box.com/representation/file_version_'.$raw->file_version->id.'/image_2048_'.$fExtension.'/1.'.$fExtension.'?shared_name='.basename($raw->shared_link->url);
1136
1137
                return $url;
1138 View Code Duplication
            } elseif ($fExtension !== 'jpg' && $fType == 'image') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1139
                $url = 'https://app.box.com/representation/file_version_'.$raw->file_version->id.'/image_2048/1.'.$fExtension.'?shared_name='.basename($raw->shared_link->url);
1140
1141
                return $url;
1142
            } elseif ($fType == 'video') {
1143
                $url = 'https://app.box.com/representation/file_version_'.$raw->file_version->id.'/video_480.'.$fExtension.'?shared_name='.basename($raw->shared_link->url);
1144
1145
                return $url;
1146 View Code Duplication
            } elseif ($fType == 'audio') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1147
                $url = 'https://app.box.com/index.php?rm=preview_stream&amp&file_version_'.$raw->file_version->id.'/audio/mpeg:'.$raw->name.'&shared_name='.basename($raw->shared_link->url);
1148
1149
                return $url;
1150
            }
1151
        } elseif ($raw->shared_link->download_url) {
1152
            return $raw->shared_link->download_url;
1153
        }
1154
1155
        return false;
1156
    }
1157
1158
    /*********************** paths/urls *************************/
1159
1160
    /**
1161
     * Return parent directory path.
1162
     *
1163
     * @param string $path file path
1164
     *
1165
     * @return string
1166
     *
1167
     * @author Dmitry (dio) Levashov
1168
     **/
1169
    protected function _dirname($path)
1170
    {
1171
        list(, , $dirname) = $this->_bd_splitPath($path);
1172
1173
        return $dirname;
1174
    }
1175
1176
    /**
1177
     * Return file name.
1178
     *
1179
     * @param string $path file path
1180
     *
1181
     * @return string
1182
     *
1183
     * @author Dmitry (dio) Levashov
1184
     **/
1185
    protected function _basename($path)
1186
    {
1187
        list(, $basename) = $this->_bd_splitPath($path);
1188
1189
        return $basename;
1190
    }
1191
1192
    /**
1193
     * Join dir name and file name and retur full path.
1194
     *
1195
     * @param string $dir
1196
     * @param string $name
1197
     *
1198
     * @return string
1199
     *
1200
     * @author Dmitry (dio) Levashov
1201
     **/
1202
    protected function _joinPath($dir, $name)
1203
    {
1204
        if (strval($dir) === '0') {
1205
            $dir = '';
1206
        }
1207
1208
        return $this->_normpath($dir.'/'.$name);
1209
    }
1210
1211
    /**
1212
     * Return normalized path, this works the same as os.path.normpath() in Python.
1213
     *
1214
     * @param string $path path
1215
     *
1216
     * @return string
1217
     *
1218
     * @author Troex Nevelin
1219
     **/
1220 View Code Duplication
    protected function _normpath($path)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1221
    {
1222
        if (DIRECTORY_SEPARATOR !== '/') {
1223
            $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
1224
        }
1225
        $path = '/'.ltrim($path, '/');
1226
1227
        return $path;
1228
    }
1229
1230
    /**
1231
     * Return file path related to root dir.
1232
     *
1233
     * @param string $path file path
1234
     *
1235
     * @return string
1236
     *
1237
     * @author Dmitry (dio) Levashov
1238
     **/
1239
    protected function _relpath($path)
1240
    {
1241
        return $path;
1242
    }
1243
1244
    /**
1245
     * Convert path related to root dir into real path.
1246
     *
1247
     * @param string $path file path
1248
     *
1249
     * @return string
1250
     *
1251
     * @author Dmitry (dio) Levashov
1252
     **/
1253
    protected function _abspath($path)
1254
    {
1255
        return $path;
1256
    }
1257
1258
    /**
1259
     * Return fake path started from root dir.
1260
     *
1261
     * @param string $path file path
1262
     *
1263
     * @return string
1264
     *
1265
     * @author Dmitry (dio) Levashov
1266
     **/
1267
    protected function _path($path)
1268
    {
1269
        return $this->rootName.$this->_normpath(substr($path, strlen($this->root)));
1270
    }
1271
1272
    /**
1273
     * Return true if $path is children of $parent.
1274
     *
1275
     * @param string $path   path to check
1276
     * @param string $parent parent path
1277
     *
1278
     * @return bool
1279
     *
1280
     * @author Dmitry (dio) Levashov
1281
     **/
1282
    protected function _inpath($path, $parent)
1283
    {
1284
        return $path == $parent || strpos($path, $parent.'/') === 0;
1285
    }
1286
1287
    /***************** file stat ********************/
1288
1289
    /**
1290
     * Return stat for given path.
1291
     * Stat contains following fields:
1292
     * - (int)    size    file size in b. required
1293
     * - (int)    ts      file modification time in unix time. required
1294
     * - (string) mime    mimetype. required for folders, others - optionally
1295
     * - (bool)   read    read permissions. required
1296
     * - (bool)   write   write permissions. required
1297
     * - (bool)   locked  is object locked. optionally
1298
     * - (bool)   hidden  is object hidden. optionally
1299
     * - (string) alias   for symlinks - link target path relative to root path. optionally
1300
     * - (string) target  for symlinks - link target path. optionally.
1301
     *
1302
     * If file does not exists - returns empty array or false.
1303
     *
1304
     * @param string $path file path
1305
     *
1306
     * @return array|false
1307
     *
1308
     * @author Dmitry (dio) Levashov
1309
     **/
1310
    protected function _stat($path)
1311
    {
1312
        if ($raw = $this->_bd_getRawItem($path)) {
1313
            return $this->_bd_parseRaw($raw);
0 ignored issues
show
Documentation introduced by
$raw is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1314
        }
1315
1316
        return false;
1317
    }
1318
1319
    /**
1320
     * Return true if path is dir and has at least one childs directory.
1321
     *
1322
     * @param string $path dir path
1323
     *
1324
     * @return bool
1325
     *
1326
     * @author Dmitry (dio) Levashov
1327
     **/
1328
    protected function _subdirs($path)
1329
    {
1330
        list(, $itemId) = $this->_bd_splitPath($path);
1331
1332
        $path = '/folders/'.$itemId.'/items?limit=1&offset=0&fields='.self::FETCHFIELDS;
1333
1334
        $url = self::API_URL.$path;
1335
1336
        if ($res = $this->_bd_fetch($url)) {
1337
            if ($res[0]->type == 'folder') {
1338
                return true;
1339
            }
1340
        }
1341
1342
        return false;
1343
    }
1344
1345
    /**
1346
     * Return object width and height
1347
     * Ususaly used for images, but can be realize for video etc...
1348
     *
1349
     * @param string $path file path
1350
     * @param string $mime file mime type
1351
     *
1352
     * @return string
1353
     *
1354
     * @author Dmitry (dio) Levashov
1355
     **/
1356
    protected function _dimensions($path, $mime)
1357
    {
1358
        if (strpos($mime, 'image') !== 0) {
1359
            return '';
1360
        }
1361
1362
        $ret = '';
1363 View Code Duplication
        if ($work = $this->getWorkFile($path)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1364
            if ($size = @getimagesize($work)) {
1365
                $cache['width'] = $size[0];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$cache was never initialized. Although not strictly required by PHP, it is generally a good practice to add $cache = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1366
                $cache['height'] = $size[1];
1367
                $ret = $size[0].'x'.$size[1];
1368
            }
1369
        }
1370
        is_file($work) && @unlink($work);
1371
1372
        return $ret;
1373
    }
1374
1375
    /******************** file/dir content *********************/
1376
1377
    /**
1378
     * Return files list in directory.
1379
     *
1380
     * @param string $path dir path
1381
     *
1382
     * @return array
1383
     *
1384
     * @author Dmitry (dio) Levashov
1385
     * @author Cem (DiscoFever)
1386
     **/
1387
    protected function _scandir($path)
1388
    {
1389
        return isset($this->dirsCache[$path])
1390
            ? $this->dirsCache[$path]
1391
            : $this->cacheDir($path);
1392
    }
1393
1394
    /**
1395
     * Open file and return file pointer.
1396
     *
1397
     * @param string $path  file path
1398
     * @param bool   $write open file for writing
0 ignored issues
show
Bug introduced by
There is no parameter named $write. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1399
     *
1400
     * @return resource|false
1401
     *
1402
     * @author Dmitry (dio) Levashov
1403
     **/
1404 View Code Duplication
    protected function _fopen($path, $mode = 'rb')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1405
    {
1406
        if ($mode === 'rb' || $mode === 'r') {
1407
            list(, $itemId) = $this->_bd_splitPath($path);
1408
            $data = [
1409
                'target' => self::API_URL.'/files/'.$itemId.'/content',
1410
                'headers' => ['Authorization: Bearer '.$this->token->data->access_token],
1411
            ];
1412
1413
            return elFinder::getStreamByUrl($data);
1414
        }
1415
1416
        return false;
1417
    }
1418
1419
    /**
1420
     * Close opened file.
1421
     *
1422
     * @param resource $fp file pointer
1423
     *
1424
     * @return bool
1425
     *
1426
     * @author Dmitry (dio) Levashov
1427
     **/
1428
    protected function _fclose($fp, $path = '')
1429
    {
1430
        fclose($fp);
1431
        if ($path) {
1432
            unlink($this->getTempFile($path));
1433
        }
1434
    }
1435
1436
    /********************  file/dir manipulations *************************/
1437
1438
    /**
1439
     * Create dir and return created dir path or false on failed.
1440
     *
1441
     * @param string $path parent dir path
1442
     * @param string $name new directory name
1443
     *
1444
     * @return string|bool
1445
     *
1446
     * @author Dmitry (dio) Levashov
1447
     **/
1448
    protected function _mkdir($path, $name)
1449
    {
1450
        try {
1451
            list(, $parentId) = $this->_bd_splitPath($path);
1452
            $params = ['name' => $name, 'parent' => ['id' => $parentId]];
1453
1454
            $url = self::API_URL.'/folders';
1455
1456
            $curl = $this->_bd_prepareCurl([
1457
                CURLOPT_URL => $url,
1458
                CURLOPT_POST => true,
1459
                CURLOPT_POSTFIELDS => json_encode($params),
1460
            ]);
1461
1462
            //create the Folder in the Parent
1463
            $folder = $this->_bd_curlExec($curl, $path);
1464
1465
            return $this->_joinPath($path, $folder->id);
1466
        } catch (Exception $e) {
1467
            return $this->setError('Box error: '.$e->getMessage());
1468
        }
1469
    }
1470
1471
    /**
1472
     * Create file and return it's path or false on failed.
1473
     *
1474
     * @param string $path parent dir path
1475
     * @param string $name new file name
1476
     *
1477
     * @return string|bool
1478
     *
1479
     * @author Dmitry (dio) Levashov
1480
     **/
1481
    protected function _mkfile($path, $name)
1482
    {
1483
        return $this->_save(tmpfile(), $path, $name, []);
1484
    }
1485
1486
    /**
1487
     * Create symlink. FTP driver does not support symlinks.
1488
     *
1489
     * @param string $target link target
1490
     * @param string $path   symlink path
1491
     *
1492
     * @return bool
1493
     *
1494
     * @author Dmitry (dio) Levashov
1495
     **/
1496
    protected function _symlink($target, $path, $name)
1497
    {
1498
        return false;
1499
    }
1500
1501
    /**
1502
     * Copy file into another file.
1503
     *
1504
     * @param string $source    source file path
1505
     * @param string $targetDir target directory path
1506
     * @param string $name      new file name
1507
     *
1508
     * @return string|false
1509
     *
1510
     * @author Dmitry (dio) Levashov
1511
     **/
1512
    protected function _copy($source, $targetDir, $name)
1513
    {
1514
        try {
1515
            //Set the Parent id
1516
            list(, $parentId) = $this->_bd_splitPath($targetDir);
1517
            list($srcPid, $srcId) = $this->_bd_splitPath($source);
0 ignored issues
show
Unused Code introduced by
The assignment to $srcPid is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
1518
1519
            $srcItem = $this->_bd_getRawItem($source);
1520
1521
            $properties = ['name' => $name, 'parent' => ['id' => $parentId]];
1522
            $data = (object) $properties;
1523
1524
            $type = ($srcItem->type === 'folder') ? 'folders' : 'files';
1525
            $url = self::API_URL.'/'.$type.'/'.$srcId.'/copy';
1526
1527
            $curl = $this->_bd_prepareCurl([
1528
                CURLOPT_URL => $url,
1529
                CURLOPT_POST => true,
1530
                CURLOPT_POSTFIELDS => json_encode($data),
1531
            ]);
1532
1533
            //copy File in the Parent
1534
            $result = $this->_bd_curlExec($curl, $targetDir);
1535
1536 View Code Duplication
            if (isset($result->id)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1537
                if ($type === 'folders' && isset($this->sessionCache['subdirs'])) {
1538
                    $this->sessionCache['subdirs'][$targetDir] = true;
1539
                }
1540
1541
                return $this->_joinPath($targetDir, $result->id);
1542
            }
1543
1544
            return false;
1545
        } catch (Exception $e) {
1546
            return $this->setError('Box error: '.$e->getMessage());
1547
        }
1548
    }
1549
1550
    /**
1551
     * Move file into another parent dir.
1552
     * Return new file path or false.
1553
     *
1554
     * @param string $source source file path
1555
     * @param string $target target dir path
0 ignored issues
show
Documentation introduced by
There is no parameter named $target. Did you maybe mean $targetDir?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
1556
     * @param string $name   file name
1557
     *
1558
     * @return string|bool
1559
     *
1560
     * @author Dmitry (dio) Levashov
1561
     **/
1562
    protected function _move($source, $targetDir, $name)
1563
    {
1564
        try {
1565
            //moving and renaming a file or directory
1566
            //Set new Parent and remove old parent
1567
            list(, $parentId) = $this->_bd_splitPath($targetDir);
1568
            list(, $itemId) = $this->_bd_splitPath($source);
1569
1570
            $srcItem = $this->_bd_getRawItem($source);
1571
1572
            //rename or move file or folder in destination target
1573
            $properties = ['name' => $name, 'parent' => ['id' => $parentId]];
1574
1575
            $type = ($srcItem->type === 'folder') ? 'folders' : 'files';
1576
            $url = self::API_URL.'/'.$type.'/'.$itemId;
1577
            $data = (object) $properties;
1578
1579
            $curl = $this->_bd_prepareCurl([
1580
                CURLOPT_URL => $url,
1581
                CURLOPT_CUSTOMREQUEST => 'PUT',
1582
                CURLOPT_POSTFIELDS => json_encode($data),
1583
            ]);
1584
1585
            $result = $this->_bd_curlExec($curl, $targetDir, [
1586
                    // The data is sent as JSON as per Box documentation.
1587
                    'Content-Type: application/json',
1588
                ]);
1589
1590
            if ($result && isset($result->id)) {
1591
                return $this->_joinPath($targetDir, $result->id);
1592
            }
1593
1594
            return false;
1595
        } catch (Exception $e) {
1596
            return $this->setError('Box error: '.$e->getMessage());
1597
        }
1598
    }
1599
1600
    /**
1601
     * Remove file.
1602
     *
1603
     * @param string $path file path
1604
     *
1605
     * @return bool
1606
     *
1607
     * @author Dmitry (dio) Levashov
1608
     **/
1609
    protected function _unlink($path)
1610
    {
1611
        return $this->_bd_unlink($path, 'files');
1612
    }
1613
1614
    /**
1615
     * Remove dir.
1616
     *
1617
     * @param string $path dir path
1618
     *
1619
     * @return bool
1620
     *
1621
     * @author Dmitry (dio) Levashov
1622
     **/
1623
    protected function _rmdir($path)
1624
    {
1625
        return $this->_bd_unlink($path, 'folders');
1626
    }
1627
1628
    /**
1629
     * Create new file and write into it from file pointer.
1630
     * Return new file path or false on error.
1631
     *
1632
     * @param resource $fp   file pointer
1633
     * @param string   $dir  target dir path
0 ignored issues
show
Bug introduced by
There is no parameter named $dir. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1634
     * @param string   $name file name
1635
     * @param array    $stat file stat (required by some virtual fs)
1636
     *
1637
     * @return bool|string
1638
     *
1639
     * @author Dmitry (dio) Levashov
1640
     **/
1641
    protected function _save($fp, $path, $name, $stat)
1642
    {
1643
        $itemId = '';
1644 View Code Duplication
        if ($name === '') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1645
            list($parentId, $itemId, $parent) = $this->_bd_splitPath($path);
1646
        } else {
1647
            if ($stat) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $stat of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1648
                if (isset($stat['name'])) {
1649
                    $name = $stat['name'];
1650
                }
1651
                if (isset($stat['rev']) && strpos($stat['hash'], $this->id) === 0) {
1652
                    $itemId = $stat['rev'];
1653
                }
1654
            }
1655
            list(, $parentId) = $this->_bd_splitPath($path);
1656
            $parent = $path;
1657
        }
1658
1659
        try {
1660
            //Create or Update a file
1661
            $metaDatas = stream_get_meta_data($fp);
1662
            $tmpFilePath = isset($metaDatas['uri']) ? $metaDatas['uri'] : '';
1663
            // remote contents
1664
            if (! $tmpFilePath || empty($metaDatas['seekable'])) {
1665
                $tmpHandle = tmpfile();
1666
                stream_copy_to_stream($fp, $tmpHandle);
1667
                $metaDatas = stream_get_meta_data($tmpHandle);
1668
                $tmpFilePath = $metaDatas['uri'];
1669
            }
1670
1671
            if ($itemId === '') {
1672
                //upload or create new file in destination target
1673
                $properties = ['name' => $name, 'parent' => ['id' => $parentId]];
1674
                $url = self::UPLOAD_URL.'/files/content';
1675
            } else {
1676
                //update existing file in destination target
1677
                $properties = ['name' => $name];
1678
                $url = self::UPLOAD_URL.'/files/'.$itemId.'/content';
1679
            }
1680
1681
            if (class_exists('CURLFile')) {
1682
                $cfile = new CURLFile($tmpFilePath);
1683
            } else {
1684
                $cfile = '@'.$tmpFilePath;
1685
            }
1686
            $params = ['attributes' => json_encode($properties), 'file' => $cfile];
1687
            $curl = $this->_bd_prepareCurl([
1688
                    CURLOPT_URL => $url,
1689
                    CURLOPT_POST => true,
1690
                    CURLOPT_POSTFIELDS => $params,
1691
                ]);
1692
1693
            $file = $this->_bd_curlExec($curl, $parent);
1694
1695
            return $this->_joinPath($parent, $file->entries[0]->id);
1696
        } catch (Exception $e) {
1697
            return $this->setError('Box error: '.$e->getMessage());
1698
        }
1699
    }
1700
1701
    /**
1702
     * Get file contents.
1703
     *
1704
     * @param string $path file path
1705
     *
1706
     * @return string|false
1707
     *
1708
     * @author Dmitry (dio) Levashov
1709
     **/
1710 View Code Duplication
    protected function _getContents($path)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1711
    {
1712
        $contents = '';
1713
1714
        try {
1715
            list(, $itemId) = $this->_bd_splitPath($path);
1716
            $url = self::API_URL.'/files/'.$itemId.'/content';
1717
1718
            $contents = $this->_bd_fetch($url, true);
1719
        } catch (Exception $e) {
1720
            return $this->setError('Box error: '.$e->getMessage());
1721
        }
1722
1723
        return $contents;
1724
    }
1725
1726
    /**
1727
     * Write a string to a file.
1728
     *
1729
     * @param string $path    file path
1730
     * @param string $content new file content
1731
     *
1732
     * @return bool
1733
     *
1734
     * @author Dmitry (dio) Levashov
1735
     **/
1736 View Code Duplication
    protected function _filePutContents($path, $content)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1737
    {
1738
        $res = false;
1739
1740
        if ($local = $this->getTempFile($path)) {
1741
            if (file_put_contents($local, $content, LOCK_EX) !== false
1742
            && ($fp = fopen($local, 'rb'))) {
1743
                clearstatcache();
1744
                $res = $this->_save($fp, $path, '', []);
1745
                fclose($fp);
1746
            }
1747
            file_exists($local) && unlink($local);
1748
        }
1749
1750
        return $res;
1751
    }
1752
1753
    /**
1754
     * Detect available archivers.
1755
     **/
1756
    protected function _checkArchivers()
1757
    {
1758
        // die('Not yet implemented. (_checkArchivers)');
0 ignored issues
show
Unused Code Comprehensibility introduced by
84% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1759
        return [];
1760
    }
1761
1762
    /**
1763
     * chmod implementation.
1764
     *
1765
     * @return bool
1766
     **/
1767
    protected function _chmod($path, $mode)
1768
    {
1769
        return false;
1770
    }
1771
1772
    /**
1773
     * Unpack archive.
1774
     *
1775
     * @param string $path archive path
1776
     * @param array  $arc  archiver command and arguments (same as in $this->archivers)
1777
     *
1778
     * @return true
1779
     *
1780
     * @author Dmitry (dio) Levashov
1781
     * @author Alexey Sukhotin
1782
     **/
1783
    protected function _unpack($path, $arc)
0 ignored issues
show
Unused Code introduced by
The parameter $path is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $arc is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1784
    {
1785
        die('Not yet implemented. (_unpack)');
0 ignored issues
show
Coding Style Compatibility introduced by
The method _unpack() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1786
        //return false;
1787
    }
1788
1789
    /**
1790
     * Recursive symlinks search.
1791
     *
1792
     * @param string $path file/dir path
1793
     *
1794
     * @return bool
1795
     *
1796
     * @author Dmitry (dio) Levashov
1797
     **/
1798
    protected function _findSymlinks($path)
0 ignored issues
show
Unused Code introduced by
The parameter $path is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1799
    {
1800
        die('Not yet implemented. (_findSymlinks)');
0 ignored issues
show
Coding Style Compatibility introduced by
The method _findSymlinks() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1801
    }
1802
1803
    /**
1804
     * Extract files from archive.
1805
     *
1806
     * @param string $path archive path
1807
     * @param array  $arc  archiver command and arguments (same as in $this->archivers)
1808
     *
1809
     * @return true
1810
     *
1811
     * @author Dmitry (dio) Levashov,
1812
     * @author Alexey Sukhotin
1813
     **/
1814
    protected function _extract($path, $arc)
1815
    {
1816
        die('Not yet implemented. (_extract)');
0 ignored issues
show
Coding Style Compatibility introduced by
The method _extract() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1817
    }
1818
1819
    /**
1820
     * Create archive and return its path.
1821
     *
1822
     * @param string $dir   target dir
1823
     * @param array  $files files names list
1824
     * @param string $name  archive name
1825
     * @param array  $arc   archiver options
1826
     *
1827
     * @return string|bool
1828
     *
1829
     * @author Dmitry (dio) Levashov,
1830
     * @author Alexey Sukhotin
1831
     **/
1832
    protected function _archive($dir, $files, $name, $arc)
1833
    {
1834
        die('Not yet implemented. (_archive)');
0 ignored issues
show
Coding Style Compatibility introduced by
The method _archive() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1835
    }
1836
} // END class
1837