1
0
mirror of https://github.com/Ne-Lexa/php-zip.git synced 2025-07-18 22:51:11 +02:00
Files
php-zip/tests/TestZipFile.php
2016-09-08 19:18:53 +03:00

244 lines
7.8 KiB
PHP

<?php
class TestZipFile extends \PHPUnit\Framework\TestCase
{
public function testCreate()
{
$output = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'test-create.zip';
$extractOutputDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'test-create';
$listFilename = 'files.txt';
$listFileContent = implode(PHP_EOL, glob('*'));
$dirName = 'src/';
$archiveComment = 'Archive comment - 😀';
$commentIndex0 = basename(__FILE__);
$zip = new \Nelexa\Zip\ZipFile();
$zip->create();
$zip->addFile(__FILE__);
$zip->addFromString($listFilename, $listFileContent);
$zip->addEmptyDir($dirName);
$zip->setArchiveComment($archiveComment);
$zip->setCommentIndex(0, $commentIndex0);
$zip->saveAs($output);
$zip->close();
$this->assertTrue(file_exists($output));
$this->assertCorrectZipArchive($output);
$zip = new \Nelexa\Zip\ZipFile();
$zip->open($output);
$listFiles = $zip->getListFiles();
$this->assertEquals(sizeof($listFiles), 3);
$filenameIndex0 = basename(__FILE__);
$this->assertEquals($listFiles[0], $filenameIndex0);
$this->assertEquals($listFiles[1], $listFilename);
$this->assertEquals($listFiles[2], $dirName);
$this->assertEquals($zip->getFromIndex(0), $zip->getFromName(basename(__FILE__)));
$this->assertEquals($zip->getFromIndex(0), file_get_contents(__FILE__));
$this->assertEquals($zip->getFromIndex(1), $zip->getFromName($listFilename));
$this->assertEquals($zip->getFromIndex(1), $listFileContent);
$this->assertEquals($zip->getArchiveComment(), $archiveComment);
$this->assertEquals($zip->getCommentIndex(0), $commentIndex0);
if (!file_exists($extractOutputDir)) {
$this->assertTrue(mkdir($extractOutputDir, 0755, true));
}
$zip->extractTo($extractOutputDir);
$this->assertTrue(file_exists($extractOutputDir . DIRECTORY_SEPARATOR . $filenameIndex0));
$this->assertEquals(md5_file($extractOutputDir . DIRECTORY_SEPARATOR . $filenameIndex0), md5_file(__FILE__));
$this->assertTrue(file_exists($extractOutputDir . DIRECTORY_SEPARATOR . $listFilename));
$this->assertEquals(file_get_contents($extractOutputDir . DIRECTORY_SEPARATOR . $listFilename), $listFileContent);
$zip->close();
unlink($output);
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($extractOutputDir, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($files as $fileInfo) {
$todo = ($fileInfo->isDir() ? 'rmdir' : 'unlink');
$todo($fileInfo->getRealPath());
}
rmdir($extractOutputDir);
}
/**
*
*/
public function testUpdate()
{
$file = __DIR__ . '/res/file.apk';
$privateKey = __DIR__ . '/res/private.pem';
$publicKey = __DIR__ . '/res/public.pem';
$outputFile = sys_get_temp_dir() . '/test-update.apk';
$zip = new \Nelexa\Zip\ZipFile($file);
$zip->open($file);
// signed apk file
$certList = array();
$manifestMf = new Manifest();
$manifestMf->appendLine("Manifest-Version: 1.0");
$manifestMf->appendLine("Created-By: 1.0 (Android)");
$manifestMf->appendLine('');
for ($i = 0, $length = $zip->getCountFiles(); $i < $length; $i++) {
$name = $zip->getNameIndex($i);
if ($name[strlen($name) - 1] === '/') continue; // is path
$content = $zip->getFromIndex($i);
$certManifest = $this->createSha1EncodeEntryManifest($name, $content);
$manifestMf->appendManifest($certManifest);
$certList[$name] = $certManifest;
}
$manifestMf = $manifestMf->getContent();
$certSf = new Manifest();
$certSf->appendLine('Signature-Version: 1.0');
$certSf->appendLine('Created-By: 1.0 (Android)');
$certSf->appendLine('SHA1-Digest-Manifest: ' . base64_encode(sha1($manifestMf, 1)));
$certSf->appendLine('');
foreach ($certList AS $filename => $content) {
$certManifest = $this->createSha1EncodeEntryManifest($filename, $content->getContent());
$certSf->appendManifest($certManifest);
}
$certSf = $certSf->getContent();
unset($certList);
$zip->addFromString('META-INF/MANIFEST.MF', $manifestMf);
$zip->addFromString('META-INF/CERT.SF', $certSf);
if (`which openssl`) {
$openssl_cmd = 'printf ' . escapeshellarg($certSf) . ' | openssl smime -md sha1 -sign -inkey ' . escapeshellarg($privateKey) . ' -signer ' . $publicKey . ' -binary -outform DER -noattr';
ob_start();
passthru($openssl_cmd, $error);
$rsaContent = ob_get_clean();
$this->assertEquals($error, 0);
$zip->addFromString('META-INF/CERT.RSA', $rsaContent);
}
$zip->saveAs($outputFile);
$zip->close();
$this->assertCorrectZipArchive($outputFile);
if (`which jarsigner`) {
ob_start();
passthru('jarsigner -verify -verbose -certs ' . escapeshellarg($outputFile), $error);
$verifedResult = ob_get_clean();
$this->assertEquals($error, 0);
$this->assertContains('jar verified', $verifedResult);
}
unlink($outputFile);
}
/**
* @param $filename
*/
private function assertCorrectZipArchive($filename)
{
exec("zip -T " . escapeshellarg($filename), $output, $returnCode);
$this->assertEquals($returnCode, 0);
}
/**
* @param string $filename
* @param string $content
* @return Manifest
*/
private function createSha1EncodeEntryManifest($filename, $content)
{
$manifest = new Manifest();
$manifest->appendLine('Name: ' . $filename);
$manifest->appendLine('SHA1-Digest: ' . base64_encode(sha1($content, 1)));
return $manifest;
}
}
class Manifest
{
private $content;
/**
* @return mixed
*/
public function getContent()
{
return trim($this->content) . "\r\n\r\n";
}
/**
* Process a long manifest line and add continuation if required
* @param $line string
* @return Manifest
*/
public function appendLine($line)
{
$begin = 0;
$sb = '';
$lineLength = mb_strlen($line, "UTF-8");
for ($end = 70; $lineLength - $begin > 70; $end += 69) {
$sb .= mb_substr($line, $begin, $end - $begin, "UTF-8") . "\r\n ";
$begin = $end;
}
$this->content .= $sb . mb_substr($line, $begin, $lineLength, "UTF-8") . "\r\n";
return $this;
}
public function appendManifest(Manifest $manifest)
{
$this->content .= $manifest->getContent();
return $this;
}
public function clear()
{
$this->content = '';
}
/**
* @param string $manifestContent
* @return Manifest
*/
public static function createFromManifest($manifestContent)
{
$manifestContent = trim($manifestContent);
$lines = explode("\n", $manifestContent);
// normalize manifest
$content = '';
$trim = array("\r", "\n");
foreach ($lines AS $line) {
$line = str_replace($trim, '', $line);
if ($line[0] === ' ') {
$content = rtrim($content, "\n\r");
$line = ltrim($line);
}
$content .= $line . "\r\n";
}
$manifset = new self;
$lines = explode("\n", $content);
foreach ($lines AS $line) {
$line = trim($line, "\n\r");
$manifset->appendLine($line);
}
return $manifset;
}
}