Passed
Branch php-cs-fixer (b9836a)
by Fabio
15:02
created

TTarFileExtractor   F

Complexity

Total Complexity 106

Size/Duplication

Total Lines 534
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 534
rs 1.5789
c 0
b 0
f 0
wmc 106

16 Methods

Rating   Name   Duplication   Size   Complexity  
C _openRead() 0 40 7
B _readLongHeader() 0 22 4
A _close() 0 17 3
A __destruct() 0 6 2
A extract() 0 3 1
B _translateWinPath() 0 14 6
A _isArchive() 0 7 2
A _cleanFile() 0 16 2
F _extractList() 0 205 53
A __construct() 0 3 1
B _dirCheck() 0 19 7
A _jumpBlock() 0 9 3
A extractModify() 0 12 2
C _readHeader() 0 56 10
A _error() 0 3 1
A _readBlock() 0 7 2

How to fix   Complexity   

Complex Class

Complex classes like TTarFileExtractor 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.

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 TTarFileExtractor, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * TTarFileExtractor class file
4
 *
5
 * @author Vincent Blavet <[email protected]>
6
 * @copyright Copyright &copy; 1997-2003 The PHP Group
7
 * @package Prado\IO
8
 */
9
10
namespace Prado\IO;
11
12
/* vim: set ts=4 sw=4: */
13
// +----------------------------------------------------------------------+
14
// | PHP Version 4                                                        |
15
// +----------------------------------------------------------------------+
16
// | Copyright (c) 1997-2003 The PHP Group                                |
17
// +----------------------------------------------------------------------+
18
// | This source file is subject to version 3.0 of the PHP license,       |
19
// | that is bundled with this package in the file LICENSE, and is        |
20
// | available through the world-wide-web at the following url:           |
21
// | http://www.php.net/license/3_0.txt.                                  |
22
// | If you did not receive a copy of the PHP license and are unable to   |
23
// | obtain it through the world-wide-web, please send a note to          |
24
// | [email protected] so we can mail you a copy immediately.               |
25
// +----------------------------------------------------------------------+
26
// | Author: Vincent Blavet <[email protected]>                      |
27
// +----------------------------------------------------------------------+
28
//
29
// $Id: TTarFileExtractor.php 3188 2012-07-12 12:13:23Z ctrlaltca $
30
31
/**
32
 * TTarFileExtractor class
33
 *
34
 * @author Vincent Blavet <[email protected]>
35
 * @package Prado\IO
36
 * @since 3.0
37
 */
38
class TTarFileExtractor
39
{
40
	/**
41
	 * @var string Name of the Tar
42
	 */
43
	private $_tarname = '';
44
45
	/**
46
	 * @var file descriptor
0 ignored issues
show
Bug introduced by
The type Prado\IO\file was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
47
	 */
48
	private $_file = 0;
49
50
	/**
51
	 * @var string Local Tar name of a remote Tar (http:// or ftp://)
52
	 */
53
	private $_temp_tarname = '';
54
55
	/**
56
	 * Archive_Tar Class constructor. This flavour of the constructor only
57
	 * declare a new Archive_Tar object, identifying it by the name of the
58
	 * tar file.
59
	 *
60
	 * @param    string  $p_tarname  The name of the tar archive to create
61
	 * @access public
62
	 */
63
	public function __construct($p_tarname)
64
	{
65
		$this->_tarname = $p_tarname;
66
	}
67
68
	public function __destruct()
69
	{
70
		$this->_close();
71
		// ----- Look for a local copy to delete
72
		if ($this->_temp_tarname != '')
73
			@unlink($this->_temp_tarname);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

73
			/** @scrutinizer ignore-unhandled */ @unlink($this->_temp_tarname);

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...
74
	}
75
76
	public function extract($p_path = '')
77
	{
78
		return $this->extractModify($p_path, '');
79
	}
80
81
	/**
82
	 * This method extract all the content of the archive in the directory
83
	 * indicated by $p_path. When relevant the memorized path of the
84
	 * files/dir can be modified by removing the $p_remove_path path at the
85
	 * beginning of the file/dir path.
86
	 * While extracting a file, if the directory path does not exists it is
87
	 * created.
88
	 * While extracting a file, if the file already exists it is replaced
89
	 * without looking for last modification date.
90
	 * While extracting a file, if the file already exists and is write
91
	 * protected, the extraction is aborted.
92
	 * While extracting a file, if a directory with the same name already
93
	 * exists, the extraction is aborted.
94
	 * While extracting a directory, if a file with the same name already
95
	 * exists, the extraction is aborted.
96
	 * While extracting a file/directory if the destination directory exist
97
	 * and is write protected, or does not exist but can not be created,
98
	 * the extraction is aborted.
99
	 * If after extraction an extracted file does not show the correct
100
	 * stored file size, the extraction is aborted.
101
	 * When the extraction is aborted, a PEAR error text is set and false
102
	 * is returned. However the result can be a partial extraction that may
103
	 * need to be manually cleaned.
104
	 *
105
	 * @param string $p_path         The path of the directory where the
106
	 *                               files/dir need to by extracted.
107
	 * @param string $p_remove_path  Part of the memorized path that can be
108
	 *                               removed if present at the beginning of
109
	 *                               the file/dir path.
110
	 * @return boolean               true on success, false on error.
111
	 * @access public
112
	 */
113
	protected function extractModify($p_path, $p_remove_path)
114
	{
115
		$v_result = true;
0 ignored issues
show
Unused Code introduced by
The assignment to $v_result is dead and can be removed.
Loading history...
116
		$v_list_detail = [];
117
118
		if ($v_result = $this->_openRead()) {
119
			$v_result = $this->_extractList($p_path, $v_list_detail,
120
											"complete", 0, $p_remove_path);
121
			$this->_close();
122
		}
123
124
		return $v_result;
125
	}
126
127
	protected function _error($p_message)
128
	{
129
		throw new \Exception($p_message);
130
	}
131
132
	private function _isArchive($p_filename = null)
133
	{
134
		if ($p_filename == null) {
135
			$p_filename = $this->_tarname;
136
		}
137
		clearstatcache();
138
		return @is_file($p_filename);
139
	}
140
141
	private function _openRead()
142
	{
143
		if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') {
144
145
		  // ----- Look if a local copy need to be done
146
		  if ($this->_temp_tarname == '') {
147
			  $this->_temp_tarname = uniqid('tar') . '.tmp';
148
			  if (!$v_file_from = @fopen($this->_tarname, 'rb')) {
149
				$this->_error('Unable to open in read mode \''
150
							  . $this->_tarname . '\'');
151
				$this->_temp_tarname = '';
152
				return false;
153
			  }
154
			  if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) {
155
				$this->_error('Unable to open in write mode \''
156
							  . $this->_temp_tarname . '\'');
157
				$this->_temp_tarname = '';
158
				return false;
159
			  }
160
			  while ($v_data = @fread($v_file_from, 1024))
161
				  @fwrite($v_file_to, $v_data);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for fwrite(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

161
				  /** @scrutinizer ignore-unhandled */ @fwrite($v_file_to, $v_data);

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...
162
			  @fclose($v_file_from);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for fclose(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

162
			  /** @scrutinizer ignore-unhandled */ @fclose($v_file_from);

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...
163
			  @fclose($v_file_to);
164
		  }
165
166
		  // ----- File to open if the local copy
167
		  $v_filename = $this->_temp_tarname;
168
169
		} else
170
		  // ----- File to open if the normal Tar file
171
		  $v_filename = $this->_tarname;
172
173
		$this->_file = @fopen($v_filename, "rb");
0 ignored issues
show
Documentation Bug introduced by
It seems like @fopen($v_filename, 'rb') of type resource or false is incompatible with the declared type Prado\IO\file of property $_file.

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...
174
175
		if ($this->_file == 0) {
176
			$this->_error('Unable to open in read mode \'' . $v_filename . '\'');
177
			return false;
178
		}
179
180
		return true;
181
	}
182
183
	private function _close()
184
	{
185
		//if (isset($this->_file)) {
186
		if (is_resource($this->_file))
0 ignored issues
show
introduced by
The condition is_resource($this->_file) can never be true.
Loading history...
187
		{
188
			   @fclose($this->_file);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for fclose(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

188
			   /** @scrutinizer ignore-unhandled */ @fclose($this->_file);

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...
189
			$this->_file = 0;
190
		}
191
192
		// ----- Look if a local copy need to be erase
193
		// Note that it might be interesting to keep the url for a time : ToDo
194
		if ($this->_temp_tarname != '') {
195
			@unlink($this->_temp_tarname);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

195
			/** @scrutinizer ignore-unhandled */ @unlink($this->_temp_tarname);

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...
196
			$this->_temp_tarname = '';
197
		}
198
199
		return true;
200
	}
201
202
	private function _cleanFile()
0 ignored issues
show
Unused Code introduced by
The method _cleanFile() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
203
	{
204
		$this->_close();
205
206
		// ----- Look for a local copy
207
		if ($this->_temp_tarname != '') {
208
			// ----- Remove the local copy but not the remote tarname
209
			@unlink($this->_temp_tarname);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

209
			/** @scrutinizer ignore-unhandled */ @unlink($this->_temp_tarname);

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...
210
			$this->_temp_tarname = '';
211
		} else {
212
			// ----- Remove the local tarname file
213
			@unlink($this->_tarname);
214
		}
215
		$this->_tarname = '';
216
217
		return true;
218
	}
219
220
	private function _readBlock()
221
	{
222
	  $v_block = null;
223
	  if (is_resource($this->_file)) {
0 ignored issues
show
introduced by
The condition is_resource($this->_file) can never be true.
Loading history...
224
			  $v_block = @fread($this->_file, 512);
225
	  }
226
	  return $v_block;
227
	}
228
229
	private function _jumpBlock($p_len = null)
230
	{
231
	  if (is_resource($this->_file)) {
0 ignored issues
show
introduced by
The condition is_resource($this->_file) can never be true.
Loading history...
232
		  if ($p_len === null)
233
			  $p_len = 1;
234
235
			  @fseek($this->_file, @ftell($this->_file) + ($p_len * 512));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for fseek(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

235
			  /** @scrutinizer ignore-unhandled */ @fseek($this->_file, @ftell($this->_file) + ($p_len * 512));

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...
236
	  }
237
	  return true;
238
	}
239
240
	private function _readHeader($v_binary_data, &$v_header)
241
	{
242
		if (strlen($v_binary_data) == 0) {
243
			$v_header['filename'] = '';
244
			return true;
245
		}
246
247
		if (strlen($v_binary_data) != 512) {
248
			$v_header['filename'] = '';
249
			$this->_error('Invalid block size : ' . strlen($v_binary_data));
250
			return false;
251
		}
252
253
		// ----- Calculate the checksum
254
		$v_checksum = 0;
255
		// ..... First part of the header
256
		for ($i = 0; $i < 148; $i++)
257
			$v_checksum += ord(substr($v_binary_data, $i, 1));
258
		// ..... Ignore the checksum value and replace it by ' ' (space)
259
		for ($i = 148; $i < 156; $i++)
260
			$v_checksum += ord(' ');
261
		// ..... Last part of the header
262
		for ($i = 156; $i < 512; $i++)
263
		   $v_checksum += ord(substr($v_binary_data, $i, 1));
264
265
		$v_data = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/"
266
						 . "a8checksum/a1typeflag/a100link/a6magic/a2version/"
267
						 . "a32uname/a32gname/a8devmajor/a8devminor",
268
						 $v_binary_data);
269
270
		// ----- Extract the checksum
271
		$v_header['checksum'] = OctDec(trim($v_data['checksum']));
272
		if ($v_header['checksum'] != $v_checksum) {
273
			$v_header['filename'] = '';
274
275
			// ----- Look for last block (empty block)
276
			if (($v_checksum == 256) && ($v_header['checksum'] == 0))
0 ignored issues
show
introduced by
The condition $v_checksum == 256 && $v_header['checksum'] == 0 can never be true.
Loading history...
277
				return true;
278
279
			$this->_error('Invalid checksum for file "' . $v_data['filename']
280
						  . '" : ' . $v_checksum . ' calculated, '
281
						  . $v_header['checksum'] . ' expected');
282
			return false;
283
		}
284
285
		// ----- Extract the properties
286
		$v_header['filename'] = trim($v_data['filename']);
287
		$v_header['mode'] = OctDec(trim($v_data['mode']));
288
		$v_header['uid'] = OctDec(trim($v_data['uid']));
289
		$v_header['gid'] = OctDec(trim($v_data['gid']));
290
		$v_header['size'] = OctDec(trim($v_data['size']));
291
		$v_header['mtime'] = OctDec(trim($v_data['mtime']));
292
		if (($v_header['typeflag'] = $v_data['typeflag']) == "5") {
293
		  $v_header['size'] = 0;
294
		}
295
		return true;
296
	}
297
298
	private function _readLongHeader(&$v_header)
299
	{
300
	  $v_filename = '';
301
	  $n = floor($v_header['size'] / 512);
302
	  for ($i = 0; $i < $n; $i++) {
303
		$v_content = $this->_readBlock();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $v_content is correct as $this->_readBlock() targeting Prado\IO\TTarFileExtractor::_readBlock() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
304
		$v_filename .= $v_content;
305
	  }
306
	  if (($v_header['size'] % 512) != 0) {
307
		$v_content = $this->_readBlock();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $v_content is correct as $this->_readBlock() targeting Prado\IO\TTarFileExtractor::_readBlock() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
308
		$v_filename .= $v_content;
309
	  }
310
311
	  // ----- Read the next header
312
	  $v_binary_data = $this->_readBlock();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $v_binary_data is correct as $this->_readBlock() targeting Prado\IO\TTarFileExtractor::_readBlock() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
313
314
	  if (!$this->_readHeader($v_binary_data, $v_header))
315
		return false;
316
317
	  $v_header['filename'] = $v_filename;
318
319
	  return true;
320
	}
321
322
	protected function _extractList($p_path, &$p_list_detail, $p_mode,
323
						  $p_file_list, $p_remove_path)
324
	{
325
	$v_result = true;
0 ignored issues
show
Unused Code introduced by
The assignment to $v_result is dead and can be removed.
Loading history...
326
	$v_nb = 0;
327
	$v_extract_all = true;
328
	$v_listing = false;
329
330
	$p_path = $this->_translateWinPath($p_path, false);
331
	if ($p_path == '' || (substr($p_path, 0, 1) != '/'
332
		&& substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))) {
333
	  $p_path = "./" . $p_path;
334
	}
335
	$p_remove_path = $this->_translateWinPath($p_remove_path);
336
337
	// ----- Look for path to remove format (should end by /)
338
	if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/'))
339
	  $p_remove_path .= '/';
340
	$p_remove_path_size = strlen($p_remove_path);
341
342
	switch ($p_mode) {
343
	  case "complete" :
344
		$v_extract_all = true;
345
		$v_listing = false;
346
	  break;
347
	  case "partial" :
348
		  $v_extract_all = false;
349
		  $v_listing = false;
350
	  break;
351
	  case "list" :
352
		  $v_extract_all = false;
353
		  $v_listing = true;
354
	  break;
355
	  default :
356
		$this->_error('Invalid extract mode (' . $p_mode . ')');
357
		return false;
358
	}
359
360
	clearstatcache();
361
362
	while (strlen($v_binary_data = $this->_readBlock()) != 0)
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $v_binary_data is correct as $this->_readBlock() targeting Prado\IO\TTarFileExtractor::_readBlock() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
363
	{
364
	  $v_extract_file = false;
365
	  $v_extraction_stopped = 0;
366
367
	  if (!$this->_readHeader($v_binary_data, $v_header))
368
		return false;
369
370
	  if ($v_header['filename'] == '') {
371
		continue;
372
	  }
373
374
	  // ----- Look for long filename
375
	  if ($v_header['typeflag'] == 'L') {
376
		if (!$this->_readLongHeader($v_header))
377
		  return false;
378
	  }
379
380
	  if ((!$v_extract_all) && (is_array($p_file_list))) {
381
		// ----- By default no unzip if the file is not found
382
		$v_extract_file = false;
383
384
		for ($i = 0; $i < count($p_file_list); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
385
		  // ----- Look if it is a directory
386
		  if (substr($p_file_list[$i], -1) == '/') {
387
			// ----- Look if the directory is in the filename path
388
			if ((strlen($v_header['filename']) > strlen($p_file_list[$i]))
389
				&& (substr($v_header['filename'], 0, strlen($p_file_list[$i]))
390
					== $p_file_list[$i])) {
391
			  $v_extract_file = true;
392
			  break;
393
			}
394
		  }
395
396
		  // ----- It is a file, so compare the file names
397
		  elseif ($p_file_list[$i] == $v_header['filename']) {
398
			$v_extract_file = true;
399
			break;
400
		  }
401
		}
402
	  } else {
403
		$v_extract_file = true;
404
	  }
405
406
	  // ----- Look if this file need to be extracted
407
	  if (($v_extract_file) && (!$v_listing))
408
	  {
409
		if (($p_remove_path != '')
410
			&& (substr($v_header['filename'], 0, $p_remove_path_size)
411
				== $p_remove_path))
412
		  $v_header['filename'] = substr($v_header['filename'],
413
										 $p_remove_path_size);
414
		if (($p_path != './') && ($p_path != '/')) {
415
		  while (substr($p_path, -1) == '/')
416
			$p_path = substr($p_path, 0, strlen($p_path) - 1);
417
418
		  if (substr($v_header['filename'], 0, 1) == '/')
419
			  $v_header['filename'] = $p_path . $v_header['filename'];
420
		  else
421
			$v_header['filename'] = $p_path . '/' . $v_header['filename'];
422
		}
423
		if (file_exists($v_header['filename'])) {
424
		  if ((@is_dir($v_header['filename']))
425
			  && ($v_header['typeflag'] == '')) {
426
			$this->_error('File ' . $v_header['filename']
427
						  . ' already exists as a directory');
428
			return false;
429
		  }
430
		  if (($this->_isArchive($v_header['filename']))
431
			  && ($v_header['typeflag'] == "5")) {
432
			$this->_error('Directory ' . $v_header['filename']
433
						  . ' already exists as a file');
434
			return false;
435
		  }
436
		  if (!is_writable($v_header['filename'])) {
437
			$this->_error('File ' . $v_header['filename']
438
						  . ' already exists and is write protected');
439
			return false;
440
		  }
441
		  if (filemtime($v_header['filename']) > $v_header['mtime']) {
442
			// To be completed : An error or silent no replace ?
443
		  }
444
		}
445
446
		// ----- Check the directory availability and create it if necessary
447
		elseif (($v_result
448
				 = $this->_dirCheck(($v_header['typeflag'] == "5"
449
									?$v_header['filename']
450
									:dirname($v_header['filename'])))) != 1) {
451
			$this->_error('Unable to create path for ' . $v_header['filename']);
452
			return false;
453
		}
454
455
		if ($v_extract_file) {
456
		  if ($v_header['typeflag'] == "5") {
457
			if (!@file_exists($v_header['filename'])) {
458
				if (!@mkdir($v_header['filename'], PRADO_CHMOD)) {
459
					$this->_error('Unable to create directory {'
460
								  . $v_header['filename'] . '}');
461
					return false;
462
				}
463
				chmod($v_header['filename'], PRADO_CHMOD);
464
			}
465
		  } else {
466
			  if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) {
467
				  $this->_error('Error while opening {' . $v_header['filename']
468
								. '} in write binary mode');
469
				  return false;
470
			  } else {
471
				  $n = floor($v_header['size'] / 512);
472
				  for ($i = 0; $i < $n; $i++) {
473
					  $v_content = $this->_readBlock();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $v_content is correct as $this->_readBlock() targeting Prado\IO\TTarFileExtractor::_readBlock() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
474
					  fwrite($v_dest_file, $v_content, 512);
0 ignored issues
show
Bug introduced by
It seems like $v_dest_file can also be of type false; however, parameter $handle of fwrite() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

474
					  fwrite(/** @scrutinizer ignore-type */ $v_dest_file, $v_content, 512);
Loading history...
475
				  }
476
			if (($v_header['size'] % 512) != 0) {
477
			  $v_content = $this->_readBlock();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $v_content is correct as $this->_readBlock() targeting Prado\IO\TTarFileExtractor::_readBlock() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
478
			  fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
479
			}
480
481
			@fclose($v_dest_file);
0 ignored issues
show
Bug introduced by
It seems like $v_dest_file can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

481
			@fclose(/** @scrutinizer ignore-type */ $v_dest_file);
Loading history...
Security Best Practice introduced by
It seems like you do not handle an error condition for fclose(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

481
			/** @scrutinizer ignore-unhandled */ @fclose($v_dest_file);

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...
482
483
			// ----- Change the file mode, mtime
484
			@touch($v_header['filename'], $v_header['mtime']);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for touch(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

484
			/** @scrutinizer ignore-unhandled */ @touch($v_header['filename'], $v_header['mtime']);

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...
485
			// To be completed
486
			//chmod($v_header[filename], DecOct($v_header[mode]));
487
		  }
488
489
		  // ----- Check the file size
490
		  clearstatcache();
491
		  if (filesize($v_header['filename']) != $v_header['size']) {
492
			  $this->_error('Extracted file ' . $v_header['filename']
493
							. ' does not have the correct file size \''
494
							. filesize($v_header['filename'])
495
							. '\' (' . $v_header['size']
496
							. ' expected). Archive may be corrupted.');
497
			  return false;
498
		  }
499
		  }
500
		} else {
501
		  $this->_jumpBlock(ceil(($v_header['size'] / 512)));
502
		}
503
	  } else {
504
		  $this->_jumpBlock(ceil(($v_header['size'] / 512)));
505
	  }
506
507
	  /* TBC : Seems to be unused ...
508
	  if ($this->_compress)
509
		$v_end_of_file = @gzeof($this->_file);
510
	  else
511
		$v_end_of_file = @feof($this->_file);
512
		*/
513
514
	  if ($v_listing || $v_extract_file || $v_extraction_stopped) {
515
		// ----- Log extracted files
516
		if (($v_file_dir = dirname($v_header['filename']))
517
			== $v_header['filename'])
518
		  $v_file_dir = '';
519
		if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == ''))
520
		  $v_file_dir = '/';
0 ignored issues
show
Unused Code introduced by
The assignment to $v_file_dir is dead and can be removed.
Loading history...
521
522
		$p_list_detail[$v_nb++] = $v_header;
523
	  }
524
	}
525
526
		return true;
527
	}
528
529
	/**
530
	 * Check if a directory exists and create it (including parent
531
	 * dirs) if not.
532
	 *
533
	 * @param string $p_dir directory to check
534
	 *
535
	 * @return bool true if the directory exists or was created
536
	 */
537
	protected function _dirCheck($p_dir)
538
	{
539
		if ((@is_dir($p_dir)) || ($p_dir == ''))
540
			return true;
541
542
		$p_parent_dir = dirname($p_dir);
543
544
		if (($p_parent_dir != $p_dir) &&
545
			($p_parent_dir != '') &&
546
			(!$this->_dirCheck($p_parent_dir)))
547
			 return false;
548
549
		if (!@mkdir($p_dir, PRADO_CHMOD)) {
550
			$this->_error("Unable to create directory '$p_dir'");
551
			return false;
552
		}
553
		chmod($p_dir, PRADO_CHMOD);
554
555
		return true;
556
	}
557
558
	protected function _translateWinPath($p_path, $p_remove_disk_letter = true)
559
	{
560
	  if (substr(PHP_OS, 0, 3) == 'WIN') {
561
		  // ----- Look for potential disk letter
562
		  if (($p_remove_disk_letter)
563
			  && (($v_position = strpos($p_path, ':')) != false)) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $v_position = strpos($p_path, ':') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
564
			  $p_path = substr($p_path, $v_position + 1);
565
		  }
566
		  // ----- Change potential windows directory separator
567
		  if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0, 1) == '\\')) {
568
			  $p_path = strtr($p_path, '\\', '/');
569
		  }
570
	  }
571
	  return $p_path;
572
	}
573
}
574