GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#2259)
by
unknown
09:29
created

FileHandler   D

Complexity

Total Complexity 205

Size/Duplication

Total Lines 1191
Duplicated Lines 5.71 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
dl 68
loc 1191
rs 4
c 0
b 0
f 0
wmc 205
lcom 1
cbo 6

30 Methods

Rating   Name   Duplication   Size   Complexity  
A getRealPath() 0 9 3
C copyDir() 0 56 11
A copyFile() 0 16 2
A readFile() 0 9 3
A writeFile() 0 17 2
A removeFile() 0 4 2
A rename() 0 4 1
A moveFile() 0 9 2
A moveDir() 0 4 1
D readDir() 0 43 10
C makeDir() 0 74 13
B removeDir() 34 34 6
B removeBlankDir() 0 25 5
C removeFilesInDir() 34 34 7
B filesize() 0 24 6
F getRemoteResource() 0 143 36
A getRemoteFile() 0 22 3
A returnBytes() 0 14 4
B checkMemoryLoadImage() 0 25 4
F createImageFile() 0 212 51
A readIniFile() 0 16 4
A writeIniFile() 0 9 3
B _makeIniBuff() 0 27 5
A openFile() 0 8 1
A hasContent() 0 4 2
A exists() 0 5 2
A isDir() 0 5 2
A isWritableDir() 0 20 3
A clearStatCache() 0 17 4
C invalidateOpcache() 0 29 7

How to fix   Duplicated Code    Complexity   

Duplicated Code

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

Common duplication problems, and corresponding solutions are:

Complex Class

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

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

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

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

1
<?php
2
/* Copyright (C) NAVER <http://www.navercorp.com> */
3
4
/**
5
 * Contains methods for accessing file system
6
 *
7
 * @author NAVER ([email protected])
8
 */
9
class FileHandler
10
{
11
12
	/**
13
	 * Changes path of target file, directory into absolute path
14
	 *
15
	 * @param string $source path to change into absolute path
16
	 * @return string Absolute path
17
	 */
18
	function getRealPath($source)
19
	{
20
		if(strlen($source) >= 2 && substr_compare($source, './', 0, 2) === 0)
21
		{
22
			return _XE_PATH_ . substr($source, 2);
23
		}
24
25
		return $source;
26
	}
27
28
	/**
29
	 * Copy a directory to target
30
	 *
31
	 * If target directory does not exist, this function creates it
32
	 *
33
	 * @param string $source_dir Path of source directory
34
	 * @param string $target_dir Path of target dir
35
	 * @param string $filter Regex to filter files. If file matches this regex, the file is not copied.
36
	 * @param string $type If set as 'force'. Even if the file exists in target, the file is copied.
37
	 * @return void
38
	 */
39
	function copyDir($source_dir, $target_dir, $filter = null, $type = null)
40
	{
41
		$source_dir = self::getRealPath($source_dir);
42
		$target_dir = self::getRealPath($target_dir);
43
		if(!is_dir($source_dir))
44
		{
45
			return FALSE;
46
		}
47
48
		// generate when no target exists
49
		self::makeDir($target_dir);
50
51
		if(substr($source_dir, -1) != DIRECTORY_SEPARATOR)
52
		{
53
			$source_dir .= DIRECTORY_SEPARATOR;
54
		}
55
56
		if(substr($target_dir, -1) != DIRECTORY_SEPARATOR)
57
		{
58
			$target_dir .= DIRECTORY_SEPARATOR;
59
		}
60
61
		$oDir = dir($source_dir);
62
		while($file = $oDir->read())
63
		{
64
			if($file{0} == '.')
65
			{
66
				continue;
67
			}
68
69
			if($filter && preg_match($filter, $file))
0 ignored issues
show
Bug Best Practice introduced by
The expression $filter of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null 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...
70
			{
71
				continue;
72
			}
73
74
			if(is_dir($source_dir . $file))
75
			{
76
				self::copyDir($source_dir . $file, $target_dir . $file, $type);
77
			}
78
			else
79
			{
80
				if($type == 'force')
81
				{
82
					@unlink($target_dir . $file);
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...
83
				}
84
				else
85
				{
86
					if(!file_exists($target_dir . $file))
87
					{
88
						@copy($source_dir . $file, $target_dir . $file);
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...
89
					}
90
				}
91
			}
92
		}
93
		$oDir->close();
94
	}
95
96
	/**
97
	 * Copy a file to target
98
	 *
99
	 * @param string $source Path of source file
100
	 * @param string $target Path of target file
101
	 * @param string $force Y: overwrite
102
	 * @return void
103
	 */
104
	function copyFile($source, $target, $force = 'Y')
105
	{
106
		setlocale(LC_CTYPE, 'en_US.UTF8', 'ko_KR.UTF8');
107
		$source = self::getRealPath($source);
108
		$target_dir = self::getRealPath(dirname($target));
109
		$target = basename($target);
110
111
		self::makeDir($target_dir);
112
113
		if($force == 'Y')
114
		{
115
			@unlink($target_dir . DIRECTORY_SEPARATOR . $target);
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...
116
		}
117
118
		@copy($source, $target_dir . DIRECTORY_SEPARATOR . $target);
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...
119
	}
120
121
	/**
122
	 * Returns the content of the file
123
	 *
124
	 * @param string $filename Path of target file
125
	 * @return string The content of the file. If target file does not exist, this function returns nothing.
126
	 */
127
	function readFile($filename)
128
	{
129
		if(($filename = self::exists($filename)) === FALSE || filesize($filename) < 1)
130
		{
131
			return;
132
		}
133
134
		return @file_get_contents($filename);
135
	}
136
137
	/**
138
	 * Write $buff into the specified file
139
	 *
140
	 * @param string $filename Path of target file
141
	 * @param string $buff Content to be written
142
	 * @param string $mode a(append) / w(write)
143
	 * @return void
144
	 */
145
	function writeFile($filename, $buff, $mode = "w")
146
	{
147
		$filename = self::getRealPath($filename);
148
		$pathinfo = pathinfo($filename);
149
		self::makeDir($pathinfo['dirname']);
150
151
		$flags = 0;
152
		if(strtolower($mode) == 'a')
153
		{
154
			$flags = FILE_APPEND;
155
		}
156
157
		@file_put_contents($filename, $buff, $flags|LOCK_EX);
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...
158
		@chmod($filename, 0644);
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...
159
		self::clearStatCache($filename);
160
		self::invalidateOpcache($filename);
161
	}
162
163
	/**
164
	 * Remove a file
165
	 *
166
	 * @param string $filename path of target file
167
	 * @return bool Returns TRUE on success or FALSE on failure.
168
	 */
169
	function removeFile($filename)
170
	{
171
		return (($filename = self::exists($filename)) !== FALSE) && @unlink($filename);
172
	}
173
174
	/**
175
	 * Rename a file
176
	 *
177
	 * In order to move a file, use this function.
178
	 *
179
	 * @param string $source Path of source file
180
	 * @param string $target Path of target file
181
	 * @return bool Returns TRUE on success or FALSE on failure.
182
	 */
183
	function rename($source, $target)
184
	{
185
		return @rename(self::getRealPath($source), self::getRealPath($target));
186
	}
187
188
	/**
189
	 * Move a file
190
	 *
191
	 * @param string $source Path of source file
192
	 * @param string $target Path of target file
193
	 * @return bool Returns TRUE on success or FALSE on failure.
194
	 */
195
	function moveFile($source, $target)
196
	{
197
		if(($source = self::exists($source)) !== FALSE)
198
		{
199
			self::removeFile($target);
200
			return self::rename($source, $target);
201
		}
202
		return FALSE;
203
	}
204
205
	/**
206
	 * Move a directory
207
	 *
208
	 * This function just wraps rename function.
209
	 *
210
	 * @param string $source_dir Path of source directory
211
	 * @param string $target_dir Path of target directory
212
	 * @return void
213
	 */
214
	function moveDir($source_dir, $target_dir)
215
	{
216
		self::rename($source_dir, $target_dir);
217
	}
218
219
	/**
220
	 * Return list of the files in the path
221
	 *
222
	 * The array does not contain files, such as '.', '..', and files starting with '.'
223
	 *
224
	 * @param string $path Path of target directory
225
	 * @param string $filter If specified, return only files matching with the filter
226
	 * @param bool $to_lower If TRUE, file names will be changed into lower case.
227
	 * @param bool $concat_prefix If TRUE, return file name as absolute path
228
	 * @return string[] Array of the filenames in the path
229
	 */
230
	function readDir($path, $filter = '', $to_lower = FALSE, $concat_prefix = FALSE)
231
	{
232
		$path = self::getRealPath($path);
233
		$output = array();
234
235
		if(substr($path, -1) != '/')
236
		{
237
			$path .= '/';
238
		}
239
240
		if(!is_dir($path))
241
		{
242
			return $output;
243
		}
244
245
		$files = scandir($path);
246
		foreach($files as $file)
247
		{
248
			if($file{0} == '.' || ($filter && !preg_match($filter, $file)))
249
			{
250
				continue;
251
			}
252
253
			if($to_lower)
254
			{
255
				$file = strtolower($file);
256
			}
257
258
			if($filter)
259
			{
260
				$file = preg_replace($filter, '$1', $file);
261
			}
262
263
			if($concat_prefix)
264
			{
265
				$file = sprintf('%s%s', str_replace(_XE_PATH_, '', $path), $file);
266
			}
267
268
			$output[] = str_replace(array('/\\', '//'), '/', $file);
269
		}
270
271
		return $output;
272
	}
273
274
	/**
275
	 * Creates a directory
276
	 *
277
	 * This function creates directories recursively, which means that if ancestors of the target directory does not exist, they will be created too.
278
	 *
279
	 * @param string $path_string Path of target directory
280
	 * @return bool TRUE if success. It might return nothing when ftp is used and connection to the ftp address failed.
281
	 */
282
	function makeDir($path_string)
283
	{
284
		if(self::exists($path_string) !== FALSE)
285
		{
286
			return TRUE;
287
		}
288
289
		if(!ini_get('safe_mode'))
290
		{
291
			@mkdir($path_string, 0755, TRUE);
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...
292
			@chmod($path_string, 0755);
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...
293
		}
294
		// if safe_mode is on, use FTP
295
		else
296
		{
297
			static $oFtp = NULL;
298
299
			$ftp_info = Context::getFTPInfo();
300
			if($oFtp == NULL)
301
			{
302
				if(!Context::isFTPRegisted())
303
				{
304
					return;
305
				}
306
307
				require_once(_XE_PATH_ . 'libs/ftp.class.php');
308
				$oFtp = new ftp();
309
				if(!$ftp_info->ftp_host)
310
				{
311
					$ftp_info->ftp_host = "127.0.0.1";
312
				}
313
				if(!$ftp_info->ftp_port)
314
				{
315
					$ftp_info->ftp_port = 21;
316
				}
317
				if(!$oFtp->ftp_connect($ftp_info->ftp_host, $ftp_info->ftp_port))
318
				{
319
					return;
320
				}
321
				if(!$oFtp->ftp_login($ftp_info->ftp_user, $ftp_info->ftp_password))
322
				{
323
					$oFtp->ftp_quit();
324
					return;
325
				}
326
			}
327
328
			if(!($ftp_path = $ftp_info->ftp_root_path))
329
			{
330
				$ftp_path = DIRECTORY_SEPARATOR;
331
			}
332
333
			$path_string = str_replace(_XE_PATH_, '', $path_string);
334
			$path_list = explode(DIRECTORY_SEPARATOR, $path_string);
335
336
			$path = _XE_PATH_;
337
			for($i = 0, $c = count($path_list); $i < $c; $i++)
338
			{
339
				if(!$path_list[$i])
340
				{
341
					continue;
342
				}
343
344
				$path .= $path_list[$i] . DIRECTORY_SEPARATOR;
345
				$ftp_path .= $path_list[$i] . DIRECTORY_SEPARATOR;
346
				if(!is_dir($path))
347
				{
348
					$oFtp->ftp_mkdir($ftp_path);
349
					$oFtp->ftp_site("CHMOD 777 " . $ftp_path);
350
				}
351
			}
352
		}
353
354
		return is_dir($path_string);
355
	}
356
357
	/**
358
	 * Remove all files under the path
359
	 *
360
	 * @param string $path Path of the target directory
361
	 * @return void
362
	 */
363 View Code Duplication
	function removeDir($path)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
364
	{
365
		if(($path = self::isDir($path)) === FALSE)
366
		{
367
			return;
368
		}
369
370
		if(self::isDir($path))
0 ignored issues
show
Bug Best Practice introduced by
The expression self::isDir($path) of type string|false is loosely compared to true; 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...
371
		{
372
			$files = array_diff(scandir($path), array('..', '.'));
373
374
			foreach($files as $file)
375
			{
376
				if(($target = self::getRealPath($path . DIRECTORY_SEPARATOR . $file)) === FALSE)
377
				{
378
					continue;
379
				}
380
381
				if(is_dir($target))
382
				{
383
					self::removeDir($target);
384
				}
385
				else
386
				{
387
					unlink($target);
388
				}
389
			}
390
			rmdir($path);
391
		}
392
		else
393
		{
394
			unlink($path);
395
		}
396
	}
397
398
	/**
399
	 * Remove a directory only if it is empty
400
	 *
401
	 * @param string $path Path of the target directory
402
	 * @return void
403
	 */
404
	function removeBlankDir($path)
405
	{
406
		if(($path = self::isDir($path)) === FALSE)
407
		{
408
			return;
409
		}
410
411
		$files = array_diff(scandir($path), array('..', '.'));
412
413
		if(count($files) < 1)
414
		{
415
			rmdir($path);
416
			return;
417
		}
418
419
		foreach($files as $file)
420
		{
421
			if(($target = self::isDir($path . DIRECTORY_SEPARATOR . $file)) === FALSE)
422
			{
423
				continue;
424
			}
425
426
			self::removeBlankDir($target);
427
		}
428
	}
429
430
	/**
431
	 * Remove files in the target directory
432
	 *
433
	 * This function keeps the directory structure.
434
	 *
435
	 * @param string $path Path of the target directory
436
	 * @return void
437
	 */
438 View Code Duplication
	function removeFilesInDir($path)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
439
	{
440
		if(($path = self::getRealPath($path)) === FALSE)
441
		{
442
			return;
443
		}
444
445
		if(is_dir($path))
446
		{
447
			$files = array_diff(scandir($path), array('..', '.'));
448
449
			foreach($files as $file)
450
			{
451
				if(($target = self::getRealPath($path . DIRECTORY_SEPARATOR . $file)) === FALSE)
452
				{
453
					continue;
454
				}
455
456
				if(is_dir($target))
457
				{
458
					self::removeFilesInDir($target);
459
				}
460
				else
461
				{
462
					unlink($target);
463
				}
464
			}
465
		}
466
		else
467
		{
468
			if(self::exists($path)) unlink($path);
0 ignored issues
show
Bug Best Practice introduced by
The expression self::exists($path) of type string|false is loosely compared to true; 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...
469
		}
470
471
	}
472
473
	/**
474
	 * Makes file size byte into KB, MB according to the size
475
	 *
476
	 * @see self::returnBytes()
477
	 * @param int $size Number of the size
478
	 * @return string File size string
479
	 */
480
	function filesize($size)
481
	{
482
		if(!$size)
483
		{
484
			return '0Byte';
485
		}
486
487
		if($size === 1)
488
		{
489
			return '1Byte';
490
		}
491
492
		if($size < 1024)
493
		{
494
			return $size . 'Bytes';
495
		}
496
497
		if($size >= 1024 && $size < 1024 * 1024)
498
		{
499
			return sprintf("%0.1fKB", $size / 1024);
500
		}
501
502
		return sprintf("%0.2fMB", $size / (1024 * 1024));
503
	}
504
505
	/**
506
	 * Return remote file's content via HTTP
507
	 *
508
	 * If the target is moved (when return code is 300~399), this function follows the location specified response header.
509
	 *
510
	 * @param string $url The address of the target file
511
	 * @param string $body HTTP request body
512
	 * @param int $timeout Connection timeout
513
	 * @param string $method GET/POST
514
	 * @param string $content_type Content type header of HTTP request
515
	 * @param string[] $headers Headers key value array.
516
	 * @param string[] $cookies Cookies key value array.
517
	 * @param string $post_data Request arguments array for POST method
518
	 * @return string If success, the content of the target file. Otherwise: none
519
	 */
520
	function getRemoteResource($url, $body = null, $timeout = 3, $method = 'GET', $content_type = null, $headers = array(), $cookies = array(), $post_data = array(), $request_config = array())
521
	{
522
		require_once(_XE_PATH_ . 'libs/idna_convert/idna_convert.class.php');
523
		$IDN = new idna_convert(array('idn_version' => 2008));
524
		$url = $IDN->encode($url);
525
526
		try
527
		{
528
			requirePear();
529
			require_once('HTTP/Request.php');
530
531
			$parsed_url = parse_url(__PROXY_SERVER__);
532
			if($parsed_url["host"] && $parsed_url["path"])
533
			{
534
				// Old style proxy server support (POST payload to proxy script)
535
				$oRequest = new HTTP_Request(__PROXY_SERVER__);
536
				$oRequest->setMethod('POST');
537
				$oRequest->addPostData('arg', serialize(array('Destination' => $url, 'method' => $method, 'body' => $body, 'content_type' => $content_type, "headers" => $headers, "post_data" => $post_data)));
538
			}
539
			else
540
			{
541
				$oRequest = new HTTP_Request($url);
0 ignored issues
show
Security Bug introduced by
It seems like $url defined by $IDN->encode($url) on line 524 can also be of type false; however, HTTP_Request2::__construct() does only seem to accept string|object<Net_URL2>|null, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
542
543
				// New style proxy server support (Use HTTP_Request2 native config format)
544
				if($parsed_url['host'])
545
				{
546
					$request_config['proxy_host'] = $parsed_url['host'];
547
					$request_config['proxy_port'] = $parsed_url['port'] ? $parsed_url['port'] : '';
548
					$request_config['proxy_user'] = rawurldecode($parsed_url['user'] ? $parsed_url['user'] : '');
549
					$request_config['proxy_password'] = rawurldecode($parsed_url['pass'] ? $parsed_url['pass'] : '');
550
					$request_config['proxy_type'] = $parsed_url['scheme'] ? $parsed_url['scheme'] : 'http';
551
				}
552
553
				if(count($request_config) && method_exists($oRequest, 'setConfig'))
554
				{
555
					foreach($request_config as $key=>$val)
556
					{
557
						if($key === 'observers')
558
						{
559
							foreach($val as $observer)
560
							{
561
								$oRequest->attach($observer);
562
							}
563
						}
564
						else
565
						{
566
							$oRequest->setConfig($key, $val);
567
						}
568
					}
569
				}
570
				if(method_exists($oRequest, 'setConfig'))
571
				{
572
					if(extension_loaded('curl'))
573
					{
574
						$oRequest->setConfig('adapter', 'curl');
575
					}
576
					elseif(version_compare(PHP_VERSION, '5.6', '<'))
577
					{
578
						$oRequest->setConfig('ssl_verify_host', false);
579
					}
580
					if(file_exists(_XE_PATH_ . 'libs/cacert/cacert.pem'))
581
					{
582
						$oRequest->setConfig('ssl_cafile', _XE_PATH_ . 'libs/cacert/cacert.pem');
583
					}
584
				}
585
586
				if(count($headers) > 0)
587
				{
588
					foreach($headers as $key => $val)
589
					{
590
						$oRequest->addHeader($key, $val);
591
					}
592
				}
593
				$host = parse_url($url, PHP_URL_HOST);
594
				if($cookies[$host])
595
				{
596
					foreach($cookies[$host] as $key => $val)
0 ignored issues
show
Bug introduced by
The expression $cookies[$host] of type string is not traversable.
Loading history...
597
					{
598
						$oRequest->addCookie($key, $val);
599
					}
600
				}
601
				if(count($post_data) > 0)
602
				{
603
					foreach($post_data as $key => $val)
0 ignored issues
show
Bug introduced by
The expression $post_data of type string|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...
604
					{
605
						$oRequest->addPostData($key, $val);
606
					}
607
				}
608
				if(!$content_type)
0 ignored issues
show
Bug Best Practice introduced by
The expression $content_type of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null 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...
609
					$oRequest->addHeader('Content-Type', 'text/html');
610
				else
611
					$oRequest->addHeader('Content-Type', $content_type);
612
				$oRequest->setMethod($method);
613
				if($body)
0 ignored issues
show
Bug Best Practice introduced by
The expression $body of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null 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...
614
					$oRequest->setBody($body);
615
			}
616
			
617
			if(method_exists($oRequest, 'setConfig'))
618
			{
619
				$oRequest->setConfig('timeout', $timeout);
620
			}
621
			elseif(property_exists($oRequest, '_timeout'))
622
			{
623
				$oRequest->_timeout = $timeout;
0 ignored issues
show
Bug introduced by
The property _timeout does not seem to exist in HTTP_Request.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
624
			}
625
626
			$oResponse = $oRequest->sendRequest();
0 ignored issues
show
Unused Code introduced by
$oResponse 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...
627
628
			$code = $oRequest->getResponseCode();
629
			$header = $oRequest->getResponseHeader();
630
			$response = $oRequest->getResponseBody();
631
			if($c = $oRequest->getResponseCookies())
632
			{
633
				foreach($c as $k => $v)
634
				{
635
					$cookies[$host][$v['name']] = $v['value'];
0 ignored issues
show
Bug introduced by
The variable $host does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
636
				}
637
			}
638
639
			if($code > 300 && $code < 399 && $header['location'])
640
			{
641
				return self::getRemoteResource($header['location'], $body, $timeout, $method, $content_type, $headers, $cookies, $post_data);
642
			}
643
644
			if($code != 200)
645
			{
646
				return;
647
			}
648
649
			if(isset($request_config['store_body']) && !$request_config['store_body'])
650
			{
651
				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 FileHandler::getRemoteResource 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...
652
			}
653
			else
654
			{
655
				return $response;
656
			}
657
		}
658
		catch(Exception $e)
659
		{
660
			return NULL;
661
		}
662
	}
663
664
	/**
665
	 * Retrieves remote file, then stores it into target path.
666
	 *
667
	 * @param string $url The address of the target file
668
	 * @param string $target_filename The location to store
669
	 * @param string $body HTTP request body
670
	 * @param string $timeout Connection timeout
671
	 * @param string $method GET/POST
672
	 * @param string $content_type Content type header of HTTP request
673
	 * @param string[] $headers Headers key value array.
674
	 * @return bool TRUE: success, FALSE: failed
675
	 */
676
	function getRemoteFile($url, $target_filename, $body = null, $timeout = 3, $method = 'GET', $content_type = null, $headers = array(), $cookies = array(), $post_data = array(), $request_config = array())
677
	{
678
		$target_filename = self::getRealPath($target_filename);
679
		self::writeFile($target_filename, '');
680
		
681
		requirePear();
682
		require_once('HTTP/Request2/Observer/Download.php');
683
		
684
		$request_config['store_body'] = false;
685
		$request_config['observers'][] = new HTTP_Request2_Observer_Download($target_filename);
686
		try
687
		{
688
			$result = self::getRemoteResource($url, $body, $timeout, $method, $content_type, $headers, $cookies, $post_data, $request_config);
689
			self::clearStatCache($target_filename);
690
			self::invalidateOpcache($target_filename);
691
		}
692
		catch(Exception $e)
693
		{
694
			return FALSE;
695
		}
696
		return $result ? TRUE : FALSE;
697
	}
698
699
	/**
700
	 * Convert size in string into numeric value
701
	 *
702
	 * @see self::filesize()
703
	 * @param $val Size in string (ex., 10, 10K, 10M, 10G )
704
	 * @return int converted size
705
	 */
706
	function returnBytes($val)
707
	{
708
		$unit = strtoupper(substr($val, -1));
709
		$val = (float)$val;
710
711
		switch ($unit)
712
		{
713
			case 'G': $val *= 1024;
714
			case 'M': $val *= 1024;
715
			case 'K': $val *= 1024;
716
		}
717
718
		return round($val);
719
	}
720
721
	/**
722
	 * Check available memory to load image file
723
	 *
724
	 * @param array $imageInfo Image info retrieved by getimagesize function
725
	 * @return bool TRUE: it's ok, FALSE: otherwise
726
	 */
727
	function checkMemoryLoadImage(&$imageInfo)
728
	{
729
		$memoryLimit = self::returnBytes(ini_get('memory_limit'));
730
		if($memoryLimit == -1)
731
		{
732
			return true;
733
		}
734
735
		$K64 = 65536;
736
		$TWEAKFACTOR = 2.0;
737
		$channels = $imageInfo['channels'];
738
		if(!$channels)
739
		{
740
			$channels = 6; //for png
741
		}
742
743
		$memoryNeeded = round(($imageInfo[0] * $imageInfo[1] * $imageInfo['bits'] * $channels / 8 + $K64 ) * $TWEAKFACTOR);
744
		$availableMemory = self::returnBytes(ini_get('memory_limit')) - memory_get_usage();
745
		if($availableMemory < $memoryNeeded)
746
		{
747
			return FALSE;
748
		}
749
750
		return TRUE;
751
	}
752
753
	/**
754
	 * Moves an image file (resizing is possible)
755
	 *
756
	 * @param string $source_file Path of the source file
757
	 * @param string $target_file Path of the target file
758
	 * @param int $resize_width Width to resize
759
	 * @param int $resize_height Height to resize
760
	 * @param string $target_type If $target_type is set (gif, jpg, png, bmp), result image will be saved as target type
761
	 * @param string $thumbnail_type Thumbnail type(crop, ratio)
762
	 * @param bool $thumbnail_transparent If $target_type is png, set background set transparent color
763
	 * @return bool TRUE: success, FALSE: failed
764
	 */
765
	function createImageFile($source_file, $target_file, $resize_width = 0, $resize_height = 0, $target_type = '', $thumbnail_type = 'crop', $thumbnail_transparent = FALSE)
766
	{
767
		// check params
768
		if (($source_file = self::exists($source_file)) === FALSE)
769
		{
770
			return;
771
		}
772
773
		$target_file = self::getRealPath($target_file);
774
		if(!$resize_width)
775
		{
776
			$resize_width = 100;
777
		}
778
779
		if(!$resize_height)
780
		{
781
			$resize_height = $resize_width;
782
		}
783
784
		// retrieve source image's information
785
		$imageInfo = getimagesize($source_file);
786
		if(!self::checkMemoryLoadImage($imageInfo))
787
		{
788
			return FALSE;
789
		}
790
791
		list($width, $height, $type, $attrs) = $imageInfo;
0 ignored issues
show
Unused Code introduced by
The assignment to $attrs is unused. Consider omitting it like so list($first,,$third).

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

Consider the following code example.

<?php

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

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

print $a . " - " . $c;

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

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
792
		if($width < 1 || $height < 1)
793
		{
794
			return;
795
		}
796
797
		switch($type)
798
		{
799
			case '1' :
800
				$type = 'gif';
801
				break;
802
			case '2' :
803
				$type = 'jpg';
804
				break;
805
			case '3' :
806
				$type = 'png';
807
				break;
808
			case '6' :
809
				$type = 'bmp';
810
				break;
811
			default :
812
				return;
813
		}
814
815
		if(!$target_type)
816
		{
817
			$target_type = $type;
818
		}
819
		$target_type = strtolower($target_type);
820
821
		// if original image is larger than specified size to resize, calculate the ratio
822
		$width_per = ($resize_width > 0 && $width >= $resize_width) ? $resize_width / $width : 1;
823
		$height_per = ($resize_height > 0 && $height >= $resize_height) ? $resize_height / $height : 1;
824
825
		$per = NULL;
0 ignored issues
show
Unused Code introduced by
$per 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...
826
		if($thumbnail_type == 'ratio')
827
		{
828
			$per = ($width_per > $height_per) ? $height_per : $width_per;
829
			$resize_width = $width * $per;
830
			$resize_height = $height * $per;
831
		}
832
		else
833
		{
834
			$per = ($width_per < $height_per) ? $height_per : $width_per;
835
		}
836
837
		// create temporary image with target size
838
		$thumb = NULL;
839
		if(function_exists('imagecreateTRUEcolor'))
840
		{
841
			$thumb = imagecreateTRUEcolor($resize_width, $resize_height);
842
		}
843
		else if(function_exists('imagecreate'))
844
		{
845
			$thumb = imagecreate($resize_width, $resize_height);
846
		}
847
848
		if(!$thumb)
849
		{
850
			return FALSE;
851
		}
852
853
		if(function_exists('imagecolorallocatealpha') && $target_type == 'png' && $thumbnail_transparent)
854
		{
855
			imagefill($thumb, 0, 0, imagecolorallocatealpha($thumb, 0, 0, 0, 127));
856
			
857
			if(function_exists('imagesavealpha'))
858
			{
859
				imagesavealpha($thumb, TRUE);
860
			}
861
862
			if(function_exists('imagealphablending'))
863
			{
864
				imagealphablending($thumb, TRUE);
865
			}
866
		}
867
		else
868
		{
869
			imagefilledrectangle($thumb, 0, 0, $resize_width - 1, $resize_height - 1, imagecolorallocate($thumb, 255, 255, 255));
870
		}
871
872
		// create temporary image having original type
873
		$source = NULL;
874
		switch($type)
875
		{
876
			case 'gif' :
877
				if(function_exists('imagecreatefromgif'))
878
				{
879
					$source = @imagecreatefromgif($source_file);
880
				}
881
				break;
882
			case 'jpeg' :
883
			case 'jpg' :
884
				if(function_exists('imagecreatefromjpeg'))
885
				{
886
					$source = @imagecreatefromjpeg($source_file);
887
				}
888
				break;
889
			case 'png' :
890
				if(function_exists('imagecreatefrompng'))
891
				{
892
					$source = @imagecreatefrompng($source_file);
893
				}
894
				break;
895
			case 'wbmp' :
896
			case 'bmp' :
897
				if(function_exists('imagecreatefromwbmp'))
898
				{
899
					$source = @imagecreatefromwbmp($source_file);
900
				}
901
				break;
902
		}
903
904
		if(!$source)
905
		{
906
			imagedestroy($thumb);
907
			return FALSE;
908
		}
909
910
		// resize original image and put it into temporary image
911
		$new_width = (int) ($width * $per);
912
		$new_height = (int) ($height * $per);
913
914
		$x = 0;
915
		$y = 0;
916
		if($thumbnail_type == 'crop')
917
		{
918
			$x = (int) ($resize_width / 2 - $new_width / 2);
919
			$y = (int) ($resize_height / 2 - $new_height / 2);
920
		}
921
922
		if(function_exists('imagecopyresampled'))
923
		{
924
			imagecopyresampled($thumb, $source, $x, $y, 0, 0, $new_width, $new_height, $width, $height);
925
		}
926
		else
927
		{
928
			imagecopyresized($thumb, $source, $x, $y, 0, 0, $new_width, $new_height, $width, $height);
929
		}
930
931
		// create directory
932
		self::makeDir(dirname($target_file));
933
934
		// write into the file
935
		$output = NULL;
936
		switch($target_type)
937
		{
938
			case 'gif' :
939
				if(function_exists('imagegif'))
940
				{
941
					$output = imagegif($thumb, $target_file);
942
				}
943
				break;
944
			case 'jpeg' :
945
			case 'jpg' :
946
				if(function_exists('imagejpeg'))
947
				{
948
					$output = imagejpeg($thumb, $target_file, 100);
949
				}
950
				break;
951
			case 'png' :
952
				if(function_exists('imagepng'))
953
				{
954
					$output = imagepng($thumb, $target_file, 9);
955
				}
956
				break;
957
			case 'wbmp' :
958
			case 'bmp' :
959
				if(function_exists('imagewbmp'))
960
				{
961
					$output = imagewbmp($thumb, $target_file, 100);
962
				}
963
				break;
964
		}
965
966
		imagedestroy($thumb);
967
		imagedestroy($source);
968
969
		if(!$output)
0 ignored issues
show
Bug Best Practice introduced by
The expression $output of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
970
		{
971
			return FALSE;
972
		}
973
		@chmod($target_file, 0644);
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...
974
975
		return TRUE;
976
	}
977
978
	/**
979
	 * Reads ini file, and puts result into array
980
	 *
981
	 * @see self::writeIniFile()
982
	 * @param string $filename Path of the ini file
983
	 * @return array ini array (if the target file does not exist, it returns FALSE)
984
	 */
985
	function readIniFile($filename)
986
	{
987
		if(($filename = self::exists($filename)) === FALSE)
988
		{
989
			return FALSE;
990
		}
991
		$arr = parse_ini_file($filename, TRUE);
992
		if(is_array($arr) && count($arr) > 0)
993
		{
994
			return $arr;
995
		}
996
		else
997
		{
998
			return array();
999
		}
1000
	}
1001
1002
	/**
1003
	 * Write array into ini file
1004
	 *
1005
	 * 	$ini['key1'] = 'value1';<br/>
1006
	 * 	$ini['key2'] = 'value2';<br/>
1007
	 * 	$ini['section']['key1_in_section'] = 'value1_in_section';<br/>
1008
	 * 	$ini['section']['key2_in_section'] = 'value2_in_section';<br/>
1009
	 * 	self::writeIniFile('exmple.ini', $ini);
1010
	 *
1011
	 * @see self::readIniFile()
1012
	 * @param string $filename Target ini file name
1013
	 * @param array $arr Array
1014
	 * @return bool if array contains nothing it returns FALSE, otherwise TRUE
1015
	 */
1016
	function writeIniFile($filename, $arr)
1017
	{
1018
		if(!is_array($arr) || count($arr) == 0)
1019
		{
1020
			return FALSE;
1021
		}
1022
		self::writeFile($filename, self::_makeIniBuff($arr));
1023
		return TRUE;
1024
	}
1025
1026
	/**
1027
	 * Make array to ini string
1028
	 *
1029
	 * @param array $arr Array
1030
	 * @return string
1031
	 */
1032
	function _makeIniBuff($arr)
1033
	{
1034
		$return = array();
1035
		foreach($arr as $key => $val)
1036
		{
1037
			// section
1038
			if(is_array($val))
1039
			{
1040
				$return[] = sprintf("[%s]", $key);
1041
				foreach($val as $k => $v)
1042
				{
1043
					$return[] = sprintf("%s=\"%s\"", $k, $v);
1044
				}
1045
				// value
1046
			}
1047
			else if(is_object($val))
1048
			{
1049
				continue;
1050
			}
1051
			else
1052
			{
1053
				$return[] = sprintf("%s=\"%s\"", $key, $val);
1054
			}
1055
		}
1056
1057
		return join("\n", $return);
1058
	}
1059
1060
	/**
1061
	 * Returns a file object
1062
	 *
1063
	 * If the directory of the file does not exist, create it.
1064
	 *
1065
	 * @param string $filename Target file name
1066
	 * @param string $mode File mode for fopen
1067
	 * @return FileObject File object
1068
	 */
1069
	function openFile($filename, $mode)
1070
	{
1071
		$pathinfo = pathinfo($filename);
1072
		self::makeDir($pathinfo['dirname']);
1073
1074
		require_once("FileObject.class.php");
1075
		return  new FileObject($filename, $mode);
1076
	}
1077
1078
	/**
1079
	 * Check whether the given file has the content.
1080
	 *
1081
	 * @param string $filename Target file name
1082
	 * @return bool Returns TRUE if the file exists and contains something.
1083
	 */
1084
	function hasContent($filename)
1085
	{
1086
		return (is_readable($filename) && (filesize($filename) > 0));
1087
	}
1088
1089
	/**
1090
	 * Check file exists.
1091
	 *
1092
	 * @param string $filename Target file name
1093
	 * @return bool Returns FALSE if the file does not exists, or Returns full path file(string).
1094
	 */
1095
	function exists($filename)
1096
	{
1097
		$filename = self::getRealPath($filename);
1098
		return file_exists($filename) ? $filename : FALSE;
1099
	}
1100
1101
	/**
1102
	 * Check it is dir
1103
	 *
1104
	 * @param string $dir Target dir path
0 ignored issues
show
Bug introduced by
There is no parameter named $dir. Was it maybe removed?

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

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

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

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

Loading history...
1105
	 * @return bool Returns FALSE if the dir is not dir, or Returns full path of dir(string).
1106
	 */
1107
	function isDir($path)
1108
	{
1109
		$path = self::getRealPath($path);
1110
		return is_dir($path) ? $path : FALSE;
1111
	}
1112
1113
	/**
1114
	 * Check is writable dir
1115
	 *
1116
	 * @param string $path Target dir path
1117
	 * @return bool
1118
	 */
1119
	function isWritableDir($path)
1120
	{
1121
		$path = self::getRealPath($path);
1122
		if(is_dir($path)==FALSE)
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
1123
		{
1124
			return FALSE;
1125
		}
1126
1127
		$checkFile = $path . '/_CheckWritableDir';
1128
1129
		$fp = fopen($checkFile, 'w');
1130
		if(!is_resource($fp))
1131
		{
1132
			return FALSE;
1133
		}
1134
		fclose($fp);
1135
1136
		self::removeFile($checkFile);
1137
		return TRUE;
1138
	}
1139
1140
	/**
1141
	 * Clears file status cache
1142
	 *
1143
	 * @param string|array $target filename or directory
1144
	 * @param boolean $include include files in the directory
1145
	 **/
1146
	static public function clearStatCache($target, $include = false)
1147
	{
1148
		if(is_array($target))
1149
		{
1150
			array_map('self::clearStatCache', $target);
1151
			return;
1152
		}
1153
1154
		$target = self::getRealPath($target);
1155
1156
		if($include && self::isDir($target))
0 ignored issues
show
Bug Best Practice introduced by
The expression self::isDir($target) of type string|false is loosely compared to true; 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...
1157
		{
1158
			self::clearStatCache(self::readDir($target, '', false, true), $include);
1159
		}
1160
1161
		clearstatcache(true, $target);
1162
	}
1163
1164
	/**
1165
	 * Invalidates a cached script of OPcache
1166
	 *
1167
	 * @param string|array $target filename or directory
1168
	 * @param boolean $force force
1169
	 **/
1170
	static public function invalidateOpcache($target, $force = true)
1171
	{
1172
		static $opcache = null;
1173
1174
		if($opcache === null)
1175
		{
1176
			$opcache = (function_exists('opcache_get_status') && function_exists('opcache_invalidate'));
1177
		}
1178
1179
		if($opcache === false)
1180
		{
1181
			return;
1182
		}
1183
1184
		if(is_array($target))
1185
		{
1186
			array_map('self::invalidateOpcache', $target);
1187
			return;
1188
		}
1189
1190
		if(substr($target, -4) === '.php')
1191
		{
1192
			opcache_invalidate(self::getRealPath($target), $force);
1193
		}
1194
		else if($path = self::isDir($target))
1195
		{
1196
			self::invalidateOpcache(self::readDir($path, '', false, true));
1197
		}
1198
	}
1199
}
1200
1201
/* End of file FileHandler.class.php */
1202
/* Location: ./classes/file/FileHandler.class.php */
1203