Skip to content

Commit

Permalink
Merge pull request #7 from giansalex/feature/ZipArchive
Browse files Browse the repository at this point in the history
ZipArchive Decompress
  • Loading branch information
giansalex authored Aug 29, 2018
2 parents 99371cd + fa51d99 commit 2cb596e
Show file tree
Hide file tree
Showing 7 changed files with 268 additions and 50 deletions.
42 changes: 36 additions & 6 deletions src/Ws/Services/BaseSunat.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,25 @@
use Greenter\Validator\ErrorCodeProviderInterface;
use Greenter\Ws\Reader\CdrReaderInterface;
use Greenter\Ws\Reader\DomCdrReader;
use Greenter\Zip\ZipHelper;
use Greenter\Zip\CompressInterface;
use Greenter\Zip\DecompressInterface;
use Greenter\Zip\ZipFileDecompress;
use Greenter\Zip\ZipFly;

/**
* Class BaseSunat.
*/
class BaseSunat
{
/**
* @var ZipHelper
* @var CompressInterface
*/
private $zipper;
private $compressor;

/**
* @var DecompressInterface
*/
private $decompressor;

/**
* @var CdrReaderInterface
Expand Down Expand Up @@ -52,7 +60,9 @@ public function setCodeProvider(ErrorCodeProviderInterface $codeProvider)
*/
public function __construct()
{
$this->zipper = new ZipHelper();
//TODO: Inject
$this->compressor = new ZipFly();
$this->decompressor = new ZipFileDecompress();
$this->cdrReader = new DomCdrReader();
}

Expand Down Expand Up @@ -114,7 +124,7 @@ protected function getErrorFromFault(\SoapFault $fault)
*/
protected function compress($filename, $xml)
{
return $this->zipper->compress($filename, $xml);
return $this->compressor->compress($filename, $xml);
}

/**
Expand All @@ -124,7 +134,7 @@ protected function compress($filename, $xml)
*/
protected function extractResponse($zipContent)
{
$xml = $this->zipper->decompressXmlFile($zipContent);
$xml = $this->getXmlResponse($zipContent);

return $this->cdrReader->getCdrResponse($xml);
}
Expand All @@ -142,4 +152,24 @@ protected function getMessageError($code)

return $this->codeProvider->getValue($code);
}

private function getXmlResponse($content)
{
$filter = function ($filename) {
return strtolower($this->getFileExtension($filename)) === 'xml';
};
$files = $this->decompressor->decompress($content, $filter);

return count($files) === 0 ? '' : $files[0]['content'];
}

private function getFileExtension($filename)
{
$lastDotPos = strrpos($filename, '.');
if (!$lastDotPos) {
return '';
}

return substr($filename, $lastDotPos + 1);
}
}
24 changes: 24 additions & 0 deletions src/Zip/CompressInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php
/**
* Created by PhpStorm.
* User: LPALQUILER-11
* Date: 24/08/2018
* Time: 17:37
*/

namespace Greenter\Zip;

/**
* Interface CompressInterface
*/
interface CompressInterface
{
/**
* Compress File.
*
* @param string $filename
* @param string $content
* @return string
*/
public function compress($filename, $content);
}
24 changes: 24 additions & 0 deletions src/Zip/DecompressInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php
/**
* Created by PhpStorm.
* User: LPALQUILER-11
* Date: 24/08/2018
* Time: 17:40
*/

namespace Greenter\Zip;

/**
* Interface DecompressInterface
*/
interface DecompressInterface
{
/**
* Extract files.
*
* @param string $content
* @param callable|null $filter
* @return array
*/
public function decompress($content, callable $filter = null);
}
56 changes: 56 additions & 0 deletions src/Zip/ZipFileDecompress.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php
/**
* Created by PhpStorm.
* User: LPALQUILER-11
* Date: 29/08/2018
* Time: 17:30
*/

namespace Greenter\Zip;

/**
* Class ZipFileDecompress
*/
class ZipFileDecompress implements DecompressInterface
{

/**
* Extract files.
*
* @param string $content
* @param callable|null $filter
* @return array
*/
public function decompress($content, callable $filter = null)
{
$temp = tempnam(sys_get_temp_dir(),time() . '.zip');
file_put_contents($temp, $content);
$zip = new \ZipArchive();
$output = [];
if ($zip->open($temp) === true && $zip->numFiles > 0) {
$output = iterator_to_array($this->getFiles($zip, $filter));
}
$zip->close();
unlink($temp);

return $output;
}

private function getFiles(\ZipArchive $zip, $filter)
{
$total = $zip->numFiles;
for ($i = 0; $i < $total; $i++) {
$name = $zip->getNameIndex($i);
if (false === $name) {
continue;
}

if (!$filter || $filter($name)) {
yield [
'filename' => $name,
'content' => $zip->getFromIndex($i)
];
}
}
}
}
57 changes: 25 additions & 32 deletions src/Zip/ZipHelper.php → src/Zip/ZipFly.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
/**
* Class ZipFile.
*/
class ZipHelper
class ZipFly implements CompressInterface, DecompressInterface
{
const UNZIP_FORMAT = 'Vsig/vver/vflag/vmeth/vmodt/vmodd/Vcrc/Vcsize/Vsize/vnamelen/vexlen';

Expand Down Expand Up @@ -41,7 +41,7 @@ class ZipHelper
private $old_offset;

/**
* ZipHelper constructor.
* ZipFly constructor.
*/
public function __construct()
{
Expand Down Expand Up @@ -175,55 +175,48 @@ public function compress($filename, $content)
return $zip;
}

private function clear()
{
$this->datasec = [];
$this->ctrl_dir = [];
$this->old_offset = 0;
}

/**
* Retorna el contenido del primer xml dentro del zip.
*
* @param string $zipContent
* Extract files.
*
* @return string
* @param string $content
* @param callable|null $filter
* @return array
*/
public function decompressXmlFile($zipContent)
public function decompress($content, callable $filter = null)
{
$start = 0;
$max = 10;
while ($max > 0) {
$dat = substr($zipContent, $start, 30);
$result = [];

while (true) {
$dat = substr($content, $start, 30);
if (empty($dat)) {
break;
}

$head = unpack(self::UNZIP_FORMAT, $dat);
$filename = substr(substr($zipContent, $start), 30, $head['namelen']);
$filename = substr(substr($content, $start), 30, $head['namelen']);
if (empty($filename)) {
break;
}
$count = 30 + $head['namelen'] + $head['exlen'];

if (strtolower($this->getFileExtension($filename)) == 'xml') {
return gzinflate(substr($zipContent, $start + $count, $head['csize']));
if (!$filter || $filter($filename)) {
$result[] = [
'filename' => $filename,
'content' => gzinflate(substr($content, $start + $count, $head['csize']))
];
}

$start += $count + $head['csize'];
--$max;
}

return '';
}

private function getFileExtension($filename)
{
$lastDotPos = strrpos($filename, '.');
if (!$lastDotPos) {
return '';
}

return substr($filename, $lastDotPos + 1);
}

private function clear()
{
$this->datasec = [];
$this->ctrl_dir = [];
$this->old_offset = 0;
return $result;
}
}
44 changes: 32 additions & 12 deletions tests/Ws/Zip/ZipFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace Tests\Greenter\Zip;

use Greenter\Zip\ZipHelper;
use Greenter\Zip\ZipFly;

/**
* Class ZipFactoryTest
Expand All @@ -28,12 +28,12 @@ public function testCompressFile()
public function testMultipleCompress()
{
$txtContent = '<h1>GREENTER WS</h1>';
$helper = new ZipHelper();
$helper = new ZipFly();
$zip = $helper->compress('myFile.xml', self::DATA_XML);
$zip2 = $helper->compress('myFile.xml', $txtContent);

$result1 = $helper->decompressXmlFile($zip);
$result2 = $helper->decompressXmlFile($zip2);
$result1 = $this->getXmlResponse($helper, $zip);
$result2 = $this->getXmlResponse($helper, $zip2);

$this->assertEquals(self::DATA_XML, $result1);
$this->assertEquals($txtContent, $result2);
Expand All @@ -42,43 +42,63 @@ public function testMultipleCompress()
public function testDecompressLastFile()
{
$zipContent = $this->createZip();
$helper = new ZipHelper();
$content = $helper->decompressXmlFile($zipContent);
$helper = new ZipFly();
$content = $this->getXmlResponse($helper, $zipContent);

$this->assertEquals(self::DATA_XML, $content);
}

public function testUnixTime()
{
$zip = new ZipHelper();
$zip = new ZipFly();
$result = $zip->unix2DosTime(181233012);

$this->assertEquals(2162688, $result);
}

public function testInvalidZip()
{
$zip = new ZipHelper();
$res = $zip->decompressXmlFile('');
$zip = new ZipFly();
$res = $zip->decompress('');

$this->assertEmpty($res);
}

public function testNotXmlZip()
{
$helper = new ZipHelper();
$helper = new ZipFly();
$zip = $helper->compress('myFile.txt', 'TEST TEXT 1');

$res = (new ZipHelper())->decompressXmlFile($zip);
$res = $this->getXmlResponse(new ZipFly(), $zip);

$this->assertEmpty($res);
}

private function createZip()
{
$helper = new ZipHelper();
$helper = new ZipFly();
$zip = $helper->compress('myFile.xml', self::DATA_XML);

return $zip;
}

private function getXmlResponse(ZipFly $zipper, $content)
{
$filter = function ($filename) {
return strtolower($this->getFileExtension($filename)) === 'xml';
};
$files = $zipper->decompress($content, $filter);

return count($files) === 0 ? '' : $files[0]['content'];
}

private function getFileExtension($filename)
{
$lastDotPos = strrpos($filename, '.');
if (!$lastDotPos) {
return '';
}

return substr($filename, $lastDotPos + 1);
}
}
Loading

0 comments on commit 2cb596e

Please sign in to comment.