php获取apk信息
使用方法如下:
<?php
require('apk_parser.php');
$p = new ApkParser(); /*
if($argc<2)
{
echo "usage:/usr/local/php/bin/php -f test_apk_parser.php test.apk\r\n";
exit();
}
$res = $p->open($argv[1]); //$argv[1]传apk包文件名
echo "package_name is:".$p->getPackage()."\r\n";
echo "VersionName is:".$p->getVersionName()."\r\n";
*/
$res = $p->open("./a.apk");
var_dump($p->getPackage());
var_dump($p->getVersionName()); ?>
依赖类ApkParser源码如下
<?php
/******************************************************
* Android APK File Parser
* Author: Katana
* Version: v0.1
* Web: http://www.win-ing.cn
*
* 功能:解析安卓apk包中的压缩XML文件,还原和读取XML内容
*
* 依赖功能:需要PHP的ZIP包函数支持。
******************************************************/ class ApkParser{
//----------------------
// 公共函数,供外部调用
//----------------------
public function open($apk_file, $xml_file='AndroidManifest.xml'){ //dl("zip.so");
if (!extension_loaded('soap')) {
var_dump("soap not exist");
}
else
{
//var_dump("soap exist");
}
if (!extension_loaded('zip')) {
var_dump("zip not exist");
}
else
{
//var_dump("zip exist");
}
$zip = new ZipArchive();
if ($zip->open($apk_file) === TRUE) {
$xml = $zip->getFromName($xml_file);
$zip->close();
if ($xml){
try {
return $this->parseString($xml);
}catch (Exception $e){
}
}
}
return false;
} public function parseString($xml){
$this->xml = $xml;
$this->length = strlen($xml); $this->root = $this->parseBlock(self::AXML_FILE);
return true;
} public function getXML($node=NULL, $lv=-1){
if ($lv == -1) $node = $this->root;
if (!$node) return ''; if ($node['type'] == self::END_TAG) $lv--;
$xml = ($node['line'] == 0 || $node['line'] == $this->line) ? '' : "\n".str_repeat(' ', $lv);
$xml .= $node['tag'];
$this->line = $node['line'];
foreach ($node['child'] as $c){
$xml .= $this->getXML($c, $lv+1);
}
return $xml;
} public function getPackage(){
return $this->getAttribute('manifest', 'package');
} public function getVersionName(){
return $this->getAttribute('manifest', 'android:versionName');
} public function getVersionCode(){
return $this->getAttribute('manifest', 'android:versionCode');
} public function getAppName(){
return $this->getAttribute('manifest/application', 'android:name');
} public function getMiniSdk(){
return $this->getAttribute('manifest/uses-sdk', 'android:minSdkVersion');
} public function getMaxSdk(){
return $this->getAttribute('manifest/uses-sdk', 'android:maxSdkVersion');
} public function getTargetSdk(){
return $this->getAttribute('manifest/uses-sdk', 'android:targetSdkVersion');
} public function getApplicationLabel(){
return $this->getAttribute('manifest/application', 'android:label');
} public function getMainActivity(){
for ($id=0; true; $id++){
$act = $this->getAttribute("manifest/application/activity[{$id}]/intent-filter/action", 'android:name');
if (!$act) break;
if ($act == 'android.intent.action.MAIN') return $this->getActivity($id);
}
return NULL;
} public function getActivity($idx=0){
$idx = intval($idx);
return $this->getAttribute("manifest/application/activity[{$idx}]", 'android:name');
} public function getAttribute($path, $name){
$r = $this->getElement($path);
if (is_null($r)) return NULL; if (isset($r['attrs'])){
foreach ($r['attrs'] as $a){
if ($a['ns_name'] == $name) return $this->getAttributeValue($a);
}
}
return NULL;
} //----------------------
// 类型常量定义
//----------------------
const AXML_FILE = 0x00080003;
const STRING_BLOCK = 0x001C0001;
const RESOURCEIDS = 0x00080180;
const START_NAMESPACE = 0x00100100;
const END_NAMESPACE = 0x00100101;
const START_TAG = 0x00100102;
const END_TAG = 0x00100103;
const TEXT = 0x00100104; const TYPE_NULL =0;
const TYPE_REFERENCE =1;
const TYPE_ATTRIBUTE =2;
const TYPE_STRING =3;
const TYPE_FLOAT =4;
const TYPE_DIMENSION =5;
const TYPE_FRACTION =6;
const TYPE_INT_DEC =16;
const TYPE_INT_HEX =17;
const TYPE_INT_BOOLEAN =18;
const TYPE_INT_COLOR_ARGB8 =28;
const TYPE_INT_COLOR_RGB8 =29;
const TYPE_INT_COLOR_ARGB4 =30;
const TYPE_INT_COLOR_RGB4 =31; const UNIT_MASK = 15;
private static $RADIX_MULTS = array(0.00390625, 3.051758E-005, 1.192093E-007, 4.656613E-010);
private static $DIMENSION_UNITS = array("px","dip","sp","pt","in","mm","","");
private static $FRACTION_UNITS = array("%","%p","","","","","",""); private $xml='';
private $length = 0;
private $stringCount = 0;
private $styleCount = 0;
private $stringTab = array();
private $styleTab = array();
private $resourceIDs = array();
private $ns = array();
private $cur_ns = NULL;
private $root = NULL;
private $line = 0; //----------------------
// 内部私有函数
//----------------------
private function getElement($path){
if (!$this->root) return NULL;
$ps = explode('/', $path);
$r = $this->root;
foreach ($ps as $v){
if (preg_match('/([^\[]+)\[([0-9]+)\]$/', $v, $ms)){
$v = $ms[1];
$off = $ms[2];
}else {
$off = 0;
}
foreach ($r['child'] as $c){
if ($c['type'] == self::START_TAG && $c['ns_name'] == $v){
if ($off == 0){
$r = $c; continue 2;
}else {
$off--;
}
}
}
// 没有找到节点
return NULL;
}
return $r;
} private function parseBlock($need = 0){
$o = 0;
$type = $this->get32($o);
if ($need && $type != $need) throw new Exception('Block Type Error', 1);
$size = $this->get32($o);
if ($size < 8 || $size > $this->length) throw new Exception('Block Size Error', 2);
$left = $this->length - $size; $props = false;
switch ($type){
case self::AXML_FILE:
$props = array(
'line' => 0,
'tag' => '<?xml version="1.0" encoding="utf-8"?>'
);
break;
case self::STRING_BLOCK:
$this->stringCount = $this->get32($o);
$this->styleCount = $this->get32($o);
$o += 4;
$strOffset = $this->get32($o);
$styOffset = $this->get32($o);
$strListOffset = $this->get32array($o, $this->stringCount);
$styListOffset = $this->get32array($o, $this->styleCount);
$this->stringTab = $this->stringCount > 0 ? $this->getStringTab($strOffset, $strListOffset) : array();
$this->styleTab = $this->styleCount > 0 ? $this->getStringTab($styOffset, $styListOffset) : array();
$o = $size;
break;
case self::RESOURCEIDS:
$count = $size / 4 - 2;
$this->resourceIDs = $this->get32array($o, $count);
break;
case self::START_NAMESPACE:
$o += 8;
$prefix = $this->get32($o);
$uri = $this->get32($o); if (empty($this->cur_ns)){
$this->cur_ns = array();
$this->ns[] = &$this->cur_ns;
}
$this->cur_ns[$uri] = $prefix;
break;
case self::END_NAMESPACE:
$o += 8;
$prefix = $this->get32($o);
$uri = $this->get32($o); if (empty($this->cur_ns)) break;
unset($this->cur_ns[$uri]);
break;
case self::START_TAG:
$line = $this->get32($o); $o += 4;
$attrs = array();
$props = array(
'line' => $line,
'ns' => $this->getNameSpace($this->get32($o)),
'name' => $this->getString($this->get32($o)),
'flag' => $this->get32($o),
'count' => $this->get16($o),
'id' => $this->get16($o)-1,
'class' => $this->get16($o)-1,
'style' => $this->get16($o)-1,
'attrs' => &$attrs
);
$props['ns_name'] = $props['ns'].$props['name'];
for ($i=0; $i < $props['count']; $i++){
$a = array(
'ns' => $this->getNameSpace($this->get32($o)),
'name' => $this->getString($this->get32($o)),
'val_str' => $this->get32($o),
'val_type' => $this->get32($o),
'val_data' => $this->get32($o)
);
$a['ns_name'] = $a['ns'].$a['name'];
$a['val_type'] >>= 24;
$attrs[] = $a;
}
// 处理TAG字符串
$tag = "<{$props['ns_name']}";
foreach ($this->cur_ns as $uri => $prefix){
$uri = $this->getString($uri);
$prefix = $this->getString($prefix);
$tag .= " xmlns:{$prefix}=\"{$uri}\"";
}
foreach ($props['attrs'] as $a){
$tag .= " {$a['ns_name']}=\"".
$this->getAttributeValue($a).
'"';
}
$tag .= '>';
$props['tag'] = $tag; unset($this->cur_ns);
$this->cur_ns = array();
$this->ns[] = &$this->cur_ns;
$left = -1;
break;
case self::END_TAG:
$line = $this->get32($o);
$o += 4;
$props = array(
'line' => $line,
'ns' => $this->getNameSpace($this->get32($o)),
'name' => $this->getString($this->get32($o))
);
$props['ns_name'] = $props['ns'].$props['name'];
$props['tag'] = "</{$props['ns_name']}>";
if (count($this->ns) > 1){
array_pop($this->ns);
unset($this->cur_ns);
$this->cur_ns = array_pop($this->ns);
$this->ns[] = &$this->cur_ns;
}
break;
case self::TEXT:
$o += 8;
$props = array(
'tag' => $this->getString($this->get32($o))
);
$o += 8;
break;
default:
throw new Exception('Block Type Error', 3);
break;
} $this->skip($o);
$child = array();
while ($this->length > $left){
$c = $this->parseBlock();
if ($props && $c) $child[] = $c;
if ($left == -1 && $c['type'] == self::END_TAG){
$left = $this->length;
break;
}
}
if ($this->length != $left) throw new Exception('Block Overflow Error', 4);
if ($props){
$props['type'] = $type;
$props['size'] = $size;
$props['child'] = $child;
return $props;
}else {
return false;
}
} private function getAttributeValue($a){
$type = &$a['val_type'];
$data = &$a['val_data'];
switch ($type){
case self::TYPE_STRING:
return $this->getString($a['val_str']);
case self::TYPE_ATTRIBUTE:
return sprintf('?%s%08X', self::_getPackage($data), $data);
case self::TYPE_REFERENCE:
return sprintf('@%s%08X', self::_getPackage($data), $data);
case self::TYPE_INT_HEX:
return sprintf('0x%08X', $data);
case self::TYPE_INT_BOOLEAN:
return ($data != 0 ? 'true' : 'false');
case self::TYPE_INT_COLOR_ARGB8:
case self::TYPE_INT_COLOR_RGB8:
case self::TYPE_INT_COLOR_ARGB4:
case self::TYPE_INT_COLOR_RGB4:
return sprintf('#%08X', $data);
case self::TYPE_DIMENSION:
return $this->_complexToFloat($data).self::$DIMENSION_UNITS[$data & self::UNIT_MASK];
case self::TYPE_FRACTION:
return $this->_complexToFloat($data).self::$FRACTION_UNITS[$data & self::UNIT_MASK];
case self::TYPE_FLOAT:
return $this->_int2float($data);
}
if ($type >=self::TYPE_INT_DEC && $type < self::TYPE_INT_COLOR_ARGB8){
return (string)$data;
}
return sprintf('<0x%X, type 0x%02X>', $data, $type);
} private function _complexToFloat($data){
return (float)($data & 0xFFFFFF00) * self::$RADIX_MULTS[($data>>4) & 3];
}
private function _int2float($v) {
$x = ($v & ((1 << 23) - 1)) + (1 << 23) * ($v >> 31 | 1);
$exp = ($v >> 23 & 0xFF) - 127;
return $x * pow(2, $exp - 23);
}
private static function _getPackage($data){
return ($data >> 24 == 1) ? 'android:' : '';
} private function getStringTab($base, $list){
$tab = array();
foreach ($list as $off){
$off += $base;
$len = $this->get16($off);
$mask = ($len >> 0x8) & 0xFF;
$len = $len & 0xFF;
if ($len == $mask){
if ($off + $len > $this->length) throw new Exception('String Table Overflow', 11);
$tab[] = substr($this->xml, $off, $len);
}else {
if ($off + $len * 2 > $this->length) throw new Exception('String Table Overflow', 11);
$str = substr($this->xml, $off, $len * 2);
//$tab[] = mb_convert_encoding($str, 'UTF-8', 'UCS-2LE');
$tab[] = iconv('UCS-2LE','UTF-8',$str);
}
}
return $tab;
}
private function getString($id){
if ($id > -1 && $id < $this->stringCount){
return $this->stringTab[$id];
}else {
return '';
}
}
private function getNameSpace($uri){
for ($i=count($this->ns); $i > 0; ){
$ns = $this->ns[--$i];
if (isset($ns[$uri])){
$ns = $this->getString($ns[$uri]);
if (!empty($ns)) $ns .= ':';
return $ns;
}
}
return '';
}
private function get32(&$off){
$int = unpack('V', substr($this->xml, $off, 4));
$off += 4;
return array_shift($int);
}
private function get32array(&$off, $size){
if ($size <= 0) return NULL;
$arr = unpack('V*', substr($this->xml, $off, 4 * $size));
if (count($arr) != $size) throw new Exception('Array Size Error', 10);
$off += 4 * $size;
return $arr;
}
private function get16(&$off){
$int = unpack('v', substr($this->xml, $off, 2));
$off += 2;
return array_shift($int);
}
private function skip($size){
$this->xml = substr($this->xml, $size);
$this->length -= $size;
}
}
?>
php获取apk信息的更多相关文章
- 获取apk信息工具(android SDK的aapt工具)
aapt命令是android SDK 中的一个工具,功能强大,比如在windows平台获取apk包的信息. 使用该工具准备条件,也即获取aapt.exe文件的方式(2选1即可): 安装android ...
- Linux系统上使用php获取apk信息
最近在做一个apk商城,需要在用户上传了apk之后系统自动读取apk信息(包名,版本号等),后台语言使用的是php,需要php去调用系统的aapt命令去读取apk信息,在Linux系统上安装aapt的 ...
- java通过解析文件获取apk版本等信息
import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import ...
- 获取apk的签名信息
在接入第三方功能时,经常要注册提交apk的签名信息 (sha1签名)?,下面列出相关步骤. 获取apk签名信息的步骤: 1)修改apk后缀名为zip,解压得到其中的META-INF文件夹; 2)把ME ...
- [置顶]
Android Studio apk打包以及获取apk签名信息
首先说下Android Studio 主要分为以下几步 填写你的签名的一些信息 (例如签名的文件名.省份.密码 别名 就是你比如叫xxx 但是别名是xx张三 认证年限就是apk过期默认是25年 其他就 ...
- C#获取apk版本信息
获取很多人都会问我为什么要写这个博客,原因很简单,这次研发apk版本信息的时候网上查了很多的资料都没有这方面的信息,因此这次功能完了想写下方法,如果以后博友们遇到了可以直接copy,不用花很多的时间, ...
- aapt命令获取apk具体信息(包名、版本号号、版本号名称、兼容api级别、启动Activity等)
aapt命令获取apk具体信息(包名.版本号号.版本号名称.兼容api级别.启动Activity等) 第一步:找到aapt 找到sdk的根文件夹,然后找到build-tools文件夹.然后会看到一些b ...
- Android apk签名详解——AS签名、获取签名信息、系统签名、命令行签名
Apk签名,每一个Android开发者都不陌生.它就是对我们的apk加了一个校验参数,防止apk被掉包.一开始做Android开发,就接触到了apk签名:后来在微信开放平台.高德地图等平台注册时,需要 ...
- Unity3d获取APK签名及公钥的方法
在Unity3d项目中获取APK包签名公钥的方法,核心思想就是通过JNI调用Android提供的方法.不过Unity3d提供了比JNI更上一层的类AndroidJavaObject以及继承它的Andr ...
随机推荐
- linux下/proc/sysrq-trigger文件的功能
/proc/sysrq-trigger该文件能做些什么事情呢? # 立即重新启动计算机 (Reboots the kernel without first unmounting file system ...
- Follow your heart
世界上最可怕的两个词,一个是执着,一个是认真.认真的人改变自己,执着的人改变命运.任何时候都别怕重来,每个看似低的起点,都是通往高峰的必经之路.不用抱怨那些不尽如人意,问问自己,你够努力了吗?转自人民 ...
- selenium webdriver 学习笔记(三)
selenium webdriver 一.上传文件操作 上传文件夹一般要打开一个本地窗口,从窗口选择本地文件添加.所以一般会卡在如何操作本地窗口添加上传文件. 其实,在selenium webdriv ...
- 如何查询Oracle性能监控
1.监控等待事件select event,sum(decode(wait_time,0,0,1)) prev, sum(decode(wait_time,0,1,0)) curr,count(*)fr ...
- Oracle GoldenGate学习之Goldengate介绍
Oracle GoldenGate学习之Goldengate介绍 (2012-10-02 17:07:27) 标签: 检查点 数据传输 队列 进程 分类: Goldengate Goldengate介 ...
- IBM中枪后,下一个是谁?
冯强/文 在之前的博文<信息战第二弹:中国对美国咨询公司Say no>我以前提到对美国咨询服务公司在国企开展业务的限制.有可能波及IBM.Microsoft.Google.CISCO.Or ...
- 核心基础以及Fragment与Activity传递数据完整示例
MainActivity如下: package cc.testsimplefragment0; import android.os.Bundle; import android.app.Activit ...
- stl之map 排序
排序问题,STL中默认是采用小于号来排序的,因为设置int等类型做key,它本身支持小于号运算,在一些特殊情况,比如关键字是一个结构体,涉及到排序就会出现问题,因为它没有小于号操作,insert等函数 ...
- npoi 使用方法
不少朋友在做项目的过程中或多或少的都会用到excel导入.导出功能,下面我来给大家介绍一下使用NPOI如何导入.导出excel, 通过代码描述一下npoi的使用方法,希望都够给需要的朋友一点点帮助,也 ...
- Div实现滚动条效果
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...