Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Tar.php
Go to the documentation of this file.
1 <?php
13 
15 
16 class Tar extends \Magento\Framework\Archive\AbstractArchive implements \Magento\Framework\Archive\ArchiveInterface
17 {
23  const TAR_BLOCK_SIZE = 512;
24 
30  protected $_currentFile;
31 
37  protected $_currentPath;
38 
45  protected $_skipRoot;
46 
52  protected $_writer;
53 
59  protected $_reader;
60 
67 
73  protected function _initWriter()
74  {
75  $this->_writer = new File($this->_destinationFilePath);
76  $this->_writer->open('w');
77 
78  return $this;
79  }
80 
86  protected static function _getFormatParseHeader()
87  {
88  return 'a100name/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1type/a100symlink/a6magic/a2version/' .
89  'a32uname/a32gname/a8devmajor/a8devminor/a155prefix/a12closer';
90  }
91 
97  protected function _destroyWriter()
98  {
99  if ($this->_writer instanceof File) {
100  $this->_writer->close();
101  $this->_writer = null;
102  }
103 
104  return $this;
105  }
106 
112  protected function _getWriter()
113  {
114  if (!$this->_writer) {
115  $this->_initWriter();
116  }
117 
118  return $this->_writer;
119  }
120 
126  protected function _initReader()
127  {
128  $this->_reader = new File($this->_getCurrentFile());
129  $this->_reader->open('r');
130 
131  return $this;
132  }
133 
139  protected function _destroyReader()
140  {
141  if ($this->_reader instanceof File) {
142  $this->_reader->close();
143  $this->_reader = null;
144  }
145 
146  return $this;
147  }
148 
154  protected function _getReader()
155  {
156  if (!$this->_reader) {
157  $this->_initReader();
158  }
159 
160  return $this->_reader;
161  }
162 
169  protected function _setSkipRoot($skipRoot)
170  {
171  $this->_skipRoot = $skipRoot;
172  return $this;
173  }
174 
181  protected function _setCurrentFile($file)
182  {
183  $file = str_replace('\\', '/', $file);
184  $this->_currentFile = $file . (!is_link($file) && is_dir($file) && substr($file, -1) != '/' ? '/' : '');
185  return $this;
186  }
187 
194  protected function _setDestinationFilePath($destinationFilePath)
195  {
196  $this->_destinationFilePath = $destinationFilePath;
197  return $this;
198  }
199 
205  protected function _getCurrentFile()
206  {
207  return $this->_currentFile;
208  }
209 
216  protected function _setCurrentPath($path)
217  {
218  $path = str_replace('\\', '/', $path);
219  if ($this->_skipRoot && is_dir($path)) {
220  $this->_currentPath = $path . (substr($path, -1) != '/' ? '/' : '');
221  } else {
222  $this->_currentPath = dirname($path) . '/';
223  }
224  return $this;
225  }
226 
232  protected function _getCurrentPath()
233  {
234  return $this->_currentPath;
235  }
236 
245  protected function _createTar($skipRoot = false, $finalize = false)
246  {
247  if (!$skipRoot) {
248  $this->_packAndWriteCurrentFile();
249  }
250 
251  $file = $this->_getCurrentFile();
252 
253  if (is_dir($file)) {
254  $dirFiles = scandir($file, SCANDIR_SORT_NONE);
255 
256  if (false === $dirFiles) {
257  throw new \Magento\Framework\Exception\LocalizedException(
258  new \Magento\Framework\Phrase('Can\'t scan dir: %1', [$file])
259  );
260  }
261 
262  array_shift($dirFiles);
263  /* remove './'*/
264  array_shift($dirFiles);
265  /* remove '../'*/
266 
267  foreach ($dirFiles as $item) {
268  $this->_setCurrentFile($file . $item)->_createTar();
269  }
270  }
271 
272  if ($finalize) {
273  $this->_getWriter()->write(str_repeat("\0", self::TAR_BLOCK_SIZE * 12));
274  }
275  }
276 
282  protected function _packAndWriteCurrentFile()
283  {
284  $archiveWriter = $this->_getWriter();
285  $archiveWriter->write($this->_composeHeader());
286 
287  $currentFile = $this->_getCurrentFile();
288 
289  $fileSize = 0;
290 
291  if (is_file($currentFile) && !is_link($currentFile)) {
292  $fileReader = new File($currentFile);
293  $fileReader->open('r');
294 
295  while (!$fileReader->eof()) {
296  $archiveWriter->write($fileReader->read());
297  }
298 
299  $fileReader->close();
300 
301  $fileSize = filesize($currentFile);
302  }
303 
304  $appendZerosCount = (self::TAR_BLOCK_SIZE - $fileSize % self::TAR_BLOCK_SIZE) % self::TAR_BLOCK_SIZE;
305  $archiveWriter->write(str_repeat("\0", $appendZerosCount));
306  }
307 
319  protected function _composeHeader($long = false)
320  {
321  $file = $this->_getCurrentFile();
322  $path = $this->_getCurrentPath();
323  $infoFile = stat($file);
324  $nameFile = str_replace($path, '', $file);
325  $nameFile = str_replace('\\', '/', $nameFile);
326  $packedHeader = '';
327  $longHeader = '';
328  if (!$long && strlen($nameFile) > 100) {
329  $longHeader = $this->_composeHeader(true);
330  $longHeader .= str_pad($nameFile, floor((strlen($nameFile) + 512 - 1) / 512) * 512, "\0");
331  }
332  $header = [];
333  $header['100-name'] = $long ? '././@LongLink' : substr($nameFile, 0, 100);
334  $header['8-mode'] = $long ? ' ' : str_pad(
335  substr(sprintf("%07o", $infoFile['mode']), -4),
336  6,
337  '0',
338  STR_PAD_LEFT
339  );
340  $header['8-uid'] = $long || $infoFile['uid'] == 0 ? "\0\0\0\0\0\0\0" : sprintf("%07o", $infoFile['uid']);
341  $header['8-gid'] = $long || $infoFile['gid'] == 0 ? "\0\0\0\0\0\0\0" : sprintf("%07o", $infoFile['gid']);
342  $header['12-size'] = $long ? sprintf(
343  "%011o",
344  strlen($nameFile)
345  ) : sprintf(
346  "%011o",
347  is_dir($file) ? 0 : filesize($file)
348  );
349  $header['12-mtime'] = $long ? '00000000000' : sprintf("%011o", $infoFile['mtime']);
350  $header['8-check'] = sprintf('% 8s', '');
351  $header['1-type'] = $long ? 'L' : (is_link($file) ? 2 : (is_dir($file) ? 5 : 0));
352  $header['100-symlink'] = is_link($file) ? readlink($file) : '';
353  $header['6-magic'] = 'ustar ';
354  $header['2-version'] = ' ';
355  $a = function_exists('posix_getpwuid') ? posix_getpwuid(fileowner($file)) : ['name' => ''];
356  $header['32-uname'] = $a['name'];
357  $a = function_exists('posix_getgrgid') ? posix_getgrgid(filegroup($file)) : ['name' => ''];
358  $header['32-gname'] = $a['name'];
359  $header['8-devmajor'] = '';
360  $header['8-devminor'] = '';
361  $header['155-prefix'] = '';
362  $header['12-closer'] = '';
363 
364  $packedHeader = '';
365  foreach ($header as $key => $element) {
366  $length = explode('-', $key);
367  $packedHeader .= pack('a' . $length[0], $element);
368  }
369 
370  $checksum = 0;
371  for ($i = 0; $i < 512; $i++) {
372  $checksum += ord(substr($packedHeader, $i, 1));
373  }
374  $packedHeader = substr_replace($packedHeader, sprintf("%07o", $checksum) . "\0", 148, 8);
375 
376  return $longHeader . $packedHeader;
377  }
378 
389  protected function _unpackCurrentTar($destination)
390  {
391  $archiveReader = $this->_getReader();
392  $list = [];
393 
394  while (!$archiveReader->eof()) {
395  $header = $this->_extractFileHeader();
396 
397  if (!$header) {
398  continue;
399  }
400 
401  $currentFile = $destination . $header['name'];
402  $dirname = dirname($currentFile);
403 
404  if (in_array($header['type'], ["0", chr(0), ''])) {
405  if (!file_exists($dirname)) {
406  $mkdirResult = @mkdir($dirname, 0777, true);
407 
408  if (false === $mkdirResult) {
409  throw new \Magento\Framework\Exception\LocalizedException(
410  new \Magento\Framework\Phrase('Failed to create directory %1', [$dirname])
411  );
412  }
413  }
414 
415  $this->_extractAndWriteFile($header, $currentFile);
416  $list[] = $currentFile;
417  } elseif ($header['type'] == '5') {
418  if (!file_exists($dirname)) {
419  $mkdirResult = @mkdir($currentFile, $header['mode'], true);
420 
421  if (false === $mkdirResult) {
422  throw new \Magento\Framework\Exception\LocalizedException(
423  new \Magento\Framework\Phrase('Failed to create directory %1', [$currentFile])
424  );
425  }
426  }
427  $list[] = $currentFile . '/';
428  } elseif ($header['type'] == '2') {
429  //we do not interrupt unpack process if symlink creation failed as symlinks are not so important
430  @symlink($header['symlink'], $currentFile);
431  }
432  }
433  return $list;
434  }
435 
441  protected function _extractFileHeader()
442  {
443  $archiveReader = $this->_getReader();
444 
445  $headerBlock = $archiveReader->read(self::TAR_BLOCK_SIZE);
446 
447  if (strlen($headerBlock) < self::TAR_BLOCK_SIZE) {
448  return false;
449  }
450 
451  $header = unpack(self::_getFormatParseHeader(), $headerBlock);
452 
453  $header['mode'] = octdec($header['mode']);
454  $header['uid'] = octdec($header['uid']);
455  $header['gid'] = octdec($header['gid']);
456  $header['size'] = octdec($header['size']);
457  $header['mtime'] = octdec($header['mtime']);
458  $header['checksum'] = octdec($header['checksum']);
459 
460  if ($header['type'] == "5") {
461  $header['size'] = 0;
462  }
463 
464  $checksum = 0;
465  $headerBlock = substr_replace($headerBlock, ' ', 148, 8);
466 
467  for ($i = 0; $i < 512; $i++) {
468  $checksum += ord(substr($headerBlock, $i, 1));
469  }
470 
471  $checksumOk = $header['checksum'] == $checksum;
472  if (isset($header['name']) && $checksumOk) {
473  $header['name'] = trim($header['name']);
474  if (!($header['name'] == '././@LongLink' && $header['type'] == 'L')) {
475  return $header;
476  }
477 
478  $realNameBlockSize = floor(
479  ($header['size'] + self::TAR_BLOCK_SIZE - 1) / self::TAR_BLOCK_SIZE
481  $realNameBlock = $archiveReader->read($realNameBlockSize);
482  $realName = substr($realNameBlock, 0, $header['size']);
483 
484  $headerMain = $this->_extractFileHeader();
485  $headerMain['name'] = trim($realName);
486  return $headerMain;
487  }
488 
489  return false;
490  }
491 
499  protected function _extractAndWriteFile($fileHeader, $destination)
500  {
501  $fileWriter = new File($destination);
502  $fileWriter->open('w', $fileHeader['mode']);
503 
504  $archiveReader = $this->_getReader();
505 
506  $filesize = $fileHeader['size'];
507  $bytesExtracted = 0;
508 
509  while ($filesize > $bytesExtracted && !$archiveReader->eof()) {
510  $block = $archiveReader->read(self::TAR_BLOCK_SIZE);
511  $nonExtractedBytesCount = $filesize - $bytesExtracted;
512 
513  $data = substr($block, 0, $nonExtractedBytesCount);
514  $fileWriter->write($data);
515 
516  $bytesExtracted += strlen($block);
517  }
518  }
519 
529  public function pack($source, $destination, $skipRoot = false)
530  {
531  $this->_setSkipRoot($skipRoot);
532  $source = realpath($source);
533  $tarData = $this->_setCurrentPath($source)->_setDestinationFilePath($destination)->_setCurrentFile($source);
534 
535  $this->_initWriter();
536  $this->_createTar($skipRoot, true);
537  $this->_destroyWriter();
538 
539  return $destination;
540  }
541 
549  public function unpack($source, $destination)
550  {
551  $this->_setCurrentFile($source)->_setCurrentPath($source);
552 
553  $this->_initReader();
554  $this->_unpackCurrentTar($destination);
555  $this->_destroyReader();
556 
557  return $destination;
558  }
559 
568  public function extract($file, $source, $destination)
569  {
570  $this->_setCurrentFile($source);
571  $this->_initReader();
572 
573  $archiveReader = $this->_getReader();
574  $extractedFile = '';
575 
576  while (!$archiveReader->eof()) {
577  $header = $this->_extractFileHeader();
578  if ($header['name'] == $file) {
579  $extractedFile = $destination . basename($header['name']);
580  $this->_extractAndWriteFile($header, $extractedFile);
581  break;
582  }
583 
584  if ($header['type'] != 5) {
585  $skipBytes = floor(
586  ($header['size'] + self::TAR_BLOCK_SIZE - 1) / self::TAR_BLOCK_SIZE
588  $archiveReader->read($skipBytes);
589  }
590  }
591 
592  $this->_destroyReader();
593  return $extractedFile;
594  }
595 }
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
$source
Definition: source.php:23
static _getFormatParseHeader()
Definition: Tar.php:86
$block
Definition: block.php:8
unpack($source, $destination)
Definition: Tar.php:549
_composeHeader($long=false)
Definition: Tar.php:319
_extractAndWriteFile($fileHeader, $destination)
Definition: Tar.php:499
extract($file, $source, $destination)
Definition: Tar.php:568
pack($source, $destination, $skipRoot=false)
Definition: Tar.php:529
mkdir($pathname, $mode=0777, $recursive=false, $context=null)
Definition: ioMock.php:25
_createTar($skipRoot=false, $finalize=false)
Definition: Tar.php:245
_unpackCurrentTar($destination)
Definition: Tar.php:389
$i
Definition: gallery.phtml:31
_setDestinationFilePath($destinationFilePath)
Definition: Tar.php:194
$element
Definition: element.phtml:12