TTarFileExtractor::_cleanFile()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 8
c 0
b 0
f 0
nc 2
nop 0
dl 0
loc 16
ccs 0
cts 8
cp 0
crap 6
rs 10
1
<?php
2
3
/**
4
 * TTarFileExtractor class file
5
 *
6
 * @author Vincent Blavet <[email protected]>
7
 */
8
9
namespace Prado\IO;
10
11
use Prado\Prado;
12
13
/* vim: set ts=4 sw=4: */
14
// +----------------------------------------------------------------------+
15
// | PHP Version 4                                                        |
16
// +----------------------------------------------------------------------+
17
// | Copyright (c) 1997-2003 The PHP Group                                |
18
// +----------------------------------------------------------------------+
19
// | This source file is subject to version 3.0 of the PHP license,       |
20
// | that is bundled with this package in the file LICENSE, and is        |
21
// | available through the world-wide-web at the following url:           |
22
// | http://www.php.net/license/3_0.txt.                                  |
23
// | If you did not receive a copy of the PHP license and are unable to   |
24
// | obtain it through the world-wide-web, please send a note to          |
25
// | [email protected] so we can mail you a copy immediately.               |
26
// +----------------------------------------------------------------------+
27
// | Author: Vincent Blavet <[email protected]>                      |
28
// +----------------------------------------------------------------------+
29
//
30
// $Id: TTarFileExtractor.php 3188 2012-07-12 12:13:23Z ctrlaltca $
31
32
/**
33
 * TTarFileExtractor class
34
 *
35
 * @author Vincent Blavet <[email protected]>
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 null|resource file descriptor
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 $p_tarname  The name of the tar archive to create
61
	 * @access public
62 1
	 */
63
	public function __construct($p_tarname)
64 1
	{
65 1
		$this->_tarname = $p_tarname;
66
	}
67 1
68
	public function __destruct()
69 1
	{
70
		$this->_close();
71 1
		// ----- 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 1
		}
75
	}
76 1
77
	public function extract($p_path = '')
78 1
	{
79
		return $this->extractModify($p_path, '');
80
	}
81
82
	/**
83
	 * This method extract all the content of the archive in the directory
84
	 * indicated by $p_path. When relevant the memorized path of the
85
	 * files/dir can be modified by removing the $p_remove_path path at the
86
	 * beginning of the file/dir path.
87
	 * While extracting a file, if the directory path does not exists it is
88
	 * created.
89
	 * While extracting a file, if the file already exists it is replaced
90
	 * without looking for last modification date.
91
	 * While extracting a file, if the file already exists and is write
92
	 * protected, the extraction is aborted.
93
	 * While extracting a file, if a directory with the same name already
94
	 * exists, the extraction is aborted.
95
	 * While extracting a directory, if a file with the same name already
96
	 * exists, the extraction is aborted.
97
	 * While extracting a file/directory if the destination directory exist
98
	 * and is write protected, or does not exist but can not be created,
99
	 * the extraction is aborted.
100
	 * If after extraction an extracted file does not show the correct
101
	 * stored file size, the extraction is aborted.
102
	 * When the extraction is aborted, a PEAR error text is set and false
103
	 * is returned. However the result can be a partial extraction that may
104
	 * need to be manually cleaned.
105
	 *
106
	 * @param string $p_path         The path of the directory where the
107
	 *                               files/dir need to by extracted.
108
	 * @param string $p_remove_path  Part of the memorized path that can be
109
	 *                               removed if present at the beginning of
110
	 *                               the file/dir path.
111
	 * @return bool               true on success, false on error.
112
	 * @access public
113 1
	 */
114
	protected function extractModify($p_path, $p_remove_path)
115 1
	{
116 1
		$v_result = true;
0 ignored issues
show
Unused Code introduced by
The assignment to $v_result is dead and can be removed.
Loading history...
117
		$v_list_detail = [];
118 1
119 1
		if ($v_result = $this->_openRead()) {
120 1
			$v_result = $this->_extractList(
121 1
				$p_path,
122 1
				$v_list_detail,
123 1
				"complete",
124 1
				0,
125
				$p_remove_path
126 1
			);
127
			$this->_close();
128
		}
129 1
130
		return $v_result;
131
	}
132
133
	protected function _error($p_message)
134
	{
135
		throw new \Exception($p_message);
136
	}
137
138
	private function _isArchive($p_filename = null)
139
	{
140
		if ($p_filename == null) {
141
			$p_filename = $this->_tarname;
142
		}
143
		clearstatcache();
144
		return @is_file($p_filename);
145
	}
146 1
147
	private function _openRead()
148 1
	{
149
		if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') {
150
			// ----- Look if a local copy need to be done
151
			if ($this->_temp_tarname == '') {
152
				$this->_temp_tarname = uniqid('tar') . '.tmp';
153
				if (!$v_file_from = @fopen($this->_tarname, 'rb')) {
154
					$this->_error('Unable to open in read mode \''
155
							  . $this->_tarname . '\'');
156
					$this->_temp_tarname = '';
157
					return false;
158
				}
159
				if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) {
160
					$this->_error('Unable to open in write mode \''
161
							  . $this->_temp_tarname . '\'');
162
					$this->_temp_tarname = '';
163
					return false;
164
				}
165
				while ($v_data = @fread($v_file_from, 1024)) {
166
					@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

166
					/** @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...
167
				}
168
				@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

168
				/** @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...
169
				@fclose($v_file_to);
170
			}
171
172
			// ----- File to open if the local copy
173
			$v_filename = $this->_temp_tarname;
174
		} else {
175
			// ----- File to open if the normal Tar file
176 1
			$v_filename = $this->_tarname;
177
		}
178
179 1
		$this->_file = @fopen($v_filename, "rb");
0 ignored issues
show
Documentation Bug introduced by
It seems like @fopen($v_filename, 'rb') can also be of type false. However, the property $_file is declared as type null|resource. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
180
181 1
		if ($this->_file == 0) {
182
			$this->_error('Unable to open in read mode \'' . $v_filename . '\'');
183
			return false;
184
		}
185
186 1
		return true;
187
	}
188
189 1
	private function _close()
190
	{
191
		//if (isset($this->_file)) {
192 1
		if (is_resource($this->_file)) {
193 1
			@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

193
			/** @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...
194 1
			$this->_file = 0;
0 ignored issues
show
Documentation Bug introduced by
It seems like 0 of type integer is incompatible with the declared type null|resource 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...
195
		}
196
197
		// ----- Look if a local copy need to be erase
198
		// Note that it might be interesting to keep the url for a time : ToDo
199 1
		if ($this->_temp_tarname != '') {
200
			@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

200
			/** @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...
201
			$this->_temp_tarname = '';
202
		}
203
204 1
		return true;
205
	}
206
207
	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...
208
	{
209
		$this->_close();
210
211
		// ----- Look for a local copy
212
		if ($this->_temp_tarname != '') {
213
			// ----- Remove the local copy but not the remote tarname
214
			@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

214
			/** @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...
215
			$this->_temp_tarname = '';
216
		} else {
217
			// ----- Remove the local tarname file
218
			@unlink($this->_tarname);
219
		}
220
		$this->_tarname = '';
221
222
		return true;
223
	}
224
225 1
	private function _readBlock()
226
	{
227 1
		$v_block = null;
228 1
		if (is_resource($this->_file)) {
229 1
			$v_block = @fread($this->_file, 512);
230
		}
231 1
		return $v_block;
232
	}
233
234
	private function _jumpBlock($p_len = null)
235
	{
236
		if (is_resource($this->_file)) {
237
			if ($p_len === null) {
238
				$p_len = 1;
239
			}
240
241
			@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

241
			/** @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...
242
		}
243
		return true;
244
	}
245
246 1
	private function _readHeader($v_binary_data, &$v_header)
247
	{
248 1
		if (strlen($v_binary_data) == 0) {
249
			$v_header['filename'] = '';
250
			return true;
251
		}
252
253 1
		if (strlen($v_binary_data) != 512) {
254
			$v_header['filename'] = '';
255
			$this->_error('Invalid block size : ' . strlen($v_binary_data));
256
			return false;
257
		}
258
259
		// ----- Calculate the checksum
260 1
		$v_checksum = 0;
261
		// ..... First part of the header
262 1
		for ($i = 0; $i < 148; $i++) {
263 1
			$v_checksum += ord(substr($v_binary_data, $i, 1));
264
		}
265
		// ..... Ignore the checksum value and replace it by ' ' (space)
266 1
		for ($i = 148; $i < 156; $i++) {
267 1
			$v_checksum += ord(' ');
268
		}
269
		// ..... Last part of the header
270 1
		for ($i = 156; $i < 512; $i++) {
271 1
			$v_checksum += ord(substr($v_binary_data, $i, 1));
272
		}
273
274 1
		$v_data = unpack(
275
			"a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/"
276
						 . "a8checksum/a1typeflag/a100link/a6magic/a2version/"
277 1
						 . "a32uname/a32gname/a8devmajor/a8devminor",
278 1
			$v_binary_data
279
		);
280
281
		// ----- Extract the checksum
282 1
		$v_header['checksum'] = OctDec(trim($v_data['checksum']));
283 1
		if ($v_header['checksum'] != $v_checksum) {
284 1
			$v_header['filename'] = '';
285
286
			// ----- Look for last block (empty block)
287 1
			if (($v_checksum == 256) && ($v_header['checksum'] == 0)) {
0 ignored issues
show
introduced by
The condition $v_checksum == 256 is always false.
Loading history...
288 1
				return true;
289
			}
290
291
			$this->_error('Invalid checksum for file "' . $v_data['filename']
292
						  . '" : ' . $v_checksum . ' calculated, '
293
						  . $v_header['checksum'] . ' expected');
294
			return false;
295
		}
296
297
		// ----- Extract the properties
298 1
		$v_header['filename'] = trim($v_data['filename']);
299 1
		$v_header['mode'] = OctDec(trim($v_data['mode']));
300 1
		$v_header['uid'] = OctDec(trim($v_data['uid']));
301 1
		$v_header['gid'] = OctDec(trim($v_data['gid']));
302 1
		$v_header['size'] = OctDec(trim($v_data['size']));
303 1
		$v_header['mtime'] = OctDec(trim($v_data['mtime']));
304 1
		if (($v_header['typeflag'] = $v_data['typeflag']) == "5") {
305 1
			$v_header['size'] = 0;
306
		}
307 1
		return true;
308
	}
309
310
	private function _readLongHeader(&$v_header)
311
	{
312
		$v_filename = '';
313
		$n = floor($v_header['size'] / 512);
314
		for ($i = 0; $i < $n; $i++) {
315
			$v_content = $this->_readBlock();
316
			$v_filename .= $v_content;
317
		}
318
		if (($v_header['size'] % 512) != 0) {
319
			$v_content = $this->_readBlock();
320
			$v_filename .= $v_content;
321
		}
322
323
		// ----- Read the next header
324
		$v_binary_data = $this->_readBlock();
325
326
		if (!$this->_readHeader($v_binary_data, $v_header)) {
327
			return false;
328
		}
329
330
		$v_header['filename'] = $v_filename;
331
332
		return true;
333
	}
334
335 1
	protected function _extractList(
336
		$p_path,
337
		&$p_list_detail,
338
		$p_mode,
339
		$p_file_list,
340
		$p_remove_path
341
	) {
342 1
		$v_result = true;
0 ignored issues
show
Unused Code introduced by
The assignment to $v_result is dead and can be removed.
Loading history...
343 1
		$v_nb = 0;
344 1
		$v_extract_all = true;
345 1
		$v_listing = false;
346
347 1
		$p_path = $this->_translateWinPath($p_path, false);
348 1
		if ($p_path == '' || (substr($p_path, 0, 1) != '/'
349 1
		&& substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))) {
350
			$p_path = "./" . $p_path;
351
		}
352 1
		$p_remove_path = $this->_translateWinPath($p_remove_path);
353
354
		// ----- Look for path to remove format (should end by /)
355 1
		if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/')) {
356
			$p_remove_path .= '/';
357
		}
358 1
		$p_remove_path_size = strlen($p_remove_path);
359
360
		switch ($p_mode) {
361 1
			case "complete":
362 1
				$v_extract_all = true;
363 1
				$v_listing = false;
364 1
				break;
365
			case "partial":
366
				$v_extract_all = false;
367
				$v_listing = false;
368
				break;
369
			case "list":
370
				$v_extract_all = false;
371
				$v_listing = true;
372
				break;
373
			default:
374
				$this->_error('Invalid extract mode (' . $p_mode . ')');
375
				return false;
376
		}
377
378 1
		clearstatcache();
379
380 1
		while (strlen($v_binary_data = $this->_readBlock()) != 0) {
0 ignored issues
show
Bug introduced by
It seems like $v_binary_data = $this->_readBlock() can also be of type false and null; however, parameter $string of strlen() does only seem to accept string, 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

380
		while (strlen(/** @scrutinizer ignore-type */ $v_binary_data = $this->_readBlock()) != 0) {
Loading history...
381 1
			$v_extract_file = false;
382 1
			$v_extraction_stopped = 0;
383
384 1
			if (!$this->_readHeader($v_binary_data, $v_header)) {
385
				return false;
386
			}
387
388 1
			if ($v_header['filename'] == '') {
389 1
				continue;
390
			}
391
392
			// ----- Look for long filename
393 1
			if ($v_header['typeflag'] == 'L') {
394
				if (!$this->_readLongHeader($v_header)) {
395
					return false;
396
				}
397
			}
398
399 1
			if ((!$v_extract_all) && (is_array($p_file_list))) {
400
				// ----- By default no unzip if the file is not found
401
				$v_extract_file = false;
402
403
				$p_file_list_count = count($p_file_list);
404
				for ($i = 0; $i < $p_file_list_count; $i++) {
405
					// ----- Look if it is a directory
406
					if (substr($p_file_list[$i], -1) == '/') {
407
						// ----- Look if the directory is in the filename path
408
						if ((strlen($v_header['filename']) > strlen($p_file_list[$i]))
409
				&& (substr($v_header['filename'], 0, strlen($p_file_list[$i]))
410
					== $p_file_list[$i])) {
411
							$v_extract_file = true;
412
							break;
413
						}
414
					}
415
416
					// ----- It is a file, so compare the file names
417
					elseif ($p_file_list[$i] == $v_header['filename']) {
418
						$v_extract_file = true;
419
						break;
420
					}
421
				}
422 1
			} else {
423
				$v_extract_file = true;
424
			}
425
426 1
			// ----- Look if this file need to be extracted
427 1
			if (($v_extract_file) && (!$v_listing)) {
428
				if (($p_remove_path != '')
429 1
			&& (substr($v_header['filename'], 0, $p_remove_path_size)
430
				== $p_remove_path)) {
431
					$v_header['filename'] = substr(
432
						$v_header['filename'],
433
						$p_remove_path_size
434
					);
435 1
				}
436 1
				if (($p_path != './') && ($p_path != '/')) {
437
					while (substr($p_path, -1) == '/') {
438
						$p_path = substr($p_path, 0, strlen($p_path) - 1);
439
					}
440 1
441
					if (substr($v_header['filename'], 0, 1) == '/') {
442
						$v_header['filename'] = $p_path . $v_header['filename'];
443 1
					} else {
444
						$v_header['filename'] = $p_path . '/' . $v_header['filename'];
445
					}
446 1
				}
447
				if (file_exists($v_header['filename'])) {
448
					if ((@is_dir($v_header['filename']))
449
			  && ($v_header['typeflag'] == '')) {
450
						$this->_error('File ' . $v_header['filename']
451
						  . ' already exists as a directory');
452
						return false;
453
					}
454
					if (($this->_isArchive($v_header['filename']))
455
			  && ($v_header['typeflag'] == "5")) {
456
						$this->_error('Directory ' . $v_header['filename']
457
						  . ' already exists as a file');
458
						return false;
459
					}
460
					if (!is_writable($v_header['filename'])) {
461
						$this->_error('File ' . $v_header['filename']
462
						  . ' already exists and is write protected');
463
						return false;
464
					}
465
					if (filemtime($v_header['filename']) > $v_header['mtime']) {
466
						// To be completed : An error or silent no replace ?
467
					}
468
				}
469
470
				// ----- Check the directory availability and create it if necessary
471 1
				elseif (($v_result
472 1
				 = $this->_dirCheck(($v_header['typeflag'] == "5"
473 1
									? $v_header['filename']
474
									: dirname($v_header['filename'])))) != 1) {
475
					$this->_error('Unable to create path for ' . $v_header['filename']);
476
					return false;
477
				}
478 1
479 1
				if ($v_extract_file) {
480 1
					if ($v_header['typeflag'] == "5") {
481
						if (!@file_exists($v_header['filename'])) {
482
							if (!@mkdir($v_header['filename'], Prado::getDefaultDirPermissions())) {
483
								$this->_error('Unable to create directory {'
484
								  . $v_header['filename'] . '}');
485
								return false;
486 1
							}
487
							chmod($v_header['filename'], Prado::getDefaultDirPermissions());
488
						}
489 1
					} else {
490
						if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) {
491
							$this->_error('Error while opening {' . $v_header['filename']
492
								. '} in write binary mode');
493
							return false;
494 1
						} else {
495 1
							$n = floor($v_header['size'] / 512);
496 1
							for ($i = 0; $i < $n; $i++) {
497 1
								$v_content = $this->_readBlock();
498
								fwrite($v_dest_file, $v_content, 512);
0 ignored issues
show
Bug introduced by
It seems like $v_content can also be of type false and null; however, parameter $data of fwrite() does only seem to accept string, 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

498
								fwrite($v_dest_file, /** @scrutinizer ignore-type */ $v_content, 512);
Loading history...
Bug introduced by
It seems like $v_dest_file can also be of type false; however, parameter $stream 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

498
								fwrite(/** @scrutinizer ignore-type */ $v_dest_file, $v_content, 512);
Loading history...
499 1
							}
500 1
							if (($v_header['size'] % 512) != 0) {
501 1
								$v_content = $this->_readBlock();
502
								fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
503
							}
504 1
505
							@fclose($v_dest_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

505
							/** @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...
Bug introduced by
It seems like $v_dest_file can also be of type false; however, parameter $stream 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

505
							@fclose(/** @scrutinizer ignore-type */ $v_dest_file);
Loading history...
506
507 1
							// ----- Change the file mode, mtime
508
							@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

508
							/** @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...
509
							// To be completed
510
							//chmod($v_header[filename], DecOct($v_header[mode]));
511
						}
512
513 1
						// ----- Check the file size
514 1
						clearstatcache();
515
						if (filesize($v_header['filename']) != $v_header['size']) {
516
							$this->_error('Extracted file ' . $v_header['filename']
517
							. ' does not have the correct file size \''
518
							. filesize($v_header['filename'])
519
							. '\' (' . $v_header['size']
520 1
							. ' expected). Archive may be corrupted.');
521
							return false;
522
						}
523
					}
524 1
				} else {
525
					$this->_jumpBlock(ceil(($v_header['size'] / 512)));
526
				}
527
			} else {
528
				$this->_jumpBlock(ceil(($v_header['size'] / 512)));
529
			}
530
531
			/* TBC : Seems to be unused ...
532
			if ($this->_compress)
533
		$v_end_of_file = @gzeof($this->_file);
534
			else
535
		$v_end_of_file = @feof($this->_file);
536
		*/
537 1
538
			if ($v_listing || $v_extract_file || $v_extraction_stopped) {
539 1
				// ----- Log extracted files
540 1
				if (($v_file_dir = dirname($v_header['filename']))
541
			== $v_header['filename']) {
542
					$v_file_dir = '';
543 1
				}
544
				if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == '')) {
545
					$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...
546
				}
547 1
548
				$p_list_detail[$v_nb++] = $v_header;
549
			}
550
		}
551 1
552
		return true;
553
	}
554
555
	/**
556
	 * Check if a directory exists and create it (including parent
557
	 * dirs) if not.
558
	 *
559
	 * @param string $p_dir directory to check
560
	 *
561
	 * @return bool true if the directory exists or was created
562 1
	 */
563
	protected function _dirCheck($p_dir)
564 1
	{
565 1
		if ((@is_dir($p_dir)) || ($p_dir == '')) {
566
			return true;
567
		}
568 1
569
		$p_parent_dir = dirname($p_dir);
570 1
571 1
		if (($p_parent_dir != $p_dir) &&
572 1
			($p_parent_dir != '') &&
573
			(!$this->_dirCheck($p_parent_dir))) {
574
			return false;
575
		}
576 1
577
		if (!@mkdir($p_dir, Prado::getDefaultDirPermissions())) {
578
			$this->_error("Unable to create directory '$p_dir'");
579
			return false;
580 1
		}
581
		chmod($p_dir, Prado::getDefaultDirPermissions());
582 1
583
		return true;
584
	}
585 1
586
	protected function _translateWinPath($p_path, $p_remove_disk_letter = true)
587 1
	{
588
		if (substr(PHP_OS, 0, 3) == 'WIN') {
589
			// ----- Look for potential disk letter
590
			if (($p_remove_disk_letter)
591
			  && (($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...
592
				$p_path = substr($p_path, $v_position + 1);
593
			}
594
			// ----- Change potential windows directory separator
595
			if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0, 1) == '\\')) {
596
				$p_path = strtr($p_path, '\\', '/');
597
			}
598 1
		}
599
		return $p_path;
600
	}
601
}
602