Skip to content

Commit 6136d0a

Browse files
committed
Tar: allow reading archive content while iterating over archive entries.
So far there was no way to read the data from a file in an archive without extracting it and extraction of a single file required rereading of a whole archive. This commit changes the yieldContents() in a way it does not skip to the next header entry before returning a current header content. A position of the next header entry is remembered instead and rewinded to only at the next next() call on the generator. This allows to read the current entry content until the next() call. For that the Tar::readCurrentEntry() method was added.
1 parent 3e51582 commit 6136d0a

File tree

1 file changed

+21
-4
lines changed

1 file changed

+21
-4
lines changed

src/Tar.php

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ class Tar extends Archive
2323
protected $memory = '';
2424
protected $closed = true;
2525
protected $writeaccess = false;
26+
protected $position = 0;
27+
protected $skipUntil = 0;
2628

2729
/**
2830
* Sets the compression to use
@@ -72,6 +74,7 @@ public function open($file)
7274
throw new ArchiveIOException('Could not open file for reading: '.$this->file);
7375
}
7476
$this->closed = false;
77+
$this->position = 0;
7578
}
7679

7780
/**
@@ -118,12 +121,23 @@ public function yieldContents()
118121
continue;
119122
}
120123

121-
$this->skipbytes(ceil($header['size'] / 512) * 512);
124+
$this->skipUntil = $this->position + ceil($header['size'] / 512) * 512;
125+
122126
yield $this->header2fileinfo($header);
127+
128+
$skip = $this->skipUntil - $this->position;
129+
if ($skip > 0) {
130+
$this->skipbytes($skip);
131+
}
123132
}
124133

125134
$this->close();
135+
}
126136

137+
public function readCurrentEntry($length = PHP_INT_MAX)
138+
{
139+
$length = min($length, $this->skipUntil - $this->position);
140+
return $this->readbytes($length);
127141
}
128142

129143
/**
@@ -439,12 +453,14 @@ public function save($file)
439453
protected function readbytes($length)
440454
{
441455
if ($this->comptype === Archive::COMPRESS_GZIP) {
442-
return @gzread($this->fh, $length);
456+
$ret = @gzread($this->fh, $length);
443457
} elseif ($this->comptype === Archive::COMPRESS_BZIP) {
444-
return @bzread($this->fh, $length);
458+
$ret = @bzread($this->fh, $length);
445459
} else {
446-
return @fread($this->fh, $length);
460+
$ret = @fread($this->fh, $length);
447461
}
462+
$this->position += strlen($ret);
463+
return $ret;
448464
}
449465

450466
/**
@@ -494,6 +510,7 @@ protected function skipbytes($bytes)
494510
} else {
495511
@fseek($this->fh, $bytes, SEEK_CUR);
496512
}
513+
$this->position += $bytes;
497514
}
498515

499516
/**

0 commit comments

Comments
 (0)