Skip to content

Instantly share code, notes, and snippets.

@davide-romanini
Created February 19, 2016 16:30
Show Gist options
  • Save davide-romanini/9d8e394b0c9131c9e601 to your computer and use it in GitHub Desktop.
Save davide-romanini/9d8e394b0c9131c9e601 to your computer and use it in GitHub Desktop.
Php unzip command wrapper
<?php
class Psr7PipeWrapper implements \Psr\Http\Message\StreamInterface
{
/**
*
* @var resource
*/
private $process;
/**
*
* @var resource
*/
private $pipe;
private $size;
public function __construct($process, $pipe, $size)
{
$this->process = $process;
$this->pipe = $pipe;
$this->size = $size;
}
public function __toString()
{
return stream_get_contents($this->pipe);
}
public function close()
{
fclose($this->pipe);
proc_close($this->process);
}
public function detach()
{
throw new \Exception("unsupported");
}
public function eof()
{
return feof($this->pipe);
}
public function getContents()
{
return stream_get_contents($this->pipe);
}
public function getMetadata($key = null)
{
return null;
}
public function getSize()
{
return $this->size;
}
public function isReadable()
{
return is_resource($this->pipe);
}
public function isSeekable()
{
return false;
}
public function isWritable()
{
return false;
}
public function read($length)
{
return fread($this->pipe, $length);
}
public function rewind()
{
throw new \RuntimeException("Not seekable");
}
public function seek($offset, $whence = SEEK_SET)
{
return fseek($this->pipe, $offset, $whence);
}
public function tell()
{
return ftell($this->pipe);
}
public function write($string)
{
throw new \RuntimeException("Not writeable");
}
}
/**
* Usa il comando unzip tramite Symfony Process
* Interfaccia limitata al listing e accesso stream ai singoli file.
*
* @author davide
*/
class UnzipWrapper
{
private $filename;
private $files = [];
public function __construct($filename)
{
$this->filename = $filename;
$process = \Symfony\Component\Process\ProcessBuilder::create()
->add('unzip')
->add('-v')
->add($filename)
->getProcess();
$process->run();
if (!$process->isSuccessful()) {
throw new \Symfony\Component\Process\Exception\ProcessFailedException($process);
}
$filelist = $process->getOutput();
$this->files = $this->parseList($filelist);
}
protected function parseList($filelist)
{
$list = [];
// Archive: xxxx.zip
// Length Method Size Cmpr Date Time CRC-32 Name
// -------- ------ ------- ---- ---------- ----- -------- ----
// 12166865 Defl:N 8985163 26% 2009-04-08 20:46 9bfcdff1 my/file/path
//
$lines = explode("\n", $filelist);
// ignore first line
array_shift($lines);
// fields on the second
$fields = preg_split("/\s+/", trim(array_shift($lines)), 8);
// ignore separator
array_shift($lines);
// real list
while (substr($line = array_shift($lines), 0, 1) != '-') {
$splitted = preg_split("/\s+/", trim($line), 8);
$list[$splitted[7]] = array_combine($fields, $splitted);
};
return $list;
}
public function listNames()
{
return array_keys($this->files);
}
public function getStream($name)
{
if (!isset($this->files[$name])) {
throw new \Exception("File $name not present in archive");
}
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"),
2 => array("pipe", "w")
);
$process = proc_open("unzip -p " . escapeshellarg($this->filename) . " " . escapeshellarg($name), $descriptorspec, $pipes);
if (is_resource($process)) {
stream_set_blocking($pipes[2], 0);
$err = stream_get_contents($pipes[2]);
if ($err != null) {
proc_close($process);
throw new \Exception($err);
}
return new Psr7PipeWrapper($process, $pipes[1], $this->files[$name]["Size"]);
}
throw new \Exception("Cannot create process");
}
public static function registerWrapper()
{
stream_wrapper_register("zip64", "Zip64StreamWrapper");
}
}
class Zip64StreamWrapper
{
/**
*
* @var Psr\Http\Message\StreamInterface
*/
private $stream;
private $zipFilename;
function stream_open($path, $mode, $options, &$opened_path)
{
$parts = explode('#', $path);
list($zip, $filename) = $parts;
$zip = str_replace('zip64://', '', $zip);
if (!$zip && !$filename) {
return false;
}
$z = new UnzipWrapper($zip);
$this->stream = $z->getStream($filename);
$this->zipFilename = $zip;
return true;
}
function stream_read($count)
{
return $this->stream->read($count);
}
function stream_write($data)
{
return $this->stream->write($data);
}
function stream_tell()
{
return $this->stream->tell();
}
function stream_eof()
{
return $this->stream->eof();
}
function stream_seek($offset, $whence)
{
return $this->stream->seek($offset, $whence);
}
function stream_metadata($path, $option, $var)
{
return null;
}
function url_stat ($path, $flags)
{
$parts = explode('#', $path);
list($zip, $filename) = $parts;
$zip = str_replace('zip64://', '', $zip);
if (!$zip && !$filename) {
return false;
}
$f = fopen($zip, 'r');
$ret = fstat($f);
fclose($f);
return $ret;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment