Issues (661)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

php/elFinderVolumeDropbox.class.php (102 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
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...
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...
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...
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
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
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
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
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
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
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
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
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
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
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
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 View Code Duplication
		if ($this->options['syncChkAsTs']) {
0 ignored issues
show
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...
416
			// 'tsPlSleep' minmum 5 sec
417
			$this->options['tsPlSleep'] = max(5, $this->options['tsPlSleep']);
418
		} else {
419
			// 'lsPlSleep' minmum 10 sec
420
			$this->options['lsPlSleep'] = max(10, $this->options['lsPlSleep']);
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
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
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
$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
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
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
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
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']) && $path !== $raw['path']) {
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
		$timeout = $this->options['searchTimeout']? $this->searchStart + $this->options['searchTimeout'] : 0;
701
		
702
		if ($res) {
703
			foreach($res as $raw) {
704 View Code Duplication
				if ($timeout && $timeout < time()) {
0 ignored issues
show
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...
705
					$this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($path)));
706
					break;
707
				}
708
				
709
				$raw = unserialize($raw);
710
				if ($stat = $this->parseRaw($raw)) {
711
					if (!isset($this->cache[$raw['path']])) {
712
						$stat = $this->updateCache($raw['path'], $stat);
713
					}
714
					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...
715
						continue;
716
					}
717
					$stat = $this->stat($raw['path']);
718
					$stat['path'] = $this->path($stat['hash']);
719
					$result[] = $stat;
720
				}
721
			}
722
		}
723
		return $result;
724
	}
725
	
726
	/**
727
	* Copy file/recursive copy dir only in current volume.
728
	* Return new file path or false.
729
	*
730
	* @param  string  $src   source path
731
	* @param  string  $dst   destination dir path
732
	* @param  string  $name  new file name (optionaly)
733
	* @return string|false
734
	* @author Dmitry (dio) Levashov
735
	* @author Naoki Sawada
736
	**/
737
	protected function copy($src, $dst, $name) {
738
739
		$this->clearcache();
740
741
		return $this->_copy($src, $dst, $name)
742
		? $this->_joinPath($dst, $name)
743
		: $this->setError(elFinder::ERROR_COPY, $this->_path($src));
744
	}
745
	
746
	/**
747
	* Remove file/ recursive remove dir
748
	*
749
	* @param  string  $path   file path
750
	* @param  bool    $force  try to remove even if file locked
751
	* @return bool
752
	* @author Dmitry (dio) Levashov
753
	* @author Naoki Sawada
754
	**/
755
	protected function remove($path, $force = false, $recursive = false) {
756
		$stat = $this->stat($path);
757
		$stat['realpath'] = $path;
758
		$this->rmTmb($stat);
0 ignored issues
show
$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...
759
		$this->clearcache();
760
	
761
		if (empty($stat)) {
762
			return $this->setError(elFinder::ERROR_RM, $this->_path($path), elFinder::ERROR_FILE_NOT_FOUND);
763
		}
764
	
765 View Code Duplication
		if (!$force && !empty($stat['locked'])) {
0 ignored issues
show
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...
766
			return $this->setError(elFinder::ERROR_LOCKED, $this->_path($path));
767
		}
768
	
769
		if ($stat['mime'] == 'directory') {
770 View Code Duplication
			if (!$recursive && !$this->_rmdir($path)) {
0 ignored issues
show
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...
771
				return $this->setError(elFinder::ERROR_RM, $this->_path($path));
772
			}
773 View Code Duplication
		} else {
0 ignored issues
show
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...
774
			if (!$recursive && !$this->_unlink($path)) {
775
				return $this->setError(elFinder::ERROR_RM, $this->_path($path));
776
			}
777
		}
778
	
779
		$this->removed[] = $stat;
780
		return true;
781
	}
782
	
783
	/**
784
	* Create thumnbnail and return it's URL on success
785
	*
786
	* @param  string  $path  file path
787
	* @param  string  $mime  file mime type
0 ignored issues
show
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...
788
	* @return string|false
789
	* @author Dmitry (dio) Levashov
790
	* @author Naoki Sawada
791
	**/
792
	protected function createTmb($path, $stat) {
793
		if (!$stat || !$this->canCreateTmb($path, $stat)) {
794
			return false;
795
		}
796
	
797
		$name = $this->tmbname($stat);
798
		$tmb  = $this->tmbPath.DIRECTORY_SEPARATOR.$name;
799
	
800
		// copy image into tmbPath so some drivers does not store files on local fs
801
		if (! $data = $this->getThumbnail($path, $this->options['getTmbSize'])) {
802
			return false;
803
		}
804
		if (! file_put_contents($tmb, $data)) {
805
			return false;
806
		}
807
	
808
		$result = false;
0 ignored issues
show
$result is not used, you could remove the assignment.

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

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

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

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

Loading history...
809
	
810
		$tmbSize = $this->tmbSize;
811
	
812
		if (($s = getimagesize($tmb)) == false) {
813
			return false;
814
		}
815
	
816
		/* If image smaller or equal thumbnail size - just fitting to thumbnail square */
817
		if ($s[0] <= $tmbSize && $s[1]  <= $tmbSize) {
818
			$result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png' );
819
	
820
		} else {
821
	
822
			if ($this->options['tmbCrop']) {
823
	
824
				/* Resize and crop if image bigger than thumbnail */
825 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
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...
826
					$result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, false, 'png');
0 ignored issues
show
$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...
827
				}
828
	
829 View Code Duplication
				if (($s = getimagesize($tmb)) != false) {
0 ignored issues
show
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...
830
					$x = $s[0] > $tmbSize ? intval(($s[0] - $tmbSize)/2) : 0;
831
					$y = $s[1] > $tmbSize ? intval(($s[1] - $tmbSize)/2) : 0;
832
					$result = $this->imgCrop($tmb, $tmbSize, $tmbSize, $x, $y, 'png');
0 ignored issues
show
$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...
$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...
$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...
833
				}
834
	
835
			} else {
836
				$result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, true, 'png');
0 ignored issues
show
$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...
837
			}
838
		
839
			$result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png' );
840
		}
841
		
842
		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...
843
			unlink($tmb);
844
			return false;
845
		}
846
	
847
		return $name;
848
	}
849
	
850
	/**
851
	 * Return thumbnail file name for required file
852
	 *
853
	 * @param  array  $stat  file stat
854
	 * @return string
855
	 * @author Dmitry (dio) Levashov
856
	 **/
857
	protected function tmbname($stat) {
858
		return $this->tmbPrefix.$stat['rev'].'.png';
859
	}
860
	
861
	/**
862
	 * Get thumbnail from dropbox.com
863
	 * @param string $path
864
	 * @param string $size
865
	 * @return string | boolean
866
	 */
867
	protected function getThumbnail($path, $size = 'small') {
868
		try {
869
			return $this->dropbox->getThumbnail($path, $size);
870
		} catch (Dropbox_Exception $e) {
0 ignored issues
show
The class Dropbox_Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

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

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

Loading history...
871
			return false;
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...
872
		}
873
	}
874
	
875
	/**
876
	* Return content URL
877
	*
878
	* @param string  $hash  file hash
879
	* @param array $options options
880
	* @return array
881
	* @author Naoki Sawada
882
	**/
883
	public function getContentUrl($hash, $options = array()) {
884
		if (($file = $this->file($hash)) == false || !$file['url'] || $file['url'] == 1) {
885
			$path = $this->decode($hash);
886
			$cache = $this->getDBdat($path);
887
			$url = '';
888
			if (isset($cache['share']) && strpos($cache['share'], $this->dropbox_dlhost) !== false) {
889
				$res = $this->getHttpResponseHeader($cache['share']);
890
				if (preg_match("/^HTTP\/[01\.]+ ([0-9]{3})/", $res, $match)) {
891
					if ($match[1] < 400) {
892
						$url = $cache['share'];
893
					}
894
				}
895
			}
896
			if (! $url) {
897
				try {
898
					$res = $this->dropbox->share($path, null, false);
899
					$url = $res['url'];
900
					if (strpos($url, 'www.dropbox.com') === false) {
901
						$res = $this->getHttpResponseHeader($url);
902
						if (preg_match('/^location:\s*(http[^\s]+)/im', $res, $match)) {
903
							$url = $match[1];
904
						}
905
					}
906
					list($url) = explode('?', $url);
907
					$url = str_replace('www.dropbox.com', $this->dropbox_dlhost, $url);
908
					if (! isset($cache['share']) || $cache['share'] !== $url) {
909
						$cache['share'] = $url;
910
						$this->updateDBdat($path, $cache);
911
					}
912
				} catch (Dropbox_Exception $e) {
0 ignored issues
show
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...
913
					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...
914
				}
915
			}
916
			return $url;
917
		}
918
		return $file['url'];
919
	}
920
	
921
	/**
922
	 * Get HTTP request response header string
923
	 * 
924
	 * @param string $url target URL
925
	 * @return string
926
	 * @author Naoki Sawada
927
	 */
928
	private function getHttpResponseHeader($url) {
929
		if (function_exists('curl_exec')) {
930
931
			$c = curl_init();
932
			curl_setopt( $c, CURLOPT_RETURNTRANSFER, true );
933
			curl_setopt( $c, CURLOPT_CUSTOMREQUEST, 'HEAD' );
934
			curl_setopt( $c, CURLOPT_HEADER, 1 );
935
			curl_setopt( $c, CURLOPT_NOBODY, true );
936
			curl_setopt( $c, CURLOPT_URL, $url );
937
			$res = curl_exec( $c );
938
			
939
		} else {
940
			
941
			require_once 'HTTP/Request2.php';
942
			try {
943
				$request2 = new HTTP_Request2();
944
				$request2->setConfig(array(
945
                    'ssl_verify_peer' => false,
946
                    'ssl_verify_host' => false
947
                ));
948
				$request2->setUrl($url);
949
				$request2->setMethod(HTTP_Request2::METHOD_HEAD);
950
				$result = $request2->send();
951
				$res = array();
952
				$res[] = 'HTTP/'.$result->getVersion().' '.$result->getStatus().' '.$result->getReasonPhrase();
953
				foreach($result->getHeader() as $key => $val) {
954
					$res[] = $key . ': ' . $val;
955
				}
956
				$res = join("\r\n", $res);
957
			} catch( HTTP_Request2_Exception $e ){
0 ignored issues
show
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...
958
				$res = '';
959
			} catch (Exception $e){
960
				$res = '';
961
			}
962
		
963
		}
964
		return $res;
965
	}
966
	
967
	/*********************** paths/urls *************************/
968
969
	/**
970
	 * Return parent directory path
971
	 *
972
	 * @param  string  $path  file path
973
	 * @return string
974
	 * @author Dmitry (dio) Levashov
975
	 **/
976
	protected function _dirname($path) {
977
		return $this->_normpath(dirname($path));
978
	}
979
980
	/**
981
	 * Return file name
982
	 *
983
	 * @param  string  $path  file path
984
	 * @return string
985
	 * @author Dmitry (dio) Levashov
986
	 **/
987
	protected function _basename($path) {
988
		return basename($path);
989
	}
990
991
	/**
992
	 * Join dir name and file name and retur full path
993
	 *
994
	 * @param  string  $dir
995
	 * @param  string  $name
996
	 * @return string
997
	 * @author Dmitry (dio) Levashov
998
	 **/
999
	protected function _joinPath($dir, $name) {
1000
		return $this->_normpath($dir.'/'.$name);
1001
	}
1002
1003
	/**
1004
	 * Return normalized path, this works the same as os.path.normpath() in Python
1005
	 *
1006
	 * @param  string  $path  path
1007
	 * @return string
1008
	 * @author Troex Nevelin
1009
	 **/
1010
	protected function _normpath($path) {
1011
		$path = '/' . ltrim($path, '/');
1012
		return $path;
1013
	}
1014
1015
	/**
1016
	 * Return file path related to root dir
1017
	 *
1018
	 * @param  string  $path  file path
1019
	 * @return string
1020
	 * @author Dmitry (dio) Levashov
1021
	 **/
1022
	protected function _relpath($path) {
1023
		return $path;
1024
	}
1025
1026
	/**
1027
	 * Convert path related to root dir into real path
1028
	 *
1029
	 * @param  string  $path  file path
1030
	 * @return string
1031
	 * @author Dmitry (dio) Levashov
1032
	 **/
1033
	protected function _abspath($path) {
1034
		return $path;
1035
	}
1036
1037
	/**
1038
	 * Return fake path started from root dir
1039
	 *
1040
	 * @param  string  $path  file path
1041
	 * @return string
1042
	 * @author Dmitry (dio) Levashov
1043
	 **/
1044
	protected function _path($path) {
1045
		return $this->rootName . $this->_normpath(substr($path, strlen($this->root)));
1046
	}
1047
1048
	/**
1049
	 * Return true if $path is children of $parent
1050
	 *
1051
	 * @param  string  $path    path to check
1052
	 * @param  string  $parent  parent path
1053
	 * @return bool
1054
	 * @author Dmitry (dio) Levashov
1055
	 **/
1056
	protected function _inpath($path, $parent) {
1057
		return $path == $parent || strpos($path, $parent.'/') === 0;
1058
	}
1059
1060
	/***************** file stat ********************/
1061
	/**
1062
	 * Return stat for given path.
1063
	 * Stat contains following fields:
1064
	 * - (int)    size    file size in b. required
1065
	 * - (int)    ts      file modification time in unix time. required
1066
	 * - (string) mime    mimetype. required for folders, others - optionally
1067
	 * - (bool)   read    read permissions. required
1068
	 * - (bool)   write   write permissions. required
1069
	 * - (bool)   locked  is object locked. optionally
1070
	 * - (bool)   hidden  is object hidden. optionally
1071
	 * - (string) alias   for symlinks - link target path relative to root path. optionally
1072
	 * - (string) target  for symlinks - link target path. optionally
1073
	 *
1074
	 * If file does not exists - returns empty array or false.
1075
	 *
1076
	 * @param  string  $path    file path
1077
	 * @return array|false
1078
	 * @author Dmitry (dio) Levashov
1079
	 **/
1080
	protected function _stat($path) {
1081
		//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...
1082
		if ($this->isMyReload()) {
1083
			$this->deltaCheck();
1084
		}
1085
		if ($raw = $this->getDBdat($path)) {
1086
			return $this->parseRaw($raw);
0 ignored issues
show
$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...
1087
		}
1088
		return false;
1089
	}
1090
1091
	/**
1092
	 * Return true if path is dir and has at least one childs directory
1093
	 *
1094
	 * @param  string  $path  dir path
1095
	 * @return bool
1096
	 * @author Dmitry (dio) Levashov
1097
	 **/
1098
	protected function _subdirs($path) {
1099
		return ($stat = $this->stat($path)) && isset($stat['dirs']) ? $stat['dirs'] : false;
1100
	}
1101
1102
	/**
1103
	 * Return object width and height
1104
	 * Ususaly used for images, but can be realize for video etc...
1105
	 *
1106
	 * @param  string  $path  file path
1107
	 * @param  string  $mime  file mime type
1108
	 * @return string
1109
	 * @author Dmitry (dio) Levashov
1110
	 **/
1111
	protected function _dimensions($path, $mime) {
1112
		if (strpos($mime, 'image') !== 0) return '';
1113
		$cache = $this->getDBdat($path);
1114
		if (isset($cache['width']) && isset($cache['height'])) {
1115
			return $cache['width'].'x'.$cache['height'];
1116
		}
1117
		$ret = '';
1118
		if ($work = $this->getWorkFile($path)) {
1119
			if ($size = @getimagesize($work)) {
1120
				$cache['width'] = $size[0];
1121
				$cache['height'] = $size[1];
1122
				$this->updateDBdat($path, $cache);
1123
				$ret = $size[0].'x'.$size[1];
1124
			}
1125
		}
1126
		is_file($work) && @unlink($work);
1127
		return $ret;
1128
	}
1129
1130
	/******************** file/dir content *********************/
1131
1132
	/**
1133
	 * Return files list in directory.
1134
	 *
1135
	 * @param  string  $path  dir path
1136
	 * @return array
1137
	 * @author Dmitry (dio) Levashov
1138
	 * @author Cem (DiscoFever)
1139
	 **/
1140
	protected function _scandir($path) {
1141
		return isset($this->dirsCache[$path])
1142
			? $this->dirsCache[$path]
1143
			: $this->cacheDir($path);
1144
	}
1145
1146
	/**
1147
	 * Open file and return file pointer
1148
	 *
1149
	 * @param  string  $path  file path
1150
	 * @param  bool    $write open file for writing
0 ignored issues
show
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...
1151
	 * @return resource|false
1152
	 * @author Dmitry (dio) Levashov
1153
	 **/
1154
	protected function _fopen($path, $mode='rb') {
1155
1156
		if (($mode == 'rb' || $mode == 'r')) {
1157
			try {
1158
				$res = $this->dropbox->media($path);
1159
				$url = parse_url($res['url']);
1160
 				$fp = stream_socket_client('ssl://'.$url['host'].':443');
1161
 				fputs($fp, "GET {$url['path']} HTTP/1.0\r\n");
1162
 				fputs($fp, "Host: {$url['host']}\r\n");
1163
 				fputs($fp, "\r\n");
1164
 				while(trim(fgets($fp)) !== ''){};
0 ignored issues
show
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...
1165
 				return $fp;
1166
			} catch (Dropbox_Exception $e) {
0 ignored issues
show
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...
1167
				return false;
1168
			}
1169
		}
1170
		
1171
		if ($this->tmp) {
1172
			$contents = $this->_getContents($path);
1173
			
1174
			if ($contents === false) {
1175
				return false;
1176
			}
1177
			
1178
			if ($local = $this->getTempFile($path)) {
1179
				if (file_put_contents($local, $contents, LOCK_EX) !== false) {
1180
					return @fopen($local, $mode);
1181
				}
1182
			}
1183
		}
1184
1185
		return false;
1186
	}
1187
1188
	/**
1189
	 * Close opened file
1190
	 *
1191
	 * @param  resource  $fp  file pointer
1192
	 * @return bool
1193
	 * @author Dmitry (dio) Levashov
1194
	 **/
1195
	protected function _fclose($fp, $path='') {
1196
		@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...
1197
		if ($path) {
1198
			@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...
1199
		}
1200
	}
1201
1202
	/********************  file/dir manipulations *************************/
1203
1204
	/**
1205
	 * Create dir and return created dir path or false on failed
1206
	 *
1207
	 * @param  string  $path  parent dir path
1208
	 * @param string  $name  new directory name
1209
	 * @return string|bool
1210
	 * @author Dmitry (dio) Levashov
1211
	 **/
1212
	protected function _mkdir($path, $name) {
1213
		$path = $this->_normpath($path.'/'.$name);
1214
		try {
1215
			$this->dropbox->createFolder($path);
1216
		} catch (Dropbox_Exception $e) {
0 ignored issues
show
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...
1217
			$this->deltaCheck();
1218
			if ($this->dir($this->encode($path))) {
1219
				return $path;
1220
			}
1221
			return $this->setError('Dropbox error: '.$e->getMessage());
1222
		}
1223
		$this->deltaCheck();
1224
		return $path;
1225
	}
1226
1227
	/**
1228
	 * Create file and return it's path or false on failed
1229
	 *
1230
	 * @param  string  $path  parent dir path
1231
	 * @param string  $name  new file name
1232
	 * @return string|bool
1233
	 * @author Dmitry (dio) Levashov
1234
	 **/
1235
	protected function _mkfile($path, $name) {
1236
		return $this->_filePutContents($path.'/'.$name, '');
1237
	}
1238
1239
	/**
1240
	 * Create symlink. FTP driver does not support symlinks.
1241
	 *
1242
	 * @param  string  $target  link target
1243
	 * @param  string  $path    symlink path
1244
	 * @return bool
1245
	 * @author Dmitry (dio) Levashov
1246
	 **/
1247
	protected function _symlink($target, $path, $name) {
1248
		return false;
1249
	}
1250
1251
	/**
1252
	 * Copy file into another file
1253
	 *
1254
	 * @param  string  $source     source file path
1255
	 * @param  string  $targetDir  target directory path
1256
	 * @param  string  $name       new file name
1257
	 * @return bool
1258
	 * @author Dmitry (dio) Levashov
1259
	 **/
1260 View Code Duplication
	protected function _copy($source, $targetDir, $name) {
0 ignored issues
show
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...
1261
		$path = $this->_normpath($targetDir.'/'.$name);
1262
		try {
1263
			$this->dropbox->copy($source, $path);
1264
		} catch (Dropbox_Exception $e) {
0 ignored issues
show
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...
1265
			return $this->setError('Dropbox error: '.$e->getMessage());
1266
		}
1267
		$this->deltaCheck();
1268
		return true;
1269
	}
1270
1271
	/**
1272
	 * Move file into another parent dir.
1273
	 * Return new file path or false.
1274
	 *
1275
	 * @param  string  $source  source file path
1276
	 * @param  string  $target  target dir path
0 ignored issues
show
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...
1277
	 * @param  string  $name    file name
1278
	 * @return string|bool
1279
	 * @author Dmitry (dio) Levashov
1280
	 **/
1281 View Code Duplication
	protected function _move($source, $targetDir, $name) {
0 ignored issues
show
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...
1282
		$target = $this->_normpath($targetDir.'/'.$name);
1283
		try {
1284
			$this->dropbox->move($source, $target);
1285
		} catch (Dropbox_Exception $e) {
0 ignored issues
show
The class Dropbox_Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

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

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

Loading history...
1286
			return $this->setError('Dropbox error: '.$e->getMessage());
1287
		}
1288
		$this->deltaCheck();
1289
		return $target;
1290
	}
1291
1292
	/**
1293
	 * Remove file
1294
	 *
1295
	 * @param  string  $path  file path
1296
	 * @return bool
1297
	 * @author Dmitry (dio) Levashov
1298
	 **/
1299
	protected function _unlink($path) {
1300
		try {
1301
			$this->dropbox->delete($path);
1302
		} catch (Dropbox_Exception $e) {
0 ignored issues
show
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...
1303
			return $this->setError('Dropbox error: '.$e->getMessage());
1304
		}
1305
		$this->deltaCheck();
1306
		return true;
1307
	}
1308
1309
	/**
1310
	 * Remove dir
1311
	 *
1312
	 * @param  string  $path  dir path
1313
	 * @return bool
1314
	 * @author Dmitry (dio) Levashov
1315
	 **/
1316
	protected function _rmdir($path) {
1317
		return $this->_unlink($path);
1318
	}
1319
1320
	/**
1321
	 * Create new file and write into it from file pointer.
1322
	 * Return new file path or false on error.
1323
	 *
1324
	 * @param  resource  $fp   file pointer
1325
	 * @param  string    $dir  target dir path
0 ignored issues
show
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...
1326
	 * @param  string    $name file name
1327
	 * @param  array     $stat file stat (required by some virtual fs)
1328
	 * @return bool|string
1329
	 * @author Dmitry (dio) Levashov
1330
	 **/
1331
	protected function _save($fp, $path, $name, $stat) {
1332
		if ($name) $path .= '/'.$name;
1333
		$path = $this->_normpath($path);
1334
		try {
1335
			$this->dropbox->putFile($path, $fp);
1336
		} catch (Dropbox_Exception $e) {
0 ignored issues
show
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...
1337
			return $this->setError('Dropbox error: '.$e->getMessage());
1338
		}
1339
		$this->deltaCheck();
1340
		if (is_array($stat)) {
1341
			$raw = $this->getDBdat($path);
1342
			if (isset($stat['width'])) $raw['width'] = $stat['width'];
1343
			if (isset($stat['height'])) $raw['height'] = $stat['height'];
1344
			$this->updateDBdat($path, $raw);
1345
		}
1346
		return $path;
1347
	}
1348
1349
	/**
1350
	 * Get file contents
1351
	 *
1352
	 * @param  string  $path  file path
1353
	 * @return string|false
1354
	 * @author Dmitry (dio) Levashov
1355
	 **/
1356
	protected function _getContents($path) {
1357
		$contents = '';
1358
		try {
1359
			$contents = $this->dropbox->getFile($path);
1360
		} catch (Dropbox_Exception $e) {
0 ignored issues
show
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...
1361
			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...
1362
		}
1363
		return $contents;
1364
	}
1365
1366
	/**
1367
	 * Write a string to a file
1368
	 *
1369
	 * @param  string  $path     file path
1370
	 * @param  string  $content  new file content
1371
	 * @return bool
1372
	 * @author Dmitry (dio) Levashov
1373
	 **/
1374
	protected function _filePutContents($path, $content) {
1375
		$res = false;
1376
1377
		if ($local = $this->getTempFile($path)) {
1378 View Code Duplication
			if (@file_put_contents($local, $content, LOCK_EX) !== false
0 ignored issues
show
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...
1379
			&& ($fp = @fopen($local, 'rb'))) {
1380
				clearstatcache();
1381
				$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 1387 which is incompatible with the return type declared by the abstract method elFinderVolumeDriver::_filePutContents of type boolean.
Loading history...
1382
				@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...
1383
			}
1384
			file_exists($local) && @unlink($local);
1385
		}
1386
1387
		return $res;
1388
	}
1389
1390
	/**
1391
	 * Detect available archivers
1392
	 *
1393
	 * @return void
1394
	 **/
1395
	protected function _checkArchivers() {
1396
		// 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...
1397
		return array();
1398
	}
1399
1400
	/**
1401
	 * chmod implementation
1402
	 *
1403
	 * @return bool
1404
	 **/
1405
	protected function _chmod($path, $mode) {
1406
		return false;
1407
	}
1408
1409
	/**
1410
	 * Unpack archive
1411
	 *
1412
	 * @param  string  $path  archive path
1413
	 * @param  array   $arc   archiver command and arguments (same as in $this->archivers)
1414
	 * @return true
1415
	 * @return void
1416
	 * @author Dmitry (dio) Levashov
1417
	 * @author Alexey Sukhotin
1418
	 **/
1419
	protected function _unpack($path, $arc) {
0 ignored issues
show
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...
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...
1420
		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...
1421
		return false;
0 ignored issues
show
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...
1422
	}
1423
1424
	/**
1425
	 * Recursive symlinks search
1426
	 *
1427
	 * @param  string  $path  file/dir path
1428
	 * @return bool
1429
	 * @author Dmitry (dio) Levashov
1430
	 **/
1431
	protected function _findSymlinks($path) {
0 ignored issues
show
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...
1432
		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...
1433
		if (is_link($path)) {
0 ignored issues
show
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...
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...
1434
			return true;
1435
		}
1436
		if (is_dir($path)) {
0 ignored issues
show
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...
1437 View Code Duplication
			foreach (scandir($path) as $name) {
0 ignored issues
show
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...
1438
				if ($name != '.' && $name != '..') {
1439
					$p = $path.DIRECTORY_SEPARATOR.$name;
1440
					if (is_link($p)) {
0 ignored issues
show
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...
1441
						return true;
1442
					}
1443
					if (is_dir($p) && $this->_findSymlinks($p)) {
0 ignored issues
show
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...
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...
1444
						return true;
1445
					} elseif (is_file($p)) {
0 ignored issues
show
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...
1446
						$this->archiveSize += filesize($p);
0 ignored issues
show
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...
1447
					}
1448
				}
1449
			}
1450
		} else {
1451
			$this->archiveSize += filesize($path);
1452
		}
1453
1454
		return false;
1455
	}
1456
1457
	/**
1458
	 * Extract files from archive
1459
	 *
1460
	 * @param  string  $path  archive path
1461
	 * @param  array   $arc   archiver command and arguments (same as in $this->archivers)
1462
	 * @return true
1463
	 * @author Dmitry (dio) Levashov,
1464
	 * @author Alexey Sukhotin
1465
	 **/
1466
	protected function _extract($path, $arc) {
1467
		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...
1468
1469
	}
1470
1471
	/**
1472
	 * Create archive and return its path
1473
	 *
1474
	 * @param  string  $dir    target dir
1475
	 * @param  array   $files  files names list
1476
	 * @param  string  $name   archive name
1477
	 * @param  array   $arc    archiver options
1478
	 * @return string|bool
1479
	 * @author Dmitry (dio) Levashov,
1480
	 * @author Alexey Sukhotin
1481
	 **/
1482
	protected function _archive($dir, $files, $name, $arc) {
1483
		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...
1484
		return false;
0 ignored issues
show
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...
1485
	}
1486
1487
} // END class
1488