Created
February 19, 2016 16:30
-
-
Save davide-romanini/9d8e394b0c9131c9e601 to your computer and use it in GitHub Desktop.
Php unzip command wrapper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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