Completed
Push — master ( 61c24d...075a0d )
by recca
07:28
created

elFinderVolumeDropbox::cacheDir()   D

Complexity

Conditions 9
Paths 4

Size

Total Lines 28
Code Lines 16

Duplication

Lines 9
Ratio 32.14 %

Importance

Changes 0
Metric Value
cc 9
eloc 16
nc 4
nop 1
dl 9
loc 28
rs 4.909
c 0
b 0
f 0
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 11 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['dropbox'] = 'Dropbox';
4
5
/**
6
 * Simple elFinder driver for FTP.
7
 *
8
 * @author Dmitry (dio) Levashov
9
 * @author Cem (discofever)
10
 **/
11
class elFinderVolumeDropbox 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...
12
{
13
    /**
14
	 * Driver id
15
	 * Must be started from letter and contains [a-z0-9]
16
	 * Used as part of volume id.
17
	 *
18
	 * @var string
19
	 **/
20
	protected $driverId = 'd';
21
22
	/**
23
	 * OAuth object.
24
	 *
25
	 * @var oauth
26
	 **/
27
	protected $oauth = null;
28
29
	/**
30
	 * Dropbox object.
31
	 *
32
	 * @var dropbox
33
	 **/
34
	protected $dropbox = null;
35
36
	/**
37
	 * Directory for meta data caches
38
	 * If not set driver not cache meta data.
39
	 *
40
	 * @var string
41
	 **/
42
	protected $metaCache = '';
43
44
	/**
45
	 * Last API error message.
46
	 *
47
	 * @var string
48
	 **/
49
	protected $apiError = '';
50
51
	/**
52
	 * Directory for tmp files
53
	 * If not set driver will try to use tmbDir as tmpDir.
54
	 *
55
	 * @var string
56
	 **/
57
	protected $tmp = '';
58
59
	/**
60
	 * Dropbox.com uid.
61
	 *
62
	 * @var string
63
	 **/
64
	protected $dropboxUid = '';
65
66
	/**
67
	 * Dropbox download host, replaces 'www.dropbox.com' of shares URL.
68
	 *
69
	 * @var string
70
	 */
71
	private $dropbox_dlhost = 'dl.dropboxusercontent.com';
72
73
    private $dropbox_phpFound = false;
74
75
    private $DB_TableName = '';
76
77
    private $tmbPrefix = '';
78
79
	/**
80
	 * Constructor
81
	 * Extend options with required fields.
82
	 *
83
	 * @author Dmitry (dio) Levashov
84
	 * @author Cem (DiscoFever)
85
	 */
86
	public function __construct()
87
	{
88
89
		// check with composer
90
		$this->dropbox_phpFound = class_exists('Dropbox_API');
91
92
	    if (! $this->dropbox_phpFound) {
93
	        // check with pear
94
			if (include_once 'Dropbox/autoload.php') {
95
			    $this->dropbox_phpFound = in_array('Dropbox_autoload', spl_autoload_functions());
96
			}
97
	    }
98
99
	    $opts = [
100
			'consumerKey' => '',
101
			'consumerSecret' => '',
102
			'accessToken' => '',
103
			'accessTokenSecret' => '',
104
			'dropboxUid' => '',
105
			'root' => 'dropbox',
106
			'path' => '/',
107
			'separator' => '/',
108
			'PDO_DSN' => '', // if empty use 'sqlite:(metaCachePath|tmbPath)/elFinder_dropbox_db_(hash:dropboxUid+consumerSecret)'
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% 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...
109
			'PDO_User' => '',
110
			'PDO_Pass' => '',
111
			'PDO_Options' => [],
112
			'PDO_DBName' => 'dropbox',
113
			'treeDeep' => 0,
114
			'tmbPath' => '',
115
			'tmbURL' => '',
116
			'tmpPath' => '',
117
			'getTmbSize' => 'large', // small: 32x32, medium or s: 64x64, large or m: 128x128, l: 640x480, xl: 1024x768
118
			'metaCachePath' => '',
119
			'metaCacheTime' => '600', // 10m
120
			'acceptedName' => '#^[^/\\?*:|"<>]*[^./\\?*:|"<>]$#',
121
			'rootCssClass' => 'elfinder-navbar-root-dropbox',
122
		];
123
	    $this->options = array_merge($this->options, $opts);
124
	    $this->options['mimeDetect'] = 'internal';
125
	}
126
127
	/**
128
	 * Prepare
129
	 * Call from elFinder::netmout() before volume->mount().
130
	 *
131
	 * @param $options
132
	 * @return array
133
	 * @author Naoki Sawada
134
	 */
135
	public function netmountPrepare($options)
0 ignored issues
show
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...
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...
136
	{
137
	    if (empty($options['consumerKey']) && defined('ELFINDER_DROPBOX_CONSUMERKEY')) {
138
	        $options['consumerKey'] = ELFINDER_DROPBOX_CONSUMERKEY;
139
	    }
140
	    if (empty($options['consumerSecret']) && defined('ELFINDER_DROPBOX_CONSUMERSECRET')) {
141
	        $options['consumerSecret'] = ELFINDER_DROPBOX_CONSUMERSECRET;
142
	    }
143
144
	    if ($options['user'] === 'init') {
145
	        if (! $this->dropbox_phpFound || empty($options['consumerKey']) || empty($options['consumerSecret']) || ! class_exists('PDO', false)) {
146
	            return ['exit' => true, 'body' => '{msg:errNetMountNoDriver}'];
147
	        }
148
149
	        if (defined('ELFINDER_DROPBOX_USE_CURL_PUT')) {
150
	            $this->oauth = new Dropbox_OAuth_Curl($options['consumerKey'], $options['consumerSecret']);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Dropbox_OAuth_Curl(...ions['consumerSecret']) of type object<Dropbox_OAuth_Curl> is incompatible with the declared type object<oauth> of property $oauth.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
151
	        } else {
152
	            if (class_exists('OAuth', false)) {
153
	                $this->oauth = new Dropbox_OAuth_PHP($options['consumerKey'], $options['consumerSecret']);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Dropbox_OAuth_PHP($...ions['consumerSecret']) of type object<Dropbox_OAuth_PHP> is incompatible with the declared type object<oauth> of property $oauth.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
154
	            } else {
155
	                if (! class_exists('HTTP_OAuth_Consumer')) {
156
	                    // We're going to try to load in manually
157
						include 'HTTP/OAuth/Consumer.php';
158
	                }
159
	                if (class_exists('HTTP_OAuth_Consumer', false)) {
160
	                    $this->oauth = new Dropbox_OAuth_PEAR($options['consumerKey'], $options['consumerSecret']);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Dropbox_OAuth_PEAR(...ions['consumerSecret']) of type object<Dropbox_OAuth_PEAR> is incompatible with the declared type object<oauth> of property $oauth.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
161
	                }
162
	            }
163
	        }
164
165
	        if (! $this->oauth) {
166
	            return ['exit' => true, 'body' => '{msg:errNetMountNoDriver}'];
167
	        }
168
169
	        if ($options['pass'] === 'init') {
170
	            $html = '';
171
	            if ($sessionToken = $this->session->get('DropboxTokens')) {
172
	                // token check
173
					try {
174
					    list(, $accessToken, $accessTokenSecret) = $sessionToken;
175
					    $this->oauth->setToken($accessToken, $accessTokenSecret);
176
					    $this->dropbox = new Dropbox_API($this->oauth, $this->options['root']);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Dropbox_API($this->...$this->options['root']) of type object<Dropbox_API> is incompatible with the declared type object<dropbox> of property $dropbox.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
177
					    $this->dropbox->getAccountInfo();
178
					    $script = '<script>
179
							$("#'.$options['id'].'").elfinder("instance").trigger("netmount", {protocol: "dropbox", mode: "done"});
180
						</script>';
181
					    $html = $script;
182
					} catch (Dropbox_Exception $e) {
0 ignored issues
show
Bug introduced by
The class Dropbox_Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
183
					    $this->session->remove('DropboxTokens');
184
					}
185
	            }
186
	            if (! $html) {
187
	                // get customdata
188
					$cdata = '';
189
	                $innerKeys = ['cmd', 'host', 'options', 'pass', 'protocol', 'user'];
190
	                $this->ARGS = $_SERVER['REQUEST_METHOD'] === 'POST' ? $_POST : $_GET;
191 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...
192
	                    if (! in_array($k, $innerKeys)) {
193
	                        $cdata .= '&'.$k.'='.rawurlencode($v);
194
	                    }
195
	                }
196
	                if (strpos($options['url'], 'http') !== 0) {
197
	                    $options['url'] = elFinder::getConnectorUrl();
198
	                }
199
	                $callback = $options['url']
200
					           .'?cmd=netmount&protocol=dropbox&host=dropbox.com&user=init&pass=return&node='.$options['id'].$cdata;
201
202
	                try {
203
	                    $tokens = $this->oauth->getRequestToken();
204
	                    $url = $this->oauth->getAuthorizeUrl(rawurlencode($callback));
205
	                } catch (Dropbox_Exception $e) {
0 ignored issues
show
Bug introduced by
The class Dropbox_Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
206
	                    return ['exit' => true, 'body' => '{msg:errAccess}'];
207
	                }
208
209
	                $this->session->set('DropboxAuthTokens', $tokens);
210
	                $html = '<input id="elf-volumedriver-dropbox-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.'\')">';
211
	                $html .= '<script>
212
						$("#'.$options['id'].'").elfinder("instance").trigger("netmount", {protocol: "dropbox", mode: "makebtn"});
213
					</script>';
214
	            }
215
216
	            return ['exit' => true, 'body' => $html];
217
	        } else {
218
	            $this->oauth->setToken($this->session->get('DropboxAuthTokens'));
219
	            $this->session->remove('DropboxAuthTokens');
220
	            $tokens = $this->oauth->getAccessToken();
221
	            $this->session->set('DropboxTokens', [$_GET['uid'], $tokens['token'], $tokens['token_secret']]);
222
223
	            $out = [
224
					'node' => $_GET['node'],
225
					'json' => '{"protocol": "dropbox", "mode": "done"}',
226
					'bind' => 'netmount',
227
				];
228
229
	            return ['exit' => 'callback', 'out' => $out];
230
	        }
231
	    }
232
	    if ($sessionToken = $this->session->get('DropboxTokens')) {
233
	        list($options['dropboxUid'], $options['accessToken'], $options['accessTokenSecret']) = $sessionToken;
234
	    }
235
	    unset($options['user'], $options['pass']);
236
237
	    return $options;
238
	}
239
240
	/**
241
	 * process of on netunmount
242
	 * Drop table `dropbox` & rm thumbs.
243
	 *
244
	 * @param $netVolumes
245
	 * @param $key
246
	 * @return bool
247
	 * @internal param array $options
248
	 */
249
	public function netunmount($netVolumes, $key)
250
	{
251
	    $count = 0;
252
	    $dropboxUid = '';
253
	    if (isset($netVolumes[$key])) {
254
	        $dropboxUid = $netVolumes[$key]['dropboxUid'];
255
	    }
256
	    foreach ($netVolumes as $volume) {
257
	        if ($volume['host'] === 'dropbox' && $volume['dropboxUid'] === $dropboxUid) {
258
	            $count++;
259
	        }
260
	    }
261
	    if ($count === 1) {
262
	        $this->DB->exec('drop table '.$this->DB_TableName);
0 ignored issues
show
Bug introduced by
The property DB does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
263
	        foreach (glob(rtrim($this->options['tmbPath'], '\\/').DIRECTORY_SEPARATOR.$this->tmbPrefix.'*.png') as $tmb) {
264
	            unlink($tmb);
265
	        }
266
	    }
267
268
	    return true;
269
	}
270
271
	/*********************************************************************/
272
	/*                               FS API                              */
273
	/*********************************************************************/
274
275
	/**
276
	 * Close opened connection.
277
	 *
278
	 * @return void
279
	 * @author Dmitry (dio) Levashov
280
	 **/
281
	public function umount()
282
	{
283
	}
284
285
	/**
286
	 * Return content URL.
287
	 *
288
	 * @param string  $hash  file hash
289
	 * @param array $options options
290
	 * @return array
291
	 * @author Naoki Sawada
292
	 **/
293
	public function getContentUrl($hash, $options = [])
294
	{
295
	    if (($file = $this->file($hash)) == false || ! $file['url'] || $file['url'] == 1) {
296
	        $path = $this->decode($hash);
297
	        $cache = $this->getDBdat($path);
298
	        $url = '';
299
	        if (isset($cache['share']) && strpos($cache['share'], $this->dropbox_dlhost) !== false) {
300
	            $res = $this->getHttpResponseHeader($cache['share']);
301
	            if (preg_match("/^HTTP\/[01\.]+ ([0-9]{3})/", $res, $match)) {
302
	                if ($match[1] < 400) {
303
	                    $url = $cache['share'];
304
	                }
305
	            }
306
	        }
307
	        if (! $url) {
308
	            try {
309
	                $res = $this->dropbox->share($path, null, false);
310
	                $url = $res['url'];
311
	                if (strpos($url, 'www.dropbox.com') === false) {
312
	                    $res = $this->getHttpResponseHeader($url);
313
	                    if (preg_match('/^location:\s*(http[^\s]+)/im', $res, $match)) {
314
	                        $url = $match[1];
315
	                    }
316
	                }
317
	                list($url) = explode('?', $url);
318
	                $url = str_replace('www.dropbox.com', $this->dropbox_dlhost, $url);
319
	                if (! isset($cache['share']) || $cache['share'] !== $url) {
320
	                    $cache['share'] = $url;
321
	                    $this->updateDBdat($path, $cache);
322
	                }
323
	            } catch (Dropbox_Exception $e) {
0 ignored issues
show
Bug introduced by
The class Dropbox_Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
324
	                return false;
325
	            }
326
	        }
327
328
	        return $url;
329
	    }
330
331
	    return $file['url'];
332
	}
333
334
	/*********************************************************************/
335
	/*                        INIT AND CONFIGURE                         */
336
	/*********************************************************************/
337
338
	/**
339
	 * Prepare FTP connection
340
	 * Connect to remote server and check if credentials are correct, if so, store the connection id in $ftp_conn.
341
	 *
342
	 * @return bool
343
	 * @author Dmitry (dio) Levashov
344
	 * @author Cem (DiscoFever)
345
	 **/
346
	protected function init()
347
	{
348
	    if (! class_exists('PDO', false)) {
349
	        return $this->setError('PHP PDO class is require.');
350
	    }
351
352
	    if (! $this->options['consumerKey']
353
		|| ! $this->options['consumerSecret']
354
		|| ! $this->options['accessToken']
355
		|| ! $this->options['accessTokenSecret']) {
356
	        return $this->setError('Required options undefined.');
357
	    }
358
359
	    if (empty($this->options['metaCachePath']) && defined('ELFINDER_DROPBOX_META_CACHE_PATH')) {
360
	        $this->options['metaCachePath'] = ELFINDER_DROPBOX_META_CACHE_PATH;
361
	    }
362
363
		// make net mount key
364
		$this->netMountKey = md5(implode('-', ['dropbox', $this->options['path']]));
365
366
	    if (! $this->oauth) {
367
	        if (defined('ELFINDER_DROPBOX_USE_CURL_PUT')) {
368
	            $this->oauth = new Dropbox_OAuth_Curl($this->options['consumerKey'], $this->options['consumerSecret']);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Dropbox_OAuth_Curl(...ions['consumerSecret']) of type object<Dropbox_OAuth_Curl> is incompatible with the declared type object<oauth> of property $oauth.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
369
	        } else {
370
	            if (class_exists('OAuth', false)) {
371
	                $this->oauth = new Dropbox_OAuth_PHP($this->options['consumerKey'], $this->options['consumerSecret']);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Dropbox_OAuth_PHP($...ions['consumerSecret']) of type object<Dropbox_OAuth_PHP> is incompatible with the declared type object<oauth> of property $oauth.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
372
	            } else {
373
	                if (! class_exists('HTTP_OAuth_Consumer')) {
374
	                    // We're going to try to load in manually
375
						include 'HTTP/OAuth/Consumer.php';
376
	                }
377
	                if (class_exists('HTTP_OAuth_Consumer', false)) {
378
	                    $this->oauth = new Dropbox_OAuth_PEAR($this->options['consumerKey'], $this->options['consumerSecret']);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Dropbox_OAuth_PEAR(...ions['consumerSecret']) of type object<Dropbox_OAuth_PEAR> is incompatible with the declared type object<oauth> of property $oauth.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
379
	                }
380
	            }
381
	        }
382
	    }
383
384
	    if (! $this->oauth) {
385
	        return $this->setError('OAuth extension not loaded.');
386
	    }
387
388
		// normalize root path
389
		$this->root = $this->options['path'] = $this->_normpath($this->options['path']);
390
391 View Code Duplication
	    if (empty($this->options['alias'])) {
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...
392
	        $this->options['alias'] = ($this->options['path'] === '/') ? 'Dropbox.com' : 'Dropbox'.$this->options['path'];
393
	    }
394
395
	    $this->rootName = $this->options['alias'];
396
397
	    try {
398
	        $this->oauth->setToken($this->options['accessToken'], $this->options['accessTokenSecret']);
399
	        $this->dropbox = new Dropbox_API($this->oauth, $this->options['root']);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Dropbox_API($this->...$this->options['root']) of type object<Dropbox_API> is incompatible with the declared type object<dropbox> of property $dropbox.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
400
	    } catch (Dropbox_Exception $e) {
0 ignored issues
show
Bug introduced by
The class Dropbox_Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
401
	        $this->session->remove('DropboxTokens');
402
403
	        return $this->setError('Dropbox error: '.$e->getMessage());
404
	    }
405
406
		// user
407
		if (empty($this->options['dropboxUid'])) {
408
		    try {
409
		        $res = $this->dropbox->getAccountInfo();
410
		        $this->options['dropboxUid'] = $res['uid'];
411
		    } catch (Dropbox_Exception $e) {
0 ignored issues
show
Bug introduced by
The class Dropbox_Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
412
		        $this->session->remove('DropboxTokens');
413
414
		        return $this->setError('Dropbox error: '.$e->getMessage());
415
		    }
416
		}
417
418
	    $this->dropboxUid = $this->options['dropboxUid'];
419
	    $this->tmbPrefix = 'dropbox'.base_convert($this->dropboxUid, 10, 32);
420
421
	    if (! empty($this->options['tmpPath'])) {
422
	        if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($this->options['tmpPath'])) {
423
	            $this->tmp = $this->options['tmpPath'];
424
	        }
425
	    }
426
	    if (! $this->tmp && is_writable($this->options['tmbPath'])) {
427
	        $this->tmp = $this->options['tmbPath'];
428
	    }
429
	    if (! $this->tmp && ($tmp = elFinder::getStaticVar('commonTempPath'))) {
430
	        $this->tmp = $tmp;
431
	    }
432
433 View Code Duplication
	    if (! empty($this->options['metaCachePath'])) {
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...
434
	        if ((is_dir($this->options['metaCachePath']) || mkdir($this->options['metaCachePath'])) && is_writable($this->options['metaCachePath'])) {
435
	            $this->metaCache = $this->options['metaCachePath'];
436
	        }
437
	    }
438
	    if (! $this->metaCache && $this->tmp) {
439
	        $this->metaCache = $this->tmp;
440
	    }
441
442
	    if (! $this->metaCache) {
443
	        return $this->setError('Cache dirctory (metaCachePath or tmp) is require.');
444
	    }
445
446
		// setup PDO
447
		if (! $this->options['PDO_DSN']) {
448
		    $this->options['PDO_DSN'] = 'sqlite:'.$this->metaCache.DIRECTORY_SEPARATOR.'.elFinder_dropbox_db_'.md5($this->dropboxUid.$this->options['consumerSecret']);
449
		}
450
		// DataBase table name
451
		$this->DB_TableName = $this->options['PDO_DBName'];
452
		// DataBase check or make table
453
		try {
454
		    $this->DB = new PDO($this->options['PDO_DSN'], $this->options['PDO_User'], $this->options['PDO_Pass'], $this->options['PDO_Options']);
455
		    if (! $this->checkDB()) {
456
		        return $this->setError('Can not make DB table');
457
		    }
458
		} catch (PDOException $e) {
459
		    return $this->setError('PDO connection failed: '.$e->getMessage());
460
		}
461
462
	    $res = $this->deltaCheck($this->isMyReload());
463
	    if ($res !== true) {
464
	        if (is_string($res)) {
465
	            return $this->setError($res);
466
	        } else {
467
	            return $this->setError('Could not check API "delta"');
468
	        }
469
	    }
470
471
	    if (is_null($this->options['syncChkAsTs'])) {
472
	        $this->options['syncChkAsTs'] = true;
473
	    }
474 View Code Duplication
	    if ($this->options['syncChkAsTs']) {
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...
475
	        // 'tsPlSleep' minmum 5 sec
476
			$this->options['tsPlSleep'] = max(5, $this->options['tsPlSleep']);
477
	    } else {
478
	        // 'lsPlSleep' minmum 10 sec
479
			$this->options['lsPlSleep'] = max(10, $this->options['lsPlSleep']);
480
	    }
481
482
	    return true;
483
	}
484
485
	/**
486
	 * Configure after successful mount.
487
	 *
488
	 * @return string
489
	 * @author Dmitry (dio) Levashov
490
	 **/
491
	protected function configure()
492
	{
493
	    parent::configure();
494
495
	    $this->disabled[] = 'archive';
496
	    $this->disabled[] = 'extract';
497
	}
498
499
	/**
500
	 * Get delta data and DB update.
501
	 *
502
	 * @param bool $refresh force refresh
503
	 * @return true|string error message
504
	 */
505
	protected function deltaCheck($refresh = true)
0 ignored issues
show
Coding Style introduced by
deltaCheck 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...
506
	{
507
	    $chk = false;
508
	    if (! $refresh && $chk = $this->query('select dat from '.$this->DB_TableName.' where path=\'\' and fname=\'\' limit 1')) {
509
	        $chk = unserialize($chk[0]);
510
	    }
511
	    if ($chk && ($chk['mtime'] + $this->options['metaCacheTime']) > $_SERVER['REQUEST_TIME']) {
512
	        return true;
513
	    }
514
515
	    try {
516
	        $more = true;
0 ignored issues
show
Unused Code introduced by
$more 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...
517
	        $this->DB->beginTransaction();
518
519
	        if ($res = $this->query('select dat from '.$this->DB_TableName.' where path=\'\' and fname=\'\' limit 1')) {
520
	            $res = unserialize($res[0]);
521
	            $cursor = $res['cursor'];
522
	        } else {
523
	            $cursor = '';
524
	        }
525
	        $delete = false;
526
	        $reset = false;
527
	        $ptimes = [];
528
	        $now = time();
529
	        do {
530
	            ini_set('max_execution_time', 120);
531
	            $_info = $this->dropbox->delta($cursor);
532
	            if (! empty($_info['reset'])) {
533
	                $this->DB->exec('TRUNCATE table '.$this->DB_TableName);
534
	                $this->DB->exec('insert into '.$this->DB_TableName.' values(\'\', \'\', \''.serialize(['cursor' => '', 'mtime' => 0]).'\', 0);');
535
	                $this->DB->exec('insert into '.$this->DB_TableName.' values(\'/\', \'\', \''.serialize([
536
						'path' => '/',
537
						'is_dir' => 1,
538
						'mime_type' => '',
539
						'bytes' => 0,
540
					]).'\', 0);');
541
	                $reset = true;
542
	            }
543
	            $cursor = $_info['cursor'];
544
545
	            foreach ($_info['entries'] as $entry) {
546
	                $key = strtolower($entry[0]);
547
	                $pkey = strtolower($this->_dirname($key));
548
549
	                $path = $this->DB->quote($pkey);
550
	                $fname = $this->DB->quote(strtolower($this->_basename($key)));
551
	                $where = 'where path='.$path.' and fname='.$fname;
552
553
	                if (empty($entry[1])) {
554
	                    $ptimes[$pkey] = isset($ptimes[$pkey]) ? max([$now, $ptimes[$pkey]]) : $now;
555
	                    $this->DB->exec('delete from '.$this->DB_TableName.' '.$where);
556
	                    ! $delete && $delete = true;
557
	                    continue;
558
	                }
559
560
	                $_itemTime = strtotime(isset($entry[1]['client_mtime']) ? $entry[1]['client_mtime'] : $entry[1]['modified']);
561
	                $ptimes[$pkey] = isset($ptimes[$pkey]) ? max([$_itemTime, $ptimes[$pkey]]) : $_itemTime;
562
	                $sql = 'select path from '.$this->DB_TableName.' '.$where.' limit 1';
563
	                if (! $reset && $this->query($sql)) {
564
	                    $this->DB->exec('update '.$this->DB_TableName.' set dat='.$this->DB->quote(serialize($entry[1])).', isdir='.($entry[1]['is_dir'] ? 1 : 0).' '.$where);
565
	                } else {
566
	                    $this->DB->exec('insert into '.$this->DB_TableName.' values ('.$path.', '.$fname.', '.$this->DB->quote(serialize($entry[1])).', '.(int) $entry[1]['is_dir'].')');
567
	                }
568
	            }
569
	        } while (! empty($_info['has_more']));
570
571
			// update time stamp of parent holder
572
			foreach ($ptimes as $_p => $_t) {
573
			    if ($praw = $this->getDBdat($_p)) {
574
			        $_update = false;
575 View Code Duplication
			        if (isset($praw['client_mtime']) && $_t > strtotime($praw['client_mtime'])) {
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...
576
			            $praw['client_mtime'] = date('r', $_t);
577
			            $_update = true;
578
			        }
579 View Code Duplication
			        if (isset($praw['modified']) && $_t > strtotime($praw['modified'])) {
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...
580
			            $praw['modified'] = date('r', $_t);
581
			            $_update = true;
582
			        }
583
			        if ($_update) {
584
			            $pwhere = 'where path='.$this->DB->quote(strtolower($this->_dirname($_p))).' and fname='.$this->DB->quote(strtolower($this->_basename($_p)));
585
			            $this->DB->exec('update '.$this->DB_TableName.' set dat='.$this->DB->quote(serialize($praw)).' '.$pwhere);
586
			        }
587
			    }
588
			}
589
590
	        $this->DB->exec('update '.$this->DB_TableName.' set dat='.$this->DB->quote(serialize(['cursor' => $cursor, 'mtime' => $_SERVER['REQUEST_TIME']])).' where path=\'\' and fname=\'\'');
591
	        if (! $this->DB->commit()) {
592
	            $e = $this->DB->errorInfo();
593
594
	            return $e[2];
595
	        }
596
	        if ($delete) {
597
	            $this->DB->exec('vacuum');
598
	        }
599
	    } catch (Dropbox_Exception $e) {
0 ignored issues
show
Bug introduced by
The class Dropbox_Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
600
	        return $e->getMessage();
601
	    }
602
603
	    return true;
604
	}
605
606
	/**
607
	 * Parse line from dropbox metadata output and return file stat (array).
608
	 *
609
	 * @param  string  $raw  line from ftp_rawlist() output
610
	 * @return array
611
	 * @author Dmitry Levashov
612
	 **/
613
	protected function parseRaw($raw)
0 ignored issues
show
Coding Style introduced by
parseRaw 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...
614
	{
615
	    $stat = [];
616
617
	    $stat['rev'] = isset($raw['rev']) ? $raw['rev'] : 'root';
618
	    $stat['name'] = $this->_basename($raw['path']);
619
	    $stat['mime'] = $raw['is_dir'] ? 'directory' : $raw['mime_type'];
620
	    $stat['size'] = $stat['mime'] == 'directory' ? 0 : $raw['bytes'];
621
	    $stat['ts'] = isset($raw['client_mtime']) ? strtotime($raw['client_mtime']) :
622
		                (isset($raw['modified']) ? strtotime($raw['modified']) : $_SERVER['REQUEST_TIME']);
623
	    $stat['dirs'] = 0;
624
	    if ($raw['is_dir']) {
625
	        $stat['dirs'] = (int) (bool) $this->query('select path from '.$this->DB_TableName.' where isdir=1 and path='.$this->DB->quote(strtolower($raw['path'])));
626
	    }
627
628
	    if (! empty($raw['url'])) {
629
	        $stat['url'] = $raw['url'];
630
	    } elseif (! $this->disabledGetUrl) {
631
	        $stat['url'] = '1';
632
	    }
633
	    if (isset($raw['width'])) {
634
	        $stat['width'] = $raw['width'];
635
	    }
636
	    if (isset($raw['height'])) {
637
	        $stat['height'] = $raw['height'];
638
	    }
639
640
	    return $stat;
641
	}
642
643
	/**
644
	 * Cache dir contents.
645
	 *
646
	 * @param  string  $path  dir path
647
	 * @return string
648
	 * @author Dmitry Levashov
649
	 **/
650
	protected function cacheDir($path)
651
	{
652
	    $this->dirsCache[$path] = [];
653
	    $hasDir = false;
654
655
	    $res = $this->query('select dat from '.$this->DB_TableName.' where path='.$this->DB->quote(strtolower($path)));
656
657
	    if ($res) {
658
	        foreach ($res as $raw) {
0 ignored issues
show
Bug introduced by
The expression $res of type boolean|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
659
	            $raw = unserialize($raw);
660 View Code Duplication
	            if ($stat = $this->parseRaw($raw)) {
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...
661
	                $stat = $this->updateCache($raw['path'], $stat);
662
	                if (empty($stat['hidden']) && $path !== $raw['path']) {
663
	                    if (! $hasDir && $stat['mime'] === 'directory') {
664
	                        $hasDir = true;
665
	                    }
666
	                    $this->dirsCache[$path][] = $raw['path'];
667
	                }
668
	            }
669
	        }
670
	    }
671
672
	    if (isset($this->sessionCache['subdirs'])) {
673
	        $this->sessionCache['subdirs'][$path] = $hasDir;
674
	    }
675
676
	    return $this->dirsCache[$path];
677
	}
678
679
	/**
680
	 * Recursive files search.
681
	 *
682
	 * @param  string  $path   dir path
683
	 * @param  string  $q      search string
684
	 * @param  array   $mimes
685
	 * @return array
686
	 * @author Naoki Sawada
687
	 **/
688
	protected function doSearch($path, $q, $mimes)
689
	{
690
	    $result = [];
691
	    $sth = $this->DB->prepare('select dat from '.$this->DB_TableName.' WHERE path LIKE ? AND fname LIKE ?');
692
	    $sth->execute([(($path === '/') ? '' : strtolower($path)).'%', '%'.strtolower($q).'%']);
693
	    $res = $sth->fetchAll(PDO::FETCH_COLUMN);
694
	    $timeout = $this->options['searchTimeout'] ? $this->searchStart + $this->options['searchTimeout'] : 0;
695
696
	    if ($res) {
697
	        foreach ($res as $raw) {
698 View Code Duplication
	            if ($timeout && $timeout < time()) {
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...
699
	                $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($path)));
700
	                break;
701
	            }
702
703
	            $raw = unserialize($raw);
704
	            if ($stat = $this->parseRaw($raw)) {
705
	                if (! isset($this->cache[$raw['path']])) {
706
	                    $stat = $this->updateCache($raw['path'], $stat);
707
	                }
708
	                if (! empty($stat['hidden']) || ($mimes && $stat['mime'] === 'directory') || ! $this->mimeAccepted($stat['mime'], $mimes)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $mimes 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...
709
	                    continue;
710
	                }
711
	                $stat = $this->stat($raw['path']);
712
	                $stat['path'] = $this->path($stat['hash']);
713
	                $result[] = $stat;
714
	            }
715
	        }
716
	    }
717
718
	    return $result;
719
	}
720
721
	/**
722
	 * Copy file/recursive copy dir only in current volume.
723
	 * Return new file path or false.
724
	 *
725
	 * @param  string  $src   source path
726
	 * @param  string  $dst   destination dir path
727
	 * @param  string  $name  new file name (optionaly)
728
	 * @return string|false
729
	 * @author Dmitry (dio) Levashov
730
	 * @author Naoki Sawada
731
	 **/
732
	protected function copy($src, $dst, $name)
733
	{
734
	    $this->clearcache();
735
736
	    return $this->_copy($src, $dst, $name)
737
		? $this->_joinPath($dst, $name)
738
		: $this->setError(elFinder::ERROR_COPY, $this->_path($src));
739
	}
740
741
	/**
742
	 * Remove file/ recursive remove dir.
743
	 *
744
	 * @param  string $path file path
745
	 * @param  bool $force try to remove even if file locked
746
	 * @param bool $recursive
747
	 * @return bool
748
	 * @author Dmitry (dio) Levashov
749
	 * @author Naoki Sawada
750
	 */
751 View Code Duplication
	protected function remove($path, $force = false, $recursive = 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...
752
	{
753
	    $stat = $this->stat($path);
754
	    $stat['realpath'] = $path;
755
	    $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...
756
	    $this->clearcache();
757
758
	    if (empty($stat)) {
759
	        return $this->setError(elFinder::ERROR_RM, $this->_path($path), elFinder::ERROR_FILE_NOT_FOUND);
760
	    }
761
762
	    if (! $force && ! empty($stat['locked'])) {
763
	        return $this->setError(elFinder::ERROR_LOCKED, $this->_path($path));
764
	    }
765
766
	    if ($stat['mime'] == 'directory') {
767
	        if (! $recursive && ! $this->_rmdir($path)) {
768
	            return $this->setError(elFinder::ERROR_RM, $this->_path($path));
769
	        }
770
	    } else {
771
	        if (! $recursive && ! $this->_unlink($path)) {
772
	            return $this->setError(elFinder::ERROR_RM, $this->_path($path));
773
	        }
774
	    }
775
776
	    $this->removed[] = $stat;
777
778
	    return true;
779
	}
780
781
	/**
782
	 * Create thumnbnail and return it's URL on success.
783
	 *
784
	 * @param  string $path file path
785
	 * @param $stat
786
	 * @return false|string
787
	 * @internal param string $mime file mime type
788
	 * @author Dmitry (dio) Levashov
789
	 * @author Naoki Sawada
790
	 */
791 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...
792
	{
793
	    if (! $stat || ! $this->canCreateTmb($path, $stat)) {
794
	        return false;
795
	    }
796
797
	    $name = $this->tmbname($stat);
798
	    $tmb = $this->tmbPath.DIRECTORY_SEPARATOR.$name;
799
800
		// copy image into tmbPath so some drivers does not store files on local fs
801
		if (! $data = $this->getThumbnail($path, $this->options['getTmbSize'])) {
802
		    return false;
803
		}
804
	    if (! file_put_contents($tmb, $data)) {
805
	        return false;
806
	    }
807
808
	    $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...
809
810
	    $tmbSize = $this->tmbSize;
811
812
	    if (($s = getimagesize($tmb)) == false) {
813
	        return false;
814
	    }
815
816
		/* If image smaller or equal thumbnail size - just fitting to thumbnail square */
817
		if ($s[0] <= $tmbSize && $s[1] <= $tmbSize) {
818
		    $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png');
819
		} else {
820
		    if ($this->options['tmbCrop']) {
821
822
				/* Resize and crop if image bigger than thumbnail */
823
				if (! (($s[0] > $tmbSize && $s[1] <= $tmbSize) || ($s[0] <= $tmbSize && $s[1] > $tmbSize)) || ($s[0] > $tmbSize && $s[1] > $tmbSize)) {
824
				    $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...
825
				}
826
827
		        if (($s = getimagesize($tmb)) != false) {
828
		            $x = $s[0] > $tmbSize ? intval(($s[0] - $tmbSize) / 2) : 0;
829
		            $y = $s[1] > $tmbSize ? intval(($s[1] - $tmbSize) / 2) : 0;
830
		            $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...
831
		        }
832
		    } else {
833
		        $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...
834
		    }
835
836
		    $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png');
837
		}
838
839
	    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...
840
	        unlink($tmb);
841
842
	        return false;
843
	    }
844
845
	    return $name;
846
	}
847
848
	/**
849
	 * Return thumbnail file name for required file.
850
	 *
851
	 * @param  array  $stat  file stat
852
	 * @return string
853
	 * @author Dmitry (dio) Levashov
854
	 **/
855
	protected function tmbname($stat)
856
	{
857
	    return $this->tmbPrefix.$stat['rev'].'.png';
858
	}
859
860
	/**
861
	 * Get thumbnail from dropbox.com.
862
	 * @param string $path
863
	 * @param string $size
864
	 * @return string | boolean
865
	 */
866
	protected function getThumbnail($path, $size = 'small')
867
	{
868
	    try {
869
	        return $this->dropbox->getThumbnail($path, $size);
870
	    } catch (Dropbox_Exception $e) {
0 ignored issues
show
Bug introduced by
The class Dropbox_Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
871
	        return false;
872
	    }
873
	}
874
875
	/*********************** paths/urls *************************/
876
877
	/**
878
	 * Return parent directory path.
879
	 *
880
	 * @param  string  $path  file path
881
	 * @return string
882
	 * @author Dmitry (dio) Levashov
883
	 **/
884
	protected function _dirname($path)
885
	{
886
	    return $this->_normpath(substr($path, 0, strrpos($path, '/')));
887
	}
888
889
	/**
890
	 * Return file name.
891
	 *
892
	 * @param  string  $path  file path
893
	 * @return string
894
	 * @author Dmitry (dio) Levashov
895
	 **/
896
	protected function _basename($path)
897
	{
898
	    return substr($path, strrpos($path, '/') + 1);
899
	}
900
901
	/**
902
	 * Join dir name and file name and retur full path.
903
	 *
904
	 * @param  string  $dir
905
	 * @param  string  $name
906
	 * @return string
907
	 * @author Dmitry (dio) Levashov
908
	 **/
909
	protected function _joinPath($dir, $name)
910
	{
911
	    return $this->_normpath($dir.'/'.$name);
912
	}
913
914
	/**
915
	 * Return normalized path, this works the same as os.path.normpath() in Python.
916
	 *
917
	 * @param  string  $path  path
918
	 * @return string
919
	 * @author Troex Nevelin
920
	 **/
921
	protected function _normpath($path)
922
	{
923
	    $path = '/'.ltrim($path, '/');
924
925
	    return $path;
926
	}
927
928
	/**
929
	 * Return file path related to root dir.
930
	 *
931
	 * @param  string  $path  file path
932
	 * @return string
933
	 * @author Dmitry (dio) Levashov
934
	 **/
935
	protected function _relpath($path)
936
	{
937
	    return $path;
938
	}
939
940
	/**
941
	 * Convert path related to root dir into real path.
942
	 *
943
	 * @param  string  $path  file path
944
	 * @return string
945
	 * @author Dmitry (dio) Levashov
946
	 **/
947
	protected function _abspath($path)
948
	{
949
	    return $path;
950
	}
951
952
	/**
953
	 * Return fake path started from root dir.
954
	 *
955
	 * @param  string  $path  file path
956
	 * @return string
957
	 * @author Dmitry (dio) Levashov
958
	 **/
959
	protected function _path($path)
960
	{
961
	    return $this->rootName.$this->_normpath(substr($path, strlen($this->root)));
962
	}
963
964
	/**
965
	 * Return true if $path is children of $parent.
966
	 *
967
	 * @param  string  $path    path to check
968
	 * @param  string  $parent  parent path
969
	 * @return bool
970
	 * @author Dmitry (dio) Levashov
971
	 **/
972
	protected function _inpath($path, $parent)
973
	{
974
	    return $path == $parent || strpos($path, $parent.'/') === 0;
975
	}
976
977
	/***************** file stat ********************/
978
979
	/**
980
	 * Return stat for given path.
981
	 * Stat contains following fields:
982
	 * - (int)    size    file size in b. required
983
	 * - (int)    ts      file modification time in unix time. required
984
	 * - (string) mime    mimetype. required for folders, others - optionally
985
	 * - (bool)   read    read permissions. required
986
	 * - (bool)   write   write permissions. required
987
	 * - (bool)   locked  is object locked. optionally
988
	 * - (bool)   hidden  is object hidden. optionally
989
	 * - (string) alias   for symlinks - link target path relative to root path. optionally
990
	 * - (string) target  for symlinks - link target path. optionally.
991
	 *
992
	 * If file does not exists - returns empty array or false.
993
	 *
994
	 * @param  string  $path    file path
995
	 * @return array|false
996
	 * @author Dmitry (dio) Levashov
997
	 **/
998
	protected function _stat($path)
999
	{
1000
	    //if (!empty($this->ARGS['reload']) && isset($this->ARGS['target']) && strpos($this->ARGS['target'], $this->id) === 0) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% 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...
1001
		if ($this->isMyReload()) {
1002
		    $this->deltaCheck();
1003
		}
1004
	    if ($raw = $this->getDBdat($path)) {
1005
	        return $this->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...
1006
	    }
1007
1008
	    return false;
1009
	}
1010
1011
	/**
1012
	 * Return true if path is dir and has at least one childs directory.
1013
	 *
1014
	 * @param  string  $path  dir path
1015
	 * @return bool
1016
	 * @author Dmitry (dio) Levashov
1017
	 **/
1018
	protected function _subdirs($path)
1019
	{
1020
	    return ($stat = $this->stat($path)) && isset($stat['dirs']) ? $stat['dirs'] : false;
1021
	}
1022
1023
	/**
1024
	 * Return object width and height
1025
	 * Ususaly used for images, but can be realize for video etc...
1026
	 *
1027
	 * @param  string  $path  file path
1028
	 * @param  string  $mime  file mime type
1029
	 * @return string
1030
	 * @author Dmitry (dio) Levashov
1031
	 **/
1032
	protected function _dimensions($path, $mime)
1033
	{
1034
	    if (strpos($mime, 'image') !== 0) {
1035
	        return '';
1036
	    }
1037
	    $cache = $this->getDBdat($path);
1038 View Code Duplication
	    if (isset($cache['width']) && isset($cache['height'])) {
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...
1039
	        return $cache['width'].'x'.$cache['height'];
1040
	    }
1041
	    $ret = '';
1042
	    if ($work = $this->getWorkFile($path)) {
1043 View Code Duplication
	        if ($size = getimagesize($work)) {
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...
1044
	            $cache['width'] = $size[0];
1045
	            $cache['height'] = $size[1];
1046
	            $this->updateDBdat($path, $cache);
1047
	            $ret = $size[0].'x'.$size[1];
1048
	        }
1049
	    }
1050
	    is_file($work) && unlink($work);
1051
1052
	    return $ret;
1053
	}
1054
1055
	/******************** file/dir content *********************/
1056
1057
	/**
1058
	 * Return files list in directory.
1059
	 *
1060
	 * @param  string  $path  dir path
1061
	 * @return array
1062
	 * @author Dmitry (dio) Levashov
1063
	 * @author Cem (DiscoFever)
1064
	 **/
1065
	protected function _scandir($path)
1066
	{
1067
	    return isset($this->dirsCache[$path])
1068
			? $this->dirsCache[$path]
1069
			: $this->cacheDir($path);
1070
	}
1071
1072
	/**
1073
	 * Open file and return file pointer.
1074
	 *
1075
	 * @param  string $path file path
1076
	 * @param string $mode
1077
	 * @return false|resource
1078
	 * @internal param bool $write open file for writing
1079
	 * @author Dmitry (dio) Levashov
1080
	 */
1081
	protected function _fopen($path, $mode = 'rb')
1082
	{
1083
	    if (($mode == 'rb' || $mode == 'r')) {
1084
	        try {
1085
	            $res = $this->dropbox->media($path);
1086
	            $url = parse_url($res['url']);
1087
	            $fp = stream_socket_client('ssl://'.$url['host'].':443');
1088
	            fwrite($fp, "GET {$url['path']} HTTP/1.0\r\n");
1089
	            fwrite($fp, "Host: {$url['host']}\r\n");
1090
	            fwrite($fp, "\r\n");
1091
	            while (trim(fgets($fp)) !== '') {
0 ignored issues
show
Unused Code introduced by
This while loop is empty and can be removed.

This check looks for while loops that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

Consider removing the loop.

Loading history...
1092
	            }
1093
1094
	            return $fp;
1095
	        } catch (Dropbox_Exception $e) {
0 ignored issues
show
Bug introduced by
The class Dropbox_Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
1096
	            return false;
1097
	        }
1098
	    }
1099
1100
	    if ($this->tmp) {
1101
	        $contents = $this->_getContents($path);
1102
1103
	        if ($contents === false) {
1104
	            return false;
1105
	        }
1106
1107
	        if ($local = $this->getTempFile($path)) {
1108
	            if (file_put_contents($local, $contents, LOCK_EX) !== false) {
1109
	                return fopen($local, $mode);
1110
	            }
1111
	        }
1112
	    }
1113
1114
	    return false;
1115
	}
1116
1117
	/**
1118
	 * Close opened file.
1119
	 *
1120
	 * @param  resource $fp file pointer
1121
	 * @param string $path
1122
	 * @return bool
1123
	 * @author Dmitry (dio) Levashov
1124
	 */
1125
	protected function _fclose($fp, $path = '')
1126
	{
1127
	    fclose($fp);
1128
	    if ($path) {
1129
	        unlink($this->getTempFile($path));
1130
	    }
1131
	}
1132
1133
	/********************  file/dir manipulations *************************/
1134
1135
	/**
1136
	 * Create dir and return created dir path or false on failed.
1137
	 *
1138
	 * @param  string  $path  parent dir path
1139
	 * @param string  $name  new directory name
1140
	 * @return string|bool
1141
	 * @author Dmitry (dio) Levashov
1142
	 **/
1143
	protected function _mkdir($path, $name)
1144
	{
1145
	    $path = $this->_normpath($path.'/'.$name);
1146
	    try {
1147
	        $this->dropbox->createFolder($path);
1148
	    } catch (Dropbox_Exception $e) {
0 ignored issues
show
Bug introduced by
The class Dropbox_Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
1149
	        $this->deltaCheck();
1150
	        if ($this->dir($this->encode($path))) {
1151
	            return $path;
1152
	        }
1153
1154
	        return $this->setError('Dropbox error: '.$e->getMessage());
1155
	    }
1156
	    $this->deltaCheck();
1157
1158
	    return $path;
1159
	}
1160
1161
	/**
1162
	 * Create file and return it's path or false on failed.
1163
	 *
1164
	 * @param  string  $path  parent dir path
1165
	 * @param string  $name  new file name
1166
	 * @return string|bool
1167
	 * @author Dmitry (dio) Levashov
1168
	 **/
1169
	protected function _mkfile($path, $name)
1170
	{
1171
	    return $this->_filePutContents($path.'/'.$name, '');
1172
	}
1173
1174
	/**
1175
	 * Create symlink. FTP driver does not support symlinks.
1176
	 *
1177
	 * @param  string $target link target
1178
	 * @param  string $path symlink path
1179
	 * @param string $name
1180
	 * @return bool
1181
	 * @author Dmitry (dio) Levashov
1182
	 */
1183
	protected function _symlink($target, $path, $name)
1184
	{
1185
	    return false;
1186
	}
1187
1188
	/**
1189
	 * Copy file into another file.
1190
	 *
1191
	 * @param  string  $source     source file path
1192
	 * @param  string  $targetDir  target directory path
1193
	 * @param  string  $name       new file name
1194
	 * @return bool
1195
	 * @author Dmitry (dio) Levashov
1196
	 **/
1197 View Code Duplication
	protected function _copy($source, $targetDir, $name)
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...
1198
	{
1199
	    $path = $this->_normpath($targetDir.'/'.$name);
1200
	    try {
1201
	        $this->dropbox->copy($source, $path);
1202
	    } catch (Dropbox_Exception $e) {
0 ignored issues
show
Bug introduced by
The class Dropbox_Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
1203
	        return $this->setError('Dropbox error: '.$e->getMessage());
1204
	    }
1205
	    $this->deltaCheck();
1206
1207
	    return true;
1208
	}
1209
1210
	/**
1211
	 * Move file into another parent dir.
1212
	 * Return new file path or false.
1213
	 *
1214
	 * @param  string $source source file path
1215
	 * @param $targetDir
1216
	 * @param  string $name file name
1217
	 * @return bool|string
1218
	 * @internal param string $target target dir path
1219
	 * @author Dmitry (dio) Levashov
1220
	 */
1221 View Code Duplication
	protected function _move($source, $targetDir, $name)
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...
1222
	{
1223
	    $target = $this->_normpath($targetDir.'/'.$name);
1224
	    try {
1225
	        $this->dropbox->move($source, $target);
1226
	    } catch (Dropbox_Exception $e) {
0 ignored issues
show
Bug introduced by
The class Dropbox_Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
1227
	        return $this->setError('Dropbox error: '.$e->getMessage());
1228
	    }
1229
	    $this->deltaCheck();
1230
1231
	    return $target;
1232
	}
1233
1234
	/**
1235
	 * Remove file.
1236
	 *
1237
	 * @param  string  $path  file path
1238
	 * @return bool
1239
	 * @author Dmitry (dio) Levashov
1240
	 **/
1241
	protected function _unlink($path)
1242
	{
1243
	    try {
1244
	        $this->dropbox->delete($path);
1245
	    } catch (Dropbox_Exception $e) {
0 ignored issues
show
Bug introduced by
The class Dropbox_Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
1246
	        return $this->setError('Dropbox error: '.$e->getMessage());
1247
	    }
1248
	    $this->deltaCheck();
1249
1250
	    return true;
1251
	}
1252
1253
	/**
1254
	 * Remove dir.
1255
	 *
1256
	 * @param  string  $path  dir path
1257
	 * @return bool
1258
	 * @author Dmitry (dio) Levashov
1259
	 **/
1260
	protected function _rmdir($path)
1261
	{
1262
	    return $this->_unlink($path);
1263
	}
1264
1265
	/**
1266
	 * Create new file and write into it from file pointer.
1267
	 * Return new file path or false on error.
1268
	 *
1269
	 * @param  resource $fp file pointer
1270
	 * @param string $path
1271
	 * @param  string $name file name
1272
	 * @param  array $stat file stat (required by some virtual fs)
1273
	 * @return bool|string
1274
	 * @internal param string $dir target dir path
1275
	 * @author Dmitry (dio) Levashov
1276
	 */
1277
	protected function _save($fp, $path, $name, $stat)
1278
	{
1279
	    if ($name) {
1280
	        $path .= '/'.$name;
1281
	    }
1282
	    $path = $this->_normpath($path);
1283
	    try {
1284
	        $this->dropbox->putFile($path, $fp);
1285
	    } catch (Dropbox_Exception $e) {
0 ignored issues
show
Bug introduced by
The class Dropbox_Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
1286
	        return $this->setError('Dropbox error: '.$e->getMessage());
1287
	    }
1288
	    $this->deltaCheck();
1289
	    if (is_array($stat)) {
1290
	        $raw = $this->getDBdat($path);
1291
	        if (isset($stat['width'])) {
1292
	            $raw['width'] = $stat['width'];
1293
	        }
1294
	        if (isset($stat['height'])) {
1295
	            $raw['height'] = $stat['height'];
1296
	        }
1297
	        $this->updateDBdat($path, $raw);
1298
	    }
1299
1300
	    return $path;
1301
	}
1302
1303
	/**
1304
	 * Get file contents.
1305
	 *
1306
	 * @param  string  $path  file path
1307
	 * @return string|false
1308
	 * @author Dmitry (dio) Levashov
1309
	 **/
1310
	protected function _getContents($path)
1311
	{
1312
	    $contents = '';
1313
	    try {
1314
	        $contents = $this->dropbox->getFile($path);
1315
	    } catch (Dropbox_Exception $e) {
0 ignored issues
show
Bug introduced by
The class Dropbox_Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
1316
	        return $this->setError('Dropbox error: '.$e->getMessage());
1317
	    }
1318
1319
	    return $contents;
1320
	}
1321
1322
	/**
1323
	 * Write a string to a file.
1324
	 *
1325
	 * @param  string  $path     file path
1326
	 * @param  string  $content  new file content
1327
	 * @return bool
1328
	 * @author Dmitry (dio) Levashov
1329
	 **/
1330 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...
1331
	{
1332
	    $res = false;
1333
1334
	    if ($local = $this->getTempFile($path)) {
1335
	        if (file_put_contents($local, $content, LOCK_EX) !== false
1336
			&& ($fp = fopen($local, 'rb'))) {
1337
	            clearstatcache();
1338
	            $res = $this->_save($fp, $path, '', []);
1339
	            fclose($fp);
1340
	        }
1341
	        file_exists($local) && unlink($local);
1342
	    }
1343
1344
	    return $res;
1345
	}
1346
1347
	/**
1348
	 * Detect available archivers.
1349
	 *
1350
	 * @return array
1351
	 **/
1352
	protected function _checkArchivers()
1353
	{
1354
	    // 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...
1355
		return [];
1356
	}
1357
1358
	/**
1359
	 * chmod implementation.
1360
	 *
1361
	 * @param string $path
1362
	 * @param string $mode
1363
	 * @return bool
1364
	 */
1365
	protected function _chmod($path, $mode)
1366
	{
1367
	    return false;
1368
	}
1369
1370
	/**
1371
	 * Unpack archive.
1372
	 *
1373
	 * @param  string  $path  archive path
1374
	 * @param  array   $arc   archiver command and arguments (same as in $this->archivers)
1375
	 * @return true
1376
	 * @return void
1377
	 * @author Dmitry (dio) Levashov
1378
	 * @author Alexey Sukhotin
1379
	 **/
1380
	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...
1381
	{
1382
	    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...
1383
	}
1384
1385
	/**
1386
	 * Recursive symlinks search.
1387
	 *
1388
	 * @param  string  $path  file/dir path
1389
	 * @return bool
1390
	 * @author Dmitry (dio) Levashov
1391
	 **/
1392
	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...
1393
	{
1394
	    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...
1395
	}
1396
1397
	/**
1398
	 * Extract files from archive.
1399
	 *
1400
	 * @param  string  $path  archive path
1401
	 * @param  array   $arc   archiver command and arguments (same as in $this->archivers)
1402
	 * @return true
1403
	 * @author Dmitry (dio) Levashov,
1404
	 * @author Alexey Sukhotin
1405
	 **/
1406
	protected function _extract($path, $arc)
1407
	{
1408
	    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...
1409
	}
1410
1411
	/**
1412
	 * Create archive and return its path.
1413
	 *
1414
	 * @param  string  $dir    target dir
1415
	 * @param  array   $files  files names list
1416
	 * @param  string  $name   archive name
1417
	 * @param  array   $arc    archiver options
1418
	 * @return string|bool
1419
	 * @author Dmitry (dio) Levashov,
1420
	 * @author Alexey Sukhotin
1421
	 **/
1422
	protected function _archive($dir, $files, $name, $arc)
1423
	{
1424
	    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...
1425
	}
1426
1427
	/**
1428
	 * Check DB for delta cache.
1429
	 *
1430
	 * @return bool
1431
	 */
1432
	private function checkDB()
0 ignored issues
show
Coding Style introduced by
checkDB uses the super-global variable $_REQUEST 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...
1433
	{
1434
	    $res = $this->query('SELECT * FROM sqlite_master WHERE type=\'table\' AND name=\''.$this->DB_TableName.'\'');
1435
	    if ($res && isset($_REQUEST['init'])) {
1436
	        // check is index(nameidx) UNIQUE?
1437
			$chk = $this->query('SELECT sql FROM sqlite_master WHERE type=\'index\' and name=\'nameidx\'');
1438
	        if (! $chk || strpos(strtoupper($chk[0]), 'UNIQUE') === false) {
1439
	            // remake
1440
				$this->DB->exec('DROP TABLE '.$this->DB_TableName);
1441
	            $res = false;
1442
	        }
1443
	    }
1444
	    if (! $res) {
1445
	        try {
1446
	            $this->DB->exec('CREATE TABLE '.$this->DB_TableName.'(path text, fname text, dat blob, isdir integer);');
1447
	            $this->DB->exec('CREATE UNIQUE INDEX nameidx ON '.$this->DB_TableName.'(path, fname)');
1448
	            $this->DB->exec('CREATE INDEX isdiridx ON '.$this->DB_TableName.'(isdir)');
1449
	        } catch (PDOException $e) {
1450
	            return $this->setError($e->getMessage());
1451
	        }
1452
	    }
1453
1454
	    return true;
1455
	}
1456
1457
	/**
1458
	 * DB query and fetchAll.
1459
	 *
1460
	 * @param string $sql
1461
	 * @return bool|array
1462
	 */
1463
	private function query($sql)
1464
	{
1465
	    if ($sth = $this->DB->query($sql)) {
1466
	        $res = $sth->fetchAll(PDO::FETCH_COLUMN);
1467
	    } else {
1468
	        $res = false;
1469
	    }
1470
1471
	    return $res;
1472
	}
1473
1474
	/**
1475
	 * Get dat(dropbox metadata) from DB.
1476
	 *
1477
	 * @param string $path
1478
	 * @return array dropbox metadata
1479
	 */
1480
	private function getDBdat($path)
1481
	{
1482
	    if ($res = $this->query('select dat from '.$this->DB_TableName.' where path='.$this->DB->quote(strtolower($this->_dirname($path))).' and fname='.$this->DB->quote(strtolower($this->_basename($path))).' limit 1')) {
1483
	        return unserialize($res[0]);
1484
	    } else {
1485
	        return [];
1486
	    }
1487
	}
1488
1489
	/**
1490
	 * Update DB dat(dropbox metadata).
1491
	 *
1492
	 * @param string $path
1493
	 * @param array $dat
1494
	 * @return bool|array
1495
	 */
1496
	private function updateDBdat($path, $dat)
1497
	{
1498
	    return $this->query('update '.$this->DB_TableName.' set dat='.$this->DB->quote(serialize($dat))
1499
				.', isdir='.($dat['is_dir'] ? 1 : 0)
1500
				.' where path='.$this->DB->quote(strtolower($this->_dirname($path))).' and fname='.$this->DB->quote(strtolower($this->_basename($path))));
1501
	}
1502
1503
	/**
1504
	 * Get HTTP request response header string.
1505
	 *
1506
	 * @param string $url target URL
1507
	 * @return string
1508
	 * @author Naoki Sawada
1509
	 */
1510
	private function getHttpResponseHeader($url)
1511
	{
1512
	    if (function_exists('curl_exec')) {
1513
	        $c = curl_init();
1514
	        curl_setopt($c, CURLOPT_RETURNTRANSFER, true);
1515
	        curl_setopt($c, CURLOPT_CUSTOMREQUEST, 'HEAD');
1516
	        curl_setopt($c, CURLOPT_HEADER, 1);
1517
	        curl_setopt($c, CURLOPT_NOBODY, true);
1518
	        curl_setopt($c, CURLOPT_URL, $url);
1519
	        $res = curl_exec($c);
1520
	    } else {
1521
	        require_once 'HTTP/Request2.php';
1522
	        try {
1523
	            $request2 = new HTTP_Request2();
1524
	            $request2->setConfig([
1525
	                'ssl_verify_peer' => false,
1526
	                'ssl_verify_host' => false,
1527
	            ]);
1528
	            $request2->setUrl($url);
1529
	            $request2->setMethod(HTTP_Request2::METHOD_HEAD);
1530
	            $result = $request2->send();
1531
	            $res = [];
1532
	            $res[] = 'HTTP/'.$result->getVersion().' '.$result->getStatus().' '.$result->getReasonPhrase();
1533
	            foreach ($result->getHeader() as $key => $val) {
1534
	                $res[] = $key.': '.$val;
1535
	            }
1536
	            $res = implode("\r\n", $res);
1537
	        } catch (HTTP_Request2_Exception $e) {
0 ignored issues
show
Bug introduced by
The class HTTP_Request2_Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
1538
	            $res = '';
1539
	        } catch (Exception $e) {
1540
	            $res = '';
1541
	        }
1542
	    }
1543
1544
	    return $res;
1545
	}
1546
} // END class
1547