You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

122 lines
3.0 KiB
PHP

<?php
namespace CubiStore\Web\Utils;
use SimpleXMLElement;
class Apk
{
/**
* @var string
*/
private $file;
/**
* @var SimpleXMLElement|null
*/
private $manifest;
/**
* Apk constructor.
* @param string $file
*/
public function __construct(string $file)
{
$this->file = $file;
}
public function isValid(): bool
{
// Get first 4 bytes
$fh = fopen($this->file, 'r');
if ($fh === false) {
throw new \RuntimeException("Failed to open file '{$this->file}'");
}
$header = fread($fh, 4);
if ($header === false) {
throw new \RuntimeException("Failed to read file '{$this->file}'");
}
fclose($fh);
// Check if uploaded file is a valid ZIP file
if ($header !== "PK\x03\x04") {
return false;
}
$zip = new \ZipArchive();
$zip->open($this->file);
$valid = $zip->statName("AndroidManifest.xml") !== false && $zip->statName("resources.arsc");
$zip->close();
return $valid;
}
public function getManifest(): SimpleXMLElement
{
if ($this->manifest === null) {
$xml = $this->cmd('androguard', 'axml', '-o', '/dev/stdout', $this->file);
$simpleXml = simplexml_load_string($xml);
if ($simpleXml === false) {
throw new \RuntimeException("Failed to parse AndroidManifest.xml from '{$this->file}'");
}
$this->manifest = $simpleXml;
}
return $this->manifest;
}
private function getAttribute(string $name, ?string $namespace = null): string
{
if ($namespace !== null) {
return (string)$this->getManifest()->attributes($namespace, true)[$name];
}
return (string)$this->getManifest()[$name];
}
public function getPackageName(): string
{
return $this->getAttribute('package');
}
public function getVersionCode(): int
{
return intval($this->getAttribute('versionCode', 'android'), 10);
}
public function getVersionName(): string
{
return $this->getAttribute('versionName', 'android');
}
public function getLabel(): string
{
$code = (string)$this->getManifest()->application->attributes('android', true)['label'];
$output = $this->cmd('androguard', 'arsc', '--id', $code, $this->file);
preg_match(':\<default\> = \'(.*)\'$:m', $output, $matches);
return stripslashes($matches[1]);
}
private function cmd(string $cmd, string... $args): string
{
$fullCommand = $cmd . ' ' . implode(' ', array_map('escapeshellarg', $args));
$proc = popen($fullCommand, 'r');
if ($proc === false) {
throw new \RuntimeException("Failed running: $fullCommand");
}
$data = '';
while ($text = fread($proc, 1024)) {
$data .= $text;
}
pclose($proc);
return $data;
}
}