<?php
|
|
namespace PhpZip\Model\Data;
|
|
use PhpZip\Model\ZipData;
|
use PhpZip\Model\ZipEntry;
|
use PhpZip\ZipFile;
|
|
/**
|
* The class contains a streaming resource with new content added to the ZIP archive.
|
*/
|
class ZipNewData implements ZipData
|
{
|
/**
|
* A static variable allows closing the stream in the destructor
|
* only if it is its sole holder.
|
*
|
* @var array<int, int> array of resource ids and the number of class clones
|
*/
|
private static $guardClonedStream = [];
|
|
/** @var ZipEntry */
|
private $zipEntry;
|
|
/** @var resource */
|
private $stream;
|
|
/**
|
* ZipStringData constructor.
|
*
|
* @param ZipEntry $zipEntry
|
* @param string|resource $data
|
*/
|
public function __construct(ZipEntry $zipEntry, $data)
|
{
|
$this->zipEntry = $zipEntry;
|
|
if (\is_string($data)) {
|
$zipEntry->setUncompressedSize(\strlen($data));
|
|
if (!($handle = fopen('php://temp', 'w+b'))) {
|
// @codeCoverageIgnoreStart
|
throw new \RuntimeException('A temporary resource cannot be opened for writing.');
|
// @codeCoverageIgnoreEnd
|
}
|
fwrite($handle, $data);
|
rewind($handle);
|
$this->stream = $handle;
|
} elseif (\is_resource($data)) {
|
$this->stream = $data;
|
}
|
|
$resourceId = (int) $this->stream;
|
self::$guardClonedStream[$resourceId] =
|
isset(self::$guardClonedStream[$resourceId]) ?
|
self::$guardClonedStream[$resourceId] + 1 :
|
0;
|
}
|
|
/**
|
* @return resource returns stream data
|
*/
|
public function getDataAsStream()
|
{
|
if (!\is_resource($this->stream)) {
|
throw new \LogicException(sprintf('Resource has been closed (entry=%s).', $this->zipEntry->getName()));
|
}
|
|
return $this->stream;
|
}
|
|
/**
|
* @return string returns data as string
|
*/
|
public function getDataAsString()
|
{
|
$stream = $this->getDataAsStream();
|
$pos = ftell($stream);
|
|
try {
|
rewind($stream);
|
|
return stream_get_contents($stream);
|
} finally {
|
fseek($stream, $pos);
|
}
|
}
|
|
/**
|
* @param resource $outStream
|
*/
|
public function copyDataToStream($outStream)
|
{
|
$stream = $this->getDataAsStream();
|
rewind($stream);
|
stream_copy_to_stream($stream, $outStream);
|
}
|
|
/**
|
* @see https://php.net/manual/en/language.oop5.cloning.php
|
*/
|
public function __clone()
|
{
|
$resourceId = (int) $this->stream;
|
self::$guardClonedStream[$resourceId] =
|
isset(self::$guardClonedStream[$resourceId]) ?
|
self::$guardClonedStream[$resourceId] + 1 :
|
1;
|
}
|
|
/**
|
* The stream will be closed when closing the zip archive.
|
*
|
* The method implements protection against closing the stream of the cloned object.
|
*
|
* @see ZipFile::close()
|
*/
|
public function __destruct()
|
{
|
$resourceId = (int) $this->stream;
|
|
if (isset(self::$guardClonedStream[$resourceId]) && self::$guardClonedStream[$resourceId] > 0) {
|
self::$guardClonedStream[$resourceId]--;
|
|
return;
|
}
|
|
if (\is_resource($this->stream)) {
|
fclose($this->stream);
|
}
|
}
|
}
|