Completed
Push — 2.x ( 5243ac...ccb6e2 )
by Naoki
03:52
created

elFinderVolumeDropbox::deltaCheck()   F

Complexity

Conditions 26
Paths 4790

Size

Total Lines 97
Code Lines 72

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 97
rs 2
cc 26
eloc 72
nc 4790
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
	 * Net mount key
61
	 *
62
	 * @var string
63
	 **/
64
	public $netMountKey = '';
65
	
66
	/**
67
	 * Dropbox.com uid
68
	 *
69
	 * @var string
70
	 **/
71
	protected $dropboxUid = '';
72
	
73
	/**
74
	 * Dropbox download host, replaces 'www.dropbox.com' of shares URL
75
	 * 
76
	 * @var string
77
	 */
78
	private $dropbox_dlhost = 'dl.dropboxusercontent.com';
79
	
80
	private $dropbox_phpFound = false;
81
	
82
	private $DB_TableName = '';
83
	
84
	private $tmbPrefix = '';
85
	
86
	/**
87
	 * Constructor
88
	 * Extend options with required fields
89
	 *
90
	 * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
91
	 * @author Dmitry (dio) Levashov
92
	 * @author Cem (DiscoFever)
93
	 **/
94
	public function __construct() {
95
		
96
		//ini_set('memory_limit', '128M');
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% 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...
97
		@ include_once 'Dropbox/autoload.php';
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
98
		$this->dropbox_phpFound = in_array('Dropbox_autoload', spl_autoload_functions());
99
		
100
		$opts = array(
101
			'consumerKey'       => '',
102
			'consumerSecret'    => '',
103
			'accessToken'       => '',
104
			'accessTokenSecret' => '',
105
			'dropboxUid'        => '',
106
			'root'              => 'dropbox',
107
			'path'              => '/',
108
			'separator'         => '/',
109
			'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...
110
			'PDO_User'          => '',
111
			'PDO_Pass'          => '',
112
			'PDO_Options'       => array(),
113
			'PDO_DBName'        => 'dropbox',
114
			'treeDeep'          => 0,
115
			'tmbPath'           => '../files/.tmb',
116
			'tmbURL'            => 'files/.tmb',
117
			'tmpPath'           => '',
118
			'getTmbSize'        => 'large', // small: 32x32, medium or s: 64x64, large or m: 128x128, l: 640x480, xl: 1024x768
0 ignored issues
show
Unused Code Comprehensibility introduced by
44% 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...
119
			'metaCachePath'     => '',
120
			'metaCacheTime'     => '600', // 10m
121
			'acceptedName'      => '#^[^/\\?*:|"<>]*[^./\\?*:|"<>]$#',
122
			'rootCssClass'      => 'elfinder-navbar-root-dropbox'
123
		);
124
		$this->options = array_merge($this->options, $opts);
125
		$this->options['mimeDetect'] = 'internal';
126
	}
127
128
	/**
129
	 * Prepare
130
	 * Call from elFinder::netmout() before volume->mount()
131
	 *
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 $_SESSION 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...
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
		if (empty($options['consumerKey']) && defined('ELFINDER_DROPBOX_CONSUMERKEY')) $options['consumerKey'] = ELFINDER_DROPBOX_CONSUMERKEY;
137
		if (empty($options['consumerSecret']) && defined('ELFINDER_DROPBOX_CONSUMERSECRET')) $options['consumerSecret'] = ELFINDER_DROPBOX_CONSUMERSECRET;
138
		
139
		if ($options['user'] === 'init') {
140
141
			if (! $this->dropbox_phpFound || empty($options['consumerKey']) || empty($options['consumerSecret']) || !class_exists('PDO', false)) {
142
				return array('exit' => true, 'body' => '{msg:errNetMountNoDriver}');
143
			}
144
			
145
			if (defined('ELFINDER_DROPBOX_USE_CURL_PUT')) {
146
				$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...
147
			} else {
148
				if (class_exists('OAuth', false)) {
149
					$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...
150
				} else {
151
					if (! class_exists('HTTP_OAuth_Consumer', false)) {
152
						// We're going to try to load in manually
153
						include 'HTTP/OAuth/Consumer.php';
154
					}
155
					if (class_exists('HTTP_OAuth_Consumer', false)) {
156
						$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...
157
					}
158
				}
159
			}
160
			
161
			if (! $this->oauth) {
162
				return array('exit' => true, 'body' => '{msg:errNetMountNoDriver}');
163
			}
164
165
			if ($options['pass'] === 'init') {
166
				$html = '';
167
				if (isset($_SESSION['elFinderDropboxTokens'])) {
168
					// token check
169
					try {
170
						list(, $accessToken, $accessTokenSecret) = $_SESSION['elFinderDropboxTokens'];
171
						$this->oauth->setToken($accessToken, $accessTokenSecret);
172
						$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...
173
						$this->dropbox->getAccountInfo();
174
						$script = '<script>
175
							$("#'.$options['id'].'").elfinder("instance").trigger("netmount", {protocol: "dropbox", mode: "done"});
176
						</script>';
177
						$html = $script;
178
					} 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...
179
						unset($_SESSION['elFinderDropboxTokens']);
180
					}
181
				}
182
				if (! $html) {
183
					// get customdata
184
					$cdata = '';
185
					$innerKeys = array('cmd', 'host', 'options', 'pass', 'protocol', 'user');
186
					$this->ARGS = $_SERVER['REQUEST_METHOD'] === 'POST'? $_POST : $_GET;
187
					foreach($this->ARGS as $k => $v) {
188
						if (! in_array($k, $innerKeys)) {
189
							$cdata .= '&' . $k . '=' . rawurlencode($v);
190
						}
191
					}
192
					if (strpos($options['url'], 'http') !== 0 ) {
193
						$options['url'] = $this->getConnectorUrl();
194
					}
195
					$callback  = $options['url']
196
					           . '?cmd=netmount&protocol=dropbox&host=dropbox.com&user=init&pass=return&node='.$options['id'].$cdata;
197
					
198
					try {
199
						$tokens = $this->oauth->getRequestToken();
200
						$url= $this->oauth->getAuthorizeUrl(rawurlencode($callback));
201
					} 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...
202
						return array('exit' => true, 'body' => '{msg:errAccess}');
203
					}
204
					
205
					$_SESSION['elFinderDropboxAuthTokens'] = $tokens;
206
					$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.'\')">';
207
					$html .= '<script>
208
						$("#'.$options['id'].'").elfinder("instance").trigger("netmount", {protocol: "dropbox", mode: "makebtn"});
209
					</script>';
210
				}
211
				return array('exit' => true, 'body' => $html);
212
			} else {
213
				$this->oauth->setToken($_SESSION['elFinderDropboxAuthTokens']);
214
				unset($_SESSION['elFinderDropboxAuthTokens']);
215
				$tokens = $this->oauth->getAccessToken();
216
				$_SESSION['elFinderDropboxTokens'] = array($_GET['uid'], $tokens['token'], $tokens['token_secret']);
217
				
218
				$out = array(
219
					'node' => $_GET['node'],
220
					'json' => '{"protocol": "dropbox", "mode": "done"}',
221
					'bind' => 'netmount'
222
				);
223
				
224
				return array('exit' => 'callback', 'out' => $out);
225
			}
226
		}
227
		if (isset($_SESSION['elFinderDropboxTokens'])) {
228
			list($options['dropboxUid'], $options['accessToken'], $options['accessTokenSecret']) = $_SESSION['elFinderDropboxTokens'];
229
		}
230
		unset($options['user'], $options['pass']);
231
		return $options;
232
	}
233
	
234
	/**
235
	 * process of on netunmount
236
	 * Drop table `dropbox` & rm thumbs
237
	 * 
238
	 * @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...
239
	 * @return boolean
240
	 */
241
	public function netunmount($netVolumes, $key) {
242
		$count = 0;
243
		$dropboxUid = '';
244
		if (isset($netVolumes[$key])) {
245
			$dropboxUid = $netVolumes[$key]['dropboxUid'];
246
		}
247
		foreach($netVolumes as $volume) {
248
			if (@$volume['host'] === 'dropbox' && @$volume['dropboxUid'] === $dropboxUid) {
249
				$count++;
250
			}
251
		}
252
		if ($count === 1) {
253
			$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...
254
			foreach(glob(rtrim($this->options['tmbPath'], '\\/').DIRECTORY_SEPARATOR.$this->tmbPrefix.'*.png') as $tmb) {
255
				unlink($tmb);
256
			}
257
		}
258
		return true;
259
	}
260
	
261
	/**
262
	 * Get script url
263
	 * 
264
	 * @return string full URL
265
	 * @author Naoki Sawada
266
	 */
267
	private function getConnectorUrl() {
0 ignored issues
show
Coding Style introduced by
getConnectorUrl 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...
268
		$url  = ((isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off')? 'https://' : 'http://')
269
		       . $_SERVER['SERVER_NAME']                                              // host
270
		      . ($_SERVER['SERVER_PORT'] == 80 ? '' : ':' . $_SERVER['SERVER_PORT'])  // port
271
		       . $_SERVER['REQUEST_URI'];                                             // path & query
272
		list($url) = explode('?', $url);
273
		return $url;
274
	}
275
	
276
	/*********************************************************************/
277
	/*                        INIT AND CONFIGURE                         */
278
	/*********************************************************************/
279
280
	/**
281
	 * Prepare FTP connection
282
	 * Connect to remote server and check if credentials are correct, if so, store the connection id in $ftp_conn
283
	 *
284
	 * @return bool
285
	 * @author Dmitry (dio) Levashov
286
	 * @author Cem (DiscoFever)
287
	 **/
288
	protected function init() {
0 ignored issues
show
Coding Style introduced by
init uses the super-global variable $_SESSION 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...
289
		if (!class_exists('PDO', false)) {
290
			return $this->setError('PHP PDO class is require.');
291
		}
292
		
293
		if (!$this->options['consumerKey']
294
		||  !$this->options['consumerSecret']
295
		||  !$this->options['accessToken']
296
		||  !$this->options['accessTokenSecret']) {
297
			return $this->setError('Required options undefined.');
298
		}
299
		
300
		if (empty($this->options['metaCachePath']) && defined('ELFINDER_DROPBOX_META_CACHE_PATH')) {
301
			$this->options['metaCachePath'] = ELFINDER_DROPBOX_META_CACHE_PATH;
302
		}
303
		
304
		// make net mount key
305
		$this->netMountKey = md5(join('-', array('dropbox', $this->options['path'])));
306
307
		if (! $this->oauth) {
308
			if (defined('ELFINDER_DROPBOX_USE_CURL_PUT')) {
309
				$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...
310
			} else {
311
				if (class_exists('OAuth', false)) {
312
					$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...
313
				} else {
314
					if (! class_exists('HTTP_OAuth_Consumer', false)) {
315
						// We're going to try to load in manually
316
						include 'HTTP/OAuth/Consumer.php';
317
					}
318
					if (class_exists('HTTP_OAuth_Consumer', false)) {
319
						$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...
320
					}
321
				}
322
			}
323
		}
324
		
325
		if (! $this->oauth) {
326
			return $this->setError('OAuth extension not loaded.');
327
		}
328
329
		// normalize root path
330
		$this->root = $this->options['path'] = $this->_normpath($this->options['path']);
331
332 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...
333
			$this->options['alias'] = ($this->options['path'] === '/')? 'Dropbox.com'  : 'Dropbox'.$this->options['path'];
334
		}
335
336
		$this->rootName = $this->options['alias'];
337
338
		try {
339
			$this->oauth->setToken($this->options['accessToken'], $this->options['accessTokenSecret']);
340
			$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...
341
		} 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...
342
			unset($_SESSION['elFinderDropboxTokens']);
343
			return $this->setError('Dropbox error: '.$e->getMessage());
344
		}
345
		
346
		// user
347
		if (empty($this->options['dropboxUid'])) {
348
			try {
349
				$res = $this->dropbox->getAccountInfo();
350
				$this->options['dropboxUid'] = $res['uid'];
351
			} 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...
352
				unset($_SESSION['elFinderDropboxTokens']);
353
				return $this->setError('Dropbox error: '.$e->getMessage());
354
			}
355
		}
356
		
357
		$this->dropboxUid = $this->options['dropboxUid'];
358
		$this->tmbPrefix = 'dropbox'.base_convert($this->dropboxUid, 10, 32);
359
360 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...
361
			if ((is_dir($this->options['tmpPath']) || @mkdir($this->options['tmpPath'])) && is_writable($this->options['tmpPath'])) {
362
				$this->tmp = $this->options['tmpPath'];
363
			}
364
		}
365
		if (!$this->tmp && is_writable($this->options['tmbPath'])) {
366
			$this->tmp = $this->options['tmbPath'];
367
		}
368
		
369 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...
370
			if ((is_dir($this->options['metaCachePath']) || @mkdir($this->options['metaCachePath'])) && is_writable($this->options['metaCachePath'])) {
371
				$this->metaCache = $this->options['metaCachePath'];
372
			}
373
		}
374
		if (!$this->metaCache && $this->tmp) {
375
			$this->metaCache = $this->tmp;
376
		}
377
		
378
		if (!$this->tmp) {
379
			$this->disabled[] = 'archive';
380
			$this->disabled[] = 'extract';
381
		}
382
		
383
		if (!$this->metaCache) {
384
			return $this->setError('Cache dirctory (metaCachePath or tmp) is require.');
385
		}
386
		
387
		// setup PDO
388
		if (! $this->options['PDO_DSN']) {
389
			$this->options['PDO_DSN'] = 'sqlite:'.$this->metaCache.DIRECTORY_SEPARATOR.'.elFinder_dropbox_db_'.md5($this->dropboxUid.$this->options['consumerSecret']);
390
		}
391
		// DataBase table name
392
		$this->DB_TableName = $this->options['PDO_DBName'];
393
		// DataBase check or make table
394
		try {
395
			$this->DB = new PDO($this->options['PDO_DSN'], $this->options['PDO_User'], $this->options['PDO_Pass'], $this->options['PDO_Options']);
396
			if (! $this->checkDB()) {
397
				return $this->setError('Can not make DB table');
398
			}
399
		} catch (PDOException $e) {
400
			return $this->setError('PDO connection failed: '.$e->getMessage());
401
		}
402
		
403
		$res = $this->deltaCheck($this->isMyReload());
404
		if ($res !== true) {
405
			if (is_string($res)) {
406
				return $this->setError($res);
407
			} else {
408
				return $this->setError('Could not check API "delta"');
409
			}
410
		}
411
		
412
		if (is_null($this->options['syncChkAsTs'])) {
413
			$this->options['syncChkAsTs'] = true;
414
		}
415
		if ($this->options['syncChkAsTs']) {
416
			// 'tsPlSleep' minmum 5 sec
417
			$options['tsPlSleep'] = max(5, $options['tsPlSleep']);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$options was never initialized. Although not strictly required by PHP, it is generally a good practice to add $options = 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...
Bug introduced by
The variable $options seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
418
		} else {
419
			// 'lsPlSleep' minmum 10 sec
420
			$options['lsPlSleep'] = max(10, $options['lsPlSleep']);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$options was never initialized. Although not strictly required by PHP, it is generally a good practice to add $options = 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...
Bug introduced by
The variable $options seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
421
		}
422
		
423
		return true;
424
	}
425
426
427
	/**
428
	 * Configure after successfull mount.
429
	 *
430
	 * @return void
431
	 * @author Dmitry (dio) Levashov
432
	 **/
433
	protected function configure() {
434
		parent::configure();
435
		
436
		if (!$this->tmp) {
437
			$this->disabled[] = 'archive';
438
			$this->disabled[] = 'extract';
439
		}
440
	}
441
	
442
	/**
443
	 * Check DB for delta cache
444
	 * 
445
	 * @return void
446
	 */
447
	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...
448
		$res = $this->query('SELECT * FROM sqlite_master WHERE type=\'table\' AND name=\''.$this->DB_TableName.'\'');
449
		if ($res && isset($_REQUEST['init'])) {
450
			// check is index(nameidx) UNIQUE?
451
			$chk = $this->query('SELECT sql FROM sqlite_master WHERE type=\'index\' and name=\'nameidx\'');
452
			if (!$chk || strpos(strtoupper($chk[0]), 'UNIQUE') === false) {
453
				// remake
454
				$this->DB->exec('DROP TABLE '.$this->DB_TableName);
455
				$res = false;
456
			}
457
		}
458
		if (! $res) {
459
			try {
460
				$this->DB->exec('CREATE TABLE '.$this->DB_TableName.'(path text, fname text, dat blob, isdir integer);');
461
				$this->DB->exec('CREATE UNIQUE INDEX nameidx ON '.$this->DB_TableName.'(path, fname)');
462
				$this->DB->exec('CREATE INDEX isdiridx ON '.$this->DB_TableName.'(isdir)');
463
			} catch (PDOException $e) {
464
				return $this->setError($e->getMessage());
465
			}
466
		}
467
		return true;
468
	}
469
	
470
	/**
471
	 * DB query and fetchAll
472
	 * 
473
	 * @param string $sql
474
	 * @return boolean|array
475
	 */
476
	private function query($sql) {
477
		if ($sth = $this->DB->query($sql)) {
478
			$res = $sth->fetchAll(PDO::FETCH_COLUMN);
479
		} else {
480
			$res = false;
481
		}
482
		return $res;
483
	}
484
	
485
	/**
486
	 * Get dat(dropbox metadata) from DB
487
	 * 
488
	 * @param string $path
489
	 * @return array dropbox metadata
490
	 */
491
	private function getDBdat($path) {
492
		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(basename($path))).' limit 1')) {
493
			return unserialize($res[0]);
494
		} else {
495
			return array();
496
		}
497
	}
498
	
499
	/**
500
	 * Update DB dat(dropbox metadata)
501
	 * 
502
	 * @param string $path
503
	 * @param array $dat
504
	 * @return bool|array
505
	 */
506
	private function updateDBdat($path, $dat) {
507
		return $this->query('update '.$this->DB_TableName.' set dat='.$this->DB->quote(serialize($dat))
508
				. ', isdir=' . ($dat['is_dir']? 1 : 0)
509
				. ' where path='.$this->DB->quote(strtolower($this->_dirname($path))).' and fname='.$this->DB->quote(strtolower(basename($path))));
510
	}
511
	/*********************************************************************/
512
	/*                               FS API                              */
513
	/*********************************************************************/
514
515
	/**
516
	 * Close opened connection
517
	 *
518
	 * @return void
519
	 * @author Dmitry (dio) Levashov
520
	 **/
521
	public function umount() {
522
523
	}
524
	
525
	/**
526
	 * Get delta data and DB update
527
	 * 
528
	 * @param boolean $refresh force refresh
529
	 * @return true|string error message
530
	 */
531
	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...
532
		$chk = false;
533
		if (! $refresh && $chk = $this->query('select dat from '.$this->DB_TableName.' where path=\'\' and fname=\'\' limit 1')) {
534
			$chk = unserialize($chk[0]);
535
		}
536
		if ($chk && ($chk['mtime'] + $this->options['metaCacheTime']) > $_SERVER['REQUEST_TIME']) {
537
			return true;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return true; (boolean) is incompatible with the return type documented by elFinderVolumeDropbox::deltaCheck of type true|string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
538
		}
539
		
540
		try {
541
			$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...
542
			$this->DB->beginTransaction();
543
			
544
			if ($res = $this->query('select dat from '.$this->DB_TableName.' where path=\'\' and fname=\'\' limit 1')) {
545
				$res = unserialize($res[0]);
546
				$cursor = $res['cursor'];
547
			} else {
548
				$cursor = '';
549
			}
550
			$delete = false;
551
			$reset = false;
552
			$ptimes = array();
553
			$now = time();
554
			do {
555
				@ ini_set('max_execution_time', 120);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
556
				$_info = $this->dropbox->delta($cursor);
557
				if (! empty($_info['reset'])) {
558
					$this->DB->exec('TRUNCATE table '.$this->DB_TableName);
559
					$this->DB->exec('insert into '.$this->DB_TableName.' values(\'\', \'\', \''.serialize(array('cursor' => '', 'mtime' => 0)).'\', 0);');
560
					$this->DB->exec('insert into '.$this->DB_TableName.' values(\'/\', \'\', \''.serialize(array(
561
						'path'      => '/',
562
						'is_dir'    => 1,
563
						'mime_type' => '',
564
						'bytes'     => 0
565
					)).'\', 0);');
566
					$reset = true;
567
				}
568
				$cursor = $_info['cursor'];
569
				
570
				foreach($_info['entries'] as $entry) {
571
					$key = strtolower($entry[0]);
572
					$pkey = strtolower($this->_dirname($key));
573
					
574
					$path = $this->DB->quote($pkey);
575
					$fname = $this->DB->quote(strtolower(basename($key)));
576
					$where = 'where path='.$path.' and fname='.$fname;
577
					
578
					if (empty($entry[1])) {
579
						$ptimes[$pkey] = isset($ptimes[$pkey])? max(array($now, $ptimes[$pkey])) : $now;
580
						$this->DB->exec('delete from '.$this->DB_TableName.' '.$where);
581
						! $delete && $delete = true;
582
						continue;
583
					}
584
585
					$_itemTime = strtotime(isset($entry[1]['client_mtime'])? $entry[1]['client_mtime'] : $entry[1]['modified']);
586
					$ptimes[$pkey] = isset($ptimes[$pkey])? max(array($_itemTime, $ptimes[$pkey])) : $_itemTime;
587
					$sql = 'select path from '.$this->DB_TableName.' '.$where.' limit 1';
588
					if (! $reset && $this->query($sql)) {
589
						$this->DB->exec('update '.$this->DB_TableName.' set dat='.$this->DB->quote(serialize($entry[1])).', isdir='.($entry[1]['is_dir']? 1 : 0).' ' .$where);
590
					} else {
591
						$this->DB->exec('insert into '.$this->DB_TableName.' values ('.$path.', '.$fname.', '.$this->DB->quote(serialize($entry[1])).', '.(int)$entry[1]['is_dir'].')');
592
					}
593
				}
594
			} while (! empty($_info['has_more']));
595
			
596
			// update time stamp of parent holder
597
			foreach ($ptimes as $_p => $_t) {
598
				if ($praw = $this->getDBdat($_p)) {
599
					$_update = false;
600
					if (isset($praw['client_mtime']) && $_t > strtotime($praw['client_mtime'])) {
601
						$praw['client_mtime'] = date('r', $_t);
602
						$_update = true;
603
					}
604
					if ($_t > strtotime($praw['modified'])) {
605
						$praw['modified'] = date('r', $_t);
606
						$_update = true;
607
					}
608
					if ($_update) {
609
						$pwhere = 'where path='.$this->DB->quote(strtolower($this->_dirname($_p))).' and fname='.$this->DB->quote(strtolower(basename($_p)));
610
						$this->DB->exec('update '.$this->DB_TableName.' set dat='.$this->DB->quote(serialize($praw)).' '.$pwhere);
611
					}
612
				}
613
			}
614
			
615
			$this->DB->exec('update '.$this->DB_TableName.' set dat='.$this->DB->quote(serialize(array('cursor'=>$cursor, 'mtime'=>$_SERVER['REQUEST_TIME']))).' where path=\'\' and fname=\'\'');
616
			if (! $this->DB->commit()) {
617
				$e = $this->DB->errorInfo();
618
				return $e[2];
619
			}
620
			if ($delete) {
621
				$this->DB->exec('vacuum');
622
			}
623
		} 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...
624
			return $e->getMessage();
625
		}
626
		return true;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return true; (boolean) is incompatible with the return type documented by elFinderVolumeDropbox::deltaCheck of type true|string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
627
	}
628
	
629
	/**
630
	 * Parse line from dropbox metadata output and return file stat (array)
631
	 *
632
	 * @param  string  $raw  line from ftp_rawlist() output
633
	 * @return array
634
	 * @author Dmitry Levashov
635
	 **/
636
	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...
637
		$stat = array();
638
639
		$stat['rev']   = isset($raw['rev'])? $raw['rev'] : 'root';
640
		$stat['name']  = basename($raw['path']);
641
		$stat['mime']  = $raw['is_dir']? 'directory' : $raw['mime_type'];
642
		$stat['size']  = $stat['mime'] == 'directory' ? 0 : $raw['bytes'];
643
		$stat['ts']    = isset($raw['client_mtime'])? strtotime($raw['client_mtime']) :
644
		                (isset($raw['modified'])? strtotime($raw['modified']) : $_SERVER['REQUEST_TIME']);
645
		$stat['dirs'] = 0;
646
		if ($raw['is_dir']) {
647
			$stat['dirs'] = (int)(bool)$this->query('select path from '.$this->DB_TableName.' where isdir=1 and path='.$this->DB->quote(strtolower($raw['path'])));
648
		}
649
		
650
		if (!empty($raw['url'])) {
651
			$stat['url'] = $raw['url'];
652
		} else {
653
			$stat['url'] = '1';
654
		}
655
		if (isset($raw['width'])) $stat['width'] = $raw['width'];
656
		if (isset($raw['height'])) $stat['height'] = $raw['height'];
657
		
658
		return $stat;
659
	}
660
661
	/**
662
	 * Cache dir contents
663
	 *
664
	 * @param  string  $path  dir path
665
	 * @return void
666
	 * @author Dmitry Levashov
667
	 **/
668
	protected function cacheDir($path) {
669
		$this->dirsCache[$path] = array();
670
		$res = $this->query('select dat from '.$this->DB_TableName.' where path='.$this->DB->quote(strtolower($path)));
671
		
672
		if ($res) {
673
			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...
674
				$raw = unserialize($raw);
675 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...
676
					$stat = $this->updateCache($raw['path'], $stat);
677
					if (empty($stat['hidden'])) {
678
						$this->dirsCache[$path][] = $raw['path'];
679
					}
680
				}
681
			}
682
		}
683
		return $this->dirsCache[$path];
684
	}
685
686
	/**
687
	* Recursive files search
688
	*
689
	* @param  string  $path   dir path
690
	* @param  string  $q      search string
691
	* @param  array   $mimes
692
	* @return array
693
	* @author Naoki Sawada
694
	**/
695
	protected function doSearch($path, $q, $mimes) {
696
		$result = array();
697
		$sth = $this->DB->prepare('select dat from '.$this->DB_TableName.' WHERE path LIKE ? AND fname LIKE ?');
698
		$sth->execute(array('%'.(($path === '/')? '' : strtolower($path)), '%'.strtolower($q).'%'));
699
		$res = $sth->fetchAll(PDO::FETCH_COLUMN);
700
		if ($res) {
701
			foreach($res as $raw) {
702
				$raw = unserialize($raw);
703
				if ($stat = $this->parseRaw($raw)) {
704
					if (!isset($this->cache[$raw['path']])) {
705
						$stat = $this->updateCache($raw['path'], $stat);
706
					}
707
					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...
708
						continue;
709
					}
710
					$result[] = $this->stat($raw['path']);
711
				}
712
			}
713
		}
714
		return $result;
715
	}
716
	
717
	/**
718
	* Copy file/recursive copy dir only in current volume.
719
	* Return new file path or false.
720
	*
721
	* @param  string  $src   source path
722
	* @param  string  $dst   destination dir path
723
	* @param  string  $name  new file name (optionaly)
724
	* @return string|false
725
	* @author Dmitry (dio) Levashov
726
	* @author Naoki Sawada
727
	**/
728
	protected function copy($src, $dst, $name) {
729
730
		$this->clearcache();
731
732
		return $this->_copy($src, $dst, $name)
733
		? $this->_joinPath($dst, $name)
734
		: $this->setError(elFinder::ERROR_COPY, $this->_path($src));
735
	}
736
	
737
	/**
738
	* Remove file/ recursive remove dir
739
	*
740
	* @param  string  $path   file path
741
	* @param  bool    $force  try to remove even if file locked
742
	* @return bool
743
	* @author Dmitry (dio) Levashov
744
	* @author Naoki Sawada
745
	**/
746
	protected function remove($path, $force = false, $recursive = false) {
747
		$stat = $this->stat($path);
748
		$stat['realpath'] = $path;
749
		$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...
750
		$this->clearcache();
751
	
752
		if (empty($stat)) {
753
			return $this->setError(elFinder::ERROR_RM, $this->_path($path), elFinder::ERROR_FILE_NOT_FOUND);
754
		}
755
	
756 View Code Duplication
		if (!$force && !empty($stat['locked'])) {
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...
757
			return $this->setError(elFinder::ERROR_LOCKED, $this->_path($path));
758
		}
759
	
760
		if ($stat['mime'] == 'directory') {
761 View Code Duplication
			if (!$recursive && !$this->_rmdir($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...
762
				return $this->setError(elFinder::ERROR_RM, $this->_path($path));
763
			}
764 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...
765
			if (!$recursive && !$this->_unlink($path)) {
766
				return $this->setError(elFinder::ERROR_RM, $this->_path($path));
767
			}
768
		}
769
	
770
		$this->removed[] = $stat;
771
		return true;
772
	}
773
	
774
	/**
775
	* Create thumnbnail and return it's URL on success
776
	*
777
	* @param  string  $path  file path
778
	* @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...
779
	* @return string|false
780
	* @author Dmitry (dio) Levashov
781
	* @author Naoki Sawada
782
	**/
783
	protected function createTmb($path, $stat) {
784
		if (!$stat || !$this->canCreateTmb($path, $stat)) {
785
			return false;
786
		}
787
	
788
		$name = $this->tmbname($stat);
789
		$tmb  = $this->tmbPath.DIRECTORY_SEPARATOR.$name;
790
	
791
		// copy image into tmbPath so some drivers does not store files on local fs
792
		if (! $data = $this->getThumbnail($path, $this->options['getTmbSize'])) {
793
			return false;
794
		}
795
		if (! file_put_contents($tmb, $data)) {
796
			return false;
797
		}
798
	
799
		$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...
800
	
801
		$tmbSize = $this->tmbSize;
802
	
803
		if (($s = getimagesize($tmb)) == false) {
804
			return false;
805
		}
806
	
807
		/* If image smaller or equal thumbnail size - just fitting to thumbnail square */
808
		if ($s[0] <= $tmbSize && $s[1]  <= $tmbSize) {
809
			$result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png' );
810
	
811
		} else {
812
	
813
			if ($this->options['tmbCrop']) {
814
	
815
				/* Resize and crop if image bigger than thumbnail */
816 View Code Duplication
				if (!(($s[0] > $tmbSize && $s[1] <= $tmbSize) || ($s[0] <= $tmbSize && $s[1] > $tmbSize) ) || ($s[0] > $tmbSize && $s[1] > $tmbSize)) {
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...
817
					$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...
818
				}
819
	
820 View Code Duplication
				if (($s = getimagesize($tmb)) != false) {
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...
821
					$x = $s[0] > $tmbSize ? intval(($s[0] - $tmbSize)/2) : 0;
822
					$y = $s[1] > $tmbSize ? intval(($s[1] - $tmbSize)/2) : 0;
823
					$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...
824
				}
825
	
826
			} else {
827
				$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...
828
			}
829
		
830
			$result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png' );
831
		}
832
		
833
		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...
834
			unlink($tmb);
835
			return false;
836
		}
837
	
838
		return $name;
839
	}
840
	
841
	/**
842
	 * Return thumbnail file name for required file
843
	 *
844
	 * @param  array  $stat  file stat
845
	 * @return string
846
	 * @author Dmitry (dio) Levashov
847
	 **/
848
	protected function tmbname($stat) {
849
		return $this->tmbPrefix.$stat['rev'].'.png';
850
	}
851
	
852
	/**
853
	 * Get thumbnail from dropbox.com
854
	 * @param string $path
855
	 * @param string $size
856
	 * @return string | boolean
857
	 */
858
	protected function getThumbnail($path, $size = 'small') {
859
		try {
860
			return $this->dropbox->getThumbnail($path, $size);
861
		} 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...
862
			return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by elFinderVolumeDropbox::getThumbnail of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
863
		}
864
	}
865
	
866
	/**
867
	* Return content URL
868
	*
869
	* @param string  $hash  file hash
870
	* @param array $options options
871
	* @return array
872
	* @author Naoki Sawada
873
	**/
874
	public function getContentUrl($hash, $options = array()) {
875
		if (($file = $this->file($hash)) == false || !$file['url'] || $file['url'] == 1) {
876
			$path = $this->decode($hash);
877
			$cache = $this->getDBdat($path);
878
			$url = '';
879
			if (isset($cache['share']) && strpos($cache['share'], $this->dropbox_dlhost) !== false) {
880
				$res = $this->getHttpResponseHeader($cache['share']);
881
				if (preg_match("/^HTTP\/[01\.]+ ([0-9]{3})/", $res, $match)) {
882
					if ($match[1] < 400) {
883
						$url = $cache['share'];
884
					}
885
				}
886
			}
887
			if (! $url) {
888
				try {
889
					$res = $this->dropbox->share($path, null, false);
890
					$url = $res['url'];
891
					if (strpos($url, 'www.dropbox.com') === false) {
892
						$res = $this->getHttpResponseHeader($url);
893
						if (preg_match('/^location:\s*(http[^\s]+)/im', $res, $match)) {
894
							$url = $match[1];
895
						}
896
					}
897
					list($url) = explode('?', $url);
898
					$url = str_replace('www.dropbox.com', $this->dropbox_dlhost, $url);
899
					if (! isset($cache['share']) || $cache['share'] !== $url) {
900
						$cache['share'] = $url;
901
						$this->updateDBdat($path, $cache);
902
					}
903
				} 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...
904
					return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by elFinderVolumeDropbox::getContentUrl of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
905
				}
906
			}
907
			return $url;
908
		}
909
		return $file['url'];
910
	}
911
	
912
	/**
913
	 * Get HTTP request response header string
914
	 * 
915
	 * @param string $url target URL
916
	 * @return string
917
	 * @author Naoki Sawada
918
	 */
919
	private function getHttpResponseHeader($url) {
920
		if (function_exists('curl_exec')) {
921
922
			$c = curl_init();
923
			curl_setopt( $c, CURLOPT_RETURNTRANSFER, true );
924
			curl_setopt( $c, CURLOPT_CUSTOMREQUEST, 'HEAD' );
925
			curl_setopt( $c, CURLOPT_HEADER, 1 );
926
			curl_setopt( $c, CURLOPT_NOBODY, true );
927
			curl_setopt( $c, CURLOPT_URL, $url );
928
			$res = curl_exec( $c );
929
			
930
		} else {
931
			
932
			require_once 'HTTP/Request2.php';
933
			try {
934
				$request2 = new HTTP_Request2();
935
				$request2->setConfig(array(
936
                    'ssl_verify_peer' => false,
937
                    'ssl_verify_host' => false
938
                ));
939
				$request2->setUrl($url);
940
				$request2->setMethod(HTTP_Request2::METHOD_HEAD);
941
				$result = $request2->send();
942
				$res = array();
943
				$res[] = 'HTTP/'.$result->getVersion().' '.$result->getStatus().' '.$result->getReasonPhrase();
944
				foreach($result->getHeader() as $key => $val) {
945
					$res[] = $key . ': ' . $val;
946
				}
947
				$res = join("\r\n", $res);
948
			} 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...
949
				$res = '';
950
			} catch (Exception $e){
951
				$res = '';
952
			}
953
		
954
		}
955
		return $res;
956
	}
957
	
958
	/*********************** paths/urls *************************/
959
960
	/**
961
	 * Return parent directory path
962
	 *
963
	 * @param  string  $path  file path
964
	 * @return string
965
	 * @author Dmitry (dio) Levashov
966
	 **/
967
	protected function _dirname($path) {
968
		return $this->_normpath(dirname($path));
969
	}
970
971
	/**
972
	 * Return file name
973
	 *
974
	 * @param  string  $path  file path
975
	 * @return string
976
	 * @author Dmitry (dio) Levashov
977
	 **/
978
	protected function _basename($path) {
979
		return basename($path);
980
	}
981
982
	/**
983
	 * Join dir name and file name and retur full path
984
	 *
985
	 * @param  string  $dir
986
	 * @param  string  $name
987
	 * @return string
988
	 * @author Dmitry (dio) Levashov
989
	 **/
990
	protected function _joinPath($dir, $name) {
991
		return $this->_normpath($dir.'/'.$name);
992
	}
993
994
	/**
995
	 * Return normalized path, this works the same as os.path.normpath() in Python
996
	 *
997
	 * @param  string  $path  path
998
	 * @return string
999
	 * @author Troex Nevelin
1000
	 **/
1001
	protected function _normpath($path) {
1002
		if (DIRECTORY_SEPARATOR !== '/') {
1003
			$path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
1004
		}
1005
		$path = '/' . ltrim($path, '/');
1006
		return $path;
1007
	}
1008
1009
	/**
1010
	 * Return file path related to root dir
1011
	 *
1012
	 * @param  string  $path  file path
1013
	 * @return string
1014
	 * @author Dmitry (dio) Levashov
1015
	 **/
1016
	protected function _relpath($path) {
1017
		return $path;
1018
	}
1019
1020
	/**
1021
	 * Convert path related to root dir into real path
1022
	 *
1023
	 * @param  string  $path  file path
1024
	 * @return string
1025
	 * @author Dmitry (dio) Levashov
1026
	 **/
1027
	protected function _abspath($path) {
1028
		return $path;
1029
	}
1030
1031
	/**
1032
	 * Return fake path started from root dir
1033
	 *
1034
	 * @param  string  $path  file path
1035
	 * @return string
1036
	 * @author Dmitry (dio) Levashov
1037
	 **/
1038
	protected function _path($path) {
1039
		return $path;
1040
	}
1041
1042
	/**
1043
	 * Return true if $path is children of $parent
1044
	 *
1045
	 * @param  string  $path    path to check
1046
	 * @param  string  $parent  parent path
1047
	 * @return bool
1048
	 * @author Dmitry (dio) Levashov
1049
	 **/
1050
	protected function _inpath($path, $parent) {
1051
		return $path == $parent || strpos($path, $parent.'/') === 0;
1052
	}
1053
1054
	/***************** file stat ********************/
1055
	/**
1056
	 * Return stat for given path.
1057
	 * Stat contains following fields:
1058
	 * - (int)    size    file size in b. required
1059
	 * - (int)    ts      file modification time in unix time. required
1060
	 * - (string) mime    mimetype. required for folders, others - optionally
1061
	 * - (bool)   read    read permissions. required
1062
	 * - (bool)   write   write permissions. required
1063
	 * - (bool)   locked  is object locked. optionally
1064
	 * - (bool)   hidden  is object hidden. optionally
1065
	 * - (string) alias   for symlinks - link target path relative to root path. optionally
1066
	 * - (string) target  for symlinks - link target path. optionally
1067
	 *
1068
	 * If file does not exists - returns empty array or false.
1069
	 *
1070
	 * @param  string  $path    file path
1071
	 * @return array|false
1072
	 * @author Dmitry (dio) Levashov
1073
	 **/
1074
	protected function _stat($path) {
1075
		//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...
1076
		if ($this->isMyReload()) {
1077
			$this->deltaCheck();
1078
		}
1079
		if ($raw = $this->getDBdat($path)) {
1080
			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...
1081
		}
1082
		return false;
1083
	}
1084
1085
	/**
1086
	 * Return true if path is dir and has at least one childs directory
1087
	 *
1088
	 * @param  string  $path  dir path
1089
	 * @return bool
1090
	 * @author Dmitry (dio) Levashov
1091
	 **/
1092
	protected function _subdirs($path) {
1093
		return ($stat = $this->stat($path)) && isset($stat['dirs']) ? $stat['dirs'] : false;
1094
	}
1095
1096
	/**
1097
	 * Return object width and height
1098
	 * Ususaly used for images, but can be realize for video etc...
1099
	 *
1100
	 * @param  string  $path  file path
1101
	 * @param  string  $mime  file mime type
1102
	 * @return string
1103
	 * @author Dmitry (dio) Levashov
1104
	 **/
1105
	protected function _dimensions($path, $mime) {
1106
		if (strpos($mime, 'image') !== 0) return '';
1107
		$cache = $this->getDBdat($path);
1108
		if (isset($cache['width']) && isset($cache['height'])) {
1109
			return $cache['width'].'x'.$cache['height'];
1110
		}
1111
		$ret = '';
1112
		if ($work = $this->getWorkFile($path)) {
1113
			if ($size = @getimagesize($work)) {
1114
				$cache['width'] = $size[0];
1115
				$cache['height'] = $size[1];
1116
				$this->updateDBdat($path, $cache);
1117
				$ret = $size[0].'x'.$size[1];
1118
			}
1119
		}
1120
		is_file($work) && @unlink($work);
1121
		return $ret;
1122
	}
1123
1124
	/******************** file/dir content *********************/
1125
1126
	/**
1127
	 * Return files list in directory.
1128
	 *
1129
	 * @param  string  $path  dir path
1130
	 * @return array
1131
	 * @author Dmitry (dio) Levashov
1132
	 * @author Cem (DiscoFever)
1133
	 **/
1134
	protected function _scandir($path) {
1135
		return isset($this->dirsCache[$path])
1136
			? $this->dirsCache[$path]
1137
			: $this->cacheDir($path);
1138
	}
1139
1140
	/**
1141
	 * Open file and return file pointer
1142
	 *
1143
	 * @param  string  $path  file path
1144
	 * @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...
1145
	 * @return resource|false
1146
	 * @author Dmitry (dio) Levashov
1147
	 **/
1148
	protected function _fopen($path, $mode='rb') {
1149
1150
		if (($mode == 'rb' || $mode == 'r')) {
1151
			try {
1152
				$res = $this->dropbox->media($path);
1153
				$url = parse_url($res['url']);
1154
 				$fp = stream_socket_client('ssl://'.$url['host'].':443');
1155
 				fputs($fp, "GET {$url['path']} HTTP/1.0\r\n");
1156
 				fputs($fp, "Host: {$url['host']}\r\n");
1157
 				fputs($fp, "\r\n");
1158
 				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...
1159
 				return $fp;
1160
			} 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...
1161
				return false;
1162
			}
1163
		}
1164
		
1165
		if ($this->tmp) {
1166
			$contents = $this->_getContents($path);
1167
			
1168
			if ($contents === false) {
1169
				return false;
1170
			}
1171
			
1172
			if ($local = $this->getTempFile($path)) {
1173
				if (file_put_contents($local, $contents, LOCK_EX) !== false) {
1174
					return @fopen($local, $mode);
1175
				}
1176
			}
1177
		}
1178
1179
		return false;
1180
	}
1181
1182
	/**
1183
	 * Close opened file
1184
	 *
1185
	 * @param  resource  $fp  file pointer
1186
	 * @return bool
1187
	 * @author Dmitry (dio) Levashov
1188
	 **/
1189
	protected function _fclose($fp, $path='') {
1190
		@fclose($fp);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1191
		if ($path) {
1192
			@unlink($this->getTempFile($path));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1193
		}
1194
	}
1195
1196
	/********************  file/dir manipulations *************************/
1197
1198
	/**
1199
	 * Create dir and return created dir path or false on failed
1200
	 *
1201
	 * @param  string  $path  parent dir path
1202
	 * @param string  $name  new directory name
1203
	 * @return string|bool
1204
	 * @author Dmitry (dio) Levashov
1205
	 **/
1206
	protected function _mkdir($path, $name) {
1207
		$path = $this->_normpath($path.'/'.$name);
1208
		try {
1209
			$this->dropbox->createFolder($path);
1210
		} 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...
1211
			$this->deltaCheck();
1212
			if ($this->dir($this->encode($path))) {
1213
				return $path;
1214
			}
1215
			return $this->setError('Dropbox error: '.$e->getMessage());
1216
		}
1217
		$this->deltaCheck();
1218
		return $path;
1219
	}
1220
1221
	/**
1222
	 * Create file and return it's path or false on failed
1223
	 *
1224
	 * @param  string  $path  parent dir path
1225
	 * @param string  $name  new file name
1226
	 * @return string|bool
1227
	 * @author Dmitry (dio) Levashov
1228
	 **/
1229
	protected function _mkfile($path, $name) {
1230
		return $this->_filePutContents($path.'/'.$name, '');
1231
	}
1232
1233
	/**
1234
	 * Create symlink. FTP driver does not support symlinks.
1235
	 *
1236
	 * @param  string  $target  link target
1237
	 * @param  string  $path    symlink path
1238
	 * @return bool
1239
	 * @author Dmitry (dio) Levashov
1240
	 **/
1241
	protected function _symlink($target, $path, $name) {
1242
		return false;
1243
	}
1244
1245
	/**
1246
	 * Copy file into another file
1247
	 *
1248
	 * @param  string  $source     source file path
1249
	 * @param  string  $targetDir  target directory path
1250
	 * @param  string  $name       new file name
1251
	 * @return bool
1252
	 * @author Dmitry (dio) Levashov
1253
	 **/
1254 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...
1255
		$path = $this->_normpath($targetDir.'/'.$name);
1256
		try {
1257
			$this->dropbox->copy($source, $path);
1258
		} 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...
1259
			return $this->setError('Dropbox error: '.$e->getMessage());
1260
		}
1261
		$this->deltaCheck();
1262
		return true;
1263
	}
1264
1265
	/**
1266
	 * Move file into another parent dir.
1267
	 * Return new file path or false.
1268
	 *
1269
	 * @param  string  $source  source file path
1270
	 * @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...
1271
	 * @param  string  $name    file name
1272
	 * @return string|bool
1273
	 * @author Dmitry (dio) Levashov
1274
	 **/
1275 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...
1276
		$target = $this->_normpath($targetDir.'/'.$name);
1277
		try {
1278
			$this->dropbox->move($source, $target);
1279
		} 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...
1280
			return $this->setError('Dropbox error: '.$e->getMessage());
1281
		}
1282
		$this->deltaCheck();
1283
		return $target;
1284
	}
1285
1286
	/**
1287
	 * Remove file
1288
	 *
1289
	 * @param  string  $path  file path
1290
	 * @return bool
1291
	 * @author Dmitry (dio) Levashov
1292
	 **/
1293
	protected function _unlink($path) {
1294
		try {
1295
			$this->dropbox->delete($path);
1296
		} 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...
1297
			return $this->setError('Dropbox error: '.$e->getMessage());
1298
		}
1299
		$this->deltaCheck();
1300
		return true;
1301
	}
1302
1303
	/**
1304
	 * Remove dir
1305
	 *
1306
	 * @param  string  $path  dir path
1307
	 * @return bool
1308
	 * @author Dmitry (dio) Levashov
1309
	 **/
1310
	protected function _rmdir($path) {
1311
		return $this->_unlink($path);
1312
	}
1313
1314
	/**
1315
	 * Create new file and write into it from file pointer.
1316
	 * Return new file path or false on error.
1317
	 *
1318
	 * @param  resource  $fp   file pointer
1319
	 * @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...
1320
	 * @param  string    $name file name
1321
	 * @param  array     $stat file stat (required by some virtual fs)
1322
	 * @return bool|string
1323
	 * @author Dmitry (dio) Levashov
1324
	 **/
1325
	protected function _save($fp, $path, $name, $stat) {
1326
		if ($name) $path .= '/'.$name;
1327
		$path = $this->_normpath($path);
1328
		try {
1329
			$this->dropbox->putFile($path, $fp);
1330
		} 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...
1331
			return $this->setError('Dropbox error: '.$e->getMessage());
1332
		}
1333
		$this->deltaCheck();
1334
		if (is_array($stat)) {
1335
			$raw = $this->getDBdat($path);
1336
			if (isset($stat['width'])) $raw['width'] = $stat['width'];
1337
			if (isset($stat['height'])) $raw['height'] = $stat['height'];
1338
			$this->updateDBdat($path, $raw);
1339
		}
1340
		return $path;
1341
	}
1342
1343
	/**
1344
	 * Get file contents
1345
	 *
1346
	 * @param  string  $path  file path
1347
	 * @return string|false
1348
	 * @author Dmitry (dio) Levashov
1349
	 **/
1350
	protected function _getContents($path) {
1351
		$contents = '';
1352
		try {
1353
			$contents = $this->dropbox->getFile($path);
1354
		} 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...
1355
			return $this->setError('Dropbox error: '.$e->getMessage());
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->setError('... ' . $e->getMessage()); (boolean) is incompatible with the return type declared by the abstract method elFinderVolumeDriver::_getContents of type string|false.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
1356
		}
1357
		return $contents;
1358
	}
1359
1360
	/**
1361
	 * Write a string to a file
1362
	 *
1363
	 * @param  string  $path     file path
1364
	 * @param  string  $content  new file content
1365
	 * @return bool
1366
	 * @author Dmitry (dio) Levashov
1367
	 **/
1368
	protected function _filePutContents($path, $content) {
1369
		$res = false;
1370
1371
		if ($local = $this->getTempFile($path)) {
1372 View Code Duplication
			if (@file_put_contents($local, $content, LOCK_EX) !== false
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...
1373
			&& ($fp = @fopen($local, 'rb'))) {
1374
				clearstatcache();
1375
				$res = $this->_save($fp, $path, '', array());
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->_save($fp, $path, '', array()); of type boolean|string adds the type string to the return on line 1381 which is incompatible with the return type declared by the abstract method elFinderVolumeDriver::_filePutContents of type boolean.
Loading history...
1376
				@fclose($fp);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1377
			}
1378
			file_exists($local) && @unlink($local);
1379
		}
1380
1381
		return $res;
1382
	}
1383
1384
	/**
1385
	 * Detect available archivers
1386
	 *
1387
	 * @return void
1388
	 **/
1389
	protected function _checkArchivers() {
1390
		// 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...
1391
		return array();
1392
	}
1393
1394
	/**
1395
	 * chmod implementation
1396
	 *
1397
	 * @return bool
1398
	 **/
1399
	protected function _chmod($path, $mode) {
1400
		return false;
1401
	}
1402
1403
	/**
1404
	 * Unpack archive
1405
	 *
1406
	 * @param  string  $path  archive path
1407
	 * @param  array   $arc   archiver command and arguments (same as in $this->archivers)
1408
	 * @return true
1409
	 * @return void
1410
	 * @author Dmitry (dio) Levashov
1411
	 * @author Alexey Sukhotin
1412
	 **/
1413
	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...
1414
		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...
1415
		return false;
0 ignored issues
show
Unused Code introduced by
return false; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
1416
	}
1417
1418
	/**
1419
	 * Recursive symlinks search
1420
	 *
1421
	 * @param  string  $path  file/dir path
1422
	 * @return bool
1423
	 * @author Dmitry (dio) Levashov
1424
	 **/
1425
	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...
1426
		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...
1427
		if (is_link($path)) {
0 ignored issues
show
Unused Code introduced by
if (is_link($path)) { return true; } does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
Bug introduced by
The variable $path seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
1428
			return true;
1429
		}
1430
		if (is_dir($path)) {
0 ignored issues
show
Bug introduced by
The variable $path seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
1431 View Code Duplication
			foreach (scandir($path) as $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...
1432
				if ($name != '.' && $name != '..') {
1433
					$p = $path.DIRECTORY_SEPARATOR.$name;
1434
					if (is_link($p)) {
0 ignored issues
show
Bug introduced by
The variable $p seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
1435
						return true;
1436
					}
1437
					if (is_dir($p) && $this->_findSymlinks($p)) {
0 ignored issues
show
Bug introduced by
The variable $p seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
Bug introduced by
The variable $this seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
1438
						return true;
1439
					} elseif (is_file($p)) {
0 ignored issues
show
Bug introduced by
The variable $p seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
1440
						$this->archiveSize += filesize($p);
0 ignored issues
show
Bug introduced by
The property archiveSize 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...
1441
					}
1442
				}
1443
			}
1444
		} else {
1445
			$this->archiveSize += filesize($path);
1446
		}
1447
1448
		return false;
1449
	}
1450
1451
	/**
1452
	 * Extract files from archive
1453
	 *
1454
	 * @param  string  $path  archive path
1455
	 * @param  array   $arc   archiver command and arguments (same as in $this->archivers)
1456
	 * @return true
1457
	 * @author Dmitry (dio) Levashov,
1458
	 * @author Alexey Sukhotin
1459
	 **/
1460
	protected function _extract($path, $arc) {
1461
		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...
1462
1463
	}
1464
1465
	/**
1466
	 * Create archive and return its path
1467
	 *
1468
	 * @param  string  $dir    target dir
1469
	 * @param  array   $files  files names list
1470
	 * @param  string  $name   archive name
1471
	 * @param  array   $arc    archiver options
1472
	 * @return string|bool
1473
	 * @author Dmitry (dio) Levashov,
1474
	 * @author Alexey Sukhotin
1475
	 **/
1476
	protected function _archive($dir, $files, $name, $arc) {
1477
		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...
1478
		return false;
0 ignored issues
show
Unused Code introduced by
return false; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
1479
	}
1480
1481
} // END class
1482