使用方法如下:

  1. <?php
  2. require('apk_parser.php');
  3. $p = new ApkParser();
  4.  
  5. /*
  6. if($argc<2)
  7. {
  8. echo "usage:/usr/local/php/bin/php -f test_apk_parser.php test.apk\r\n";
  9. exit();
  10. }
  11. $res = $p->open($argv[1]); //$argv[1]传apk包文件名
  12. echo "package_name is:".$p->getPackage()."\r\n";
  13. echo "VersionName is:".$p->getVersionName()."\r\n";
  14. */
  15. $res = $p->open("./a.apk");
  16. var_dump($p->getPackage());
  17. var_dump($p->getVersionName());
  18.  
  19. ?>

依赖类ApkParser源码如下

  1. <?php
  2. /******************************************************
  3. * Android APK File Parser
  4. * Author: Katana
  5. * Version: v0.1
  6. * Web: http://www.win-ing.cn
  7. *
  8. * 功能:解析安卓apk包中的压缩XML文件,还原和读取XML内容
  9. *
  10. * 依赖功能:需要PHP的ZIP包函数支持。
  11. ******************************************************/
  12.  
  13. class ApkParser{
  14. //----------------------
  15. // 公共函数,供外部调用
  16. //----------------------
  17. public function open($apk_file, $xml_file='AndroidManifest.xml'){
  18.  
  19. //dl("zip.so");
  20. if (!extension_loaded('soap')) {
  21. var_dump("soap not exist");
  22. }
  23. else
  24. {
  25. //var_dump("soap exist");
  26. }
  27. if (!extension_loaded('zip')) {
  28. var_dump("zip not exist");
  29. }
  30. else
  31. {
  32. //var_dump("zip exist");
  33. }
  34. $zip = new ZipArchive();
  35. if ($zip->open($apk_file) === TRUE) {
  36. $xml = $zip->getFromName($xml_file);
  37. $zip->close();
  38. if ($xml){
  39. try {
  40. return $this->parseString($xml);
  41. }catch (Exception $e){
  42. }
  43. }
  44. }
  45. return false;
  46. }
  47.  
  48. public function parseString($xml){
  49. $this->xml = $xml;
  50. $this->length = strlen($xml);
  51.  
  52. $this->root = $this->parseBlock(self::AXML_FILE);
  53. return true;
  54. }
  55.  
  56. public function getXML($node=NULL, $lv=-1){
  57. if ($lv == -1) $node = $this->root;
  58. if (!$node) return '';
  59.  
  60. if ($node['type'] == self::END_TAG) $lv--;
  61. $xml = ($node['line'] == 0 || $node['line'] == $this->line) ? '' : "\n".str_repeat(' ', $lv);
  62. $xml .= $node['tag'];
  63. $this->line = $node['line'];
  64. foreach ($node['child'] as $c){
  65. $xml .= $this->getXML($c, $lv+1);
  66. }
  67. return $xml;
  68. }
  69.  
  70. public function getPackage(){
  71. return $this->getAttribute('manifest', 'package');
  72. }
  73.  
  74. public function getVersionName(){
  75. return $this->getAttribute('manifest', 'android:versionName');
  76. }
  77.  
  78. public function getVersionCode(){
  79. return $this->getAttribute('manifest', 'android:versionCode');
  80. }
  81.  
  82. public function getAppName(){
  83. return $this->getAttribute('manifest/application', 'android:name');
  84. }
  85.  
  86. public function getMiniSdk(){
  87. return $this->getAttribute('manifest/uses-sdk', 'android:minSdkVersion');
  88. }
  89.  
  90. public function getMaxSdk(){
  91. return $this->getAttribute('manifest/uses-sdk', 'android:maxSdkVersion');
  92. }
  93.  
  94. public function getTargetSdk(){
  95. return $this->getAttribute('manifest/uses-sdk', 'android:targetSdkVersion');
  96. }
  97.  
  98. public function getApplicationLabel(){
  99. return $this->getAttribute('manifest/application', 'android:label');
  100. }
  101.  
  102. public function getMainActivity(){
  103. for ($id=0; true; $id++){
  104. $act = $this->getAttribute("manifest/application/activity[{$id}]/intent-filter/action", 'android:name');
  105. if (!$act) break;
  106. if ($act == 'android.intent.action.MAIN') return $this->getActivity($id);
  107. }
  108. return NULL;
  109. }
  110.  
  111. public function getActivity($idx=0){
  112. $idx = intval($idx);
  113. return $this->getAttribute("manifest/application/activity[{$idx}]", 'android:name');
  114. }
  115.  
  116. public function getAttribute($path, $name){
  117. $r = $this->getElement($path);
  118. if (is_null($r)) return NULL;
  119.  
  120. if (isset($r['attrs'])){
  121. foreach ($r['attrs'] as $a){
  122. if ($a['ns_name'] == $name) return $this->getAttributeValue($a);
  123. }
  124. }
  125. return NULL;
  126. }
  127.  
  128. //----------------------
  129. // 类型常量定义
  130. //----------------------
  131. const AXML_FILE = 0x00080003;
  132. const STRING_BLOCK = 0x001C0001;
  133. const RESOURCEIDS = 0x00080180;
  134. const START_NAMESPACE = 0x00100100;
  135. const END_NAMESPACE = 0x00100101;
  136. const START_TAG = 0x00100102;
  137. const END_TAG = 0x00100103;
  138. const TEXT = 0x00100104;
  139.  
  140. const TYPE_NULL =0;
  141. const TYPE_REFERENCE =1;
  142. const TYPE_ATTRIBUTE =2;
  143. const TYPE_STRING =3;
  144. const TYPE_FLOAT =4;
  145. const TYPE_DIMENSION =5;
  146. const TYPE_FRACTION =6;
  147. const TYPE_INT_DEC =16;
  148. const TYPE_INT_HEX =17;
  149. const TYPE_INT_BOOLEAN =18;
  150. const TYPE_INT_COLOR_ARGB8 =28;
  151. const TYPE_INT_COLOR_RGB8 =29;
  152. const TYPE_INT_COLOR_ARGB4 =30;
  153. const TYPE_INT_COLOR_RGB4 =31;
  154.  
  155. const UNIT_MASK = 15;
  156. private static $RADIX_MULTS = array(0.00390625, 3.051758E-005, 1.192093E-007, 4.656613E-010);
  157. private static $DIMENSION_UNITS = array("px","dip","sp","pt","in","mm","","");
  158. private static $FRACTION_UNITS = array("%","%p","","","","","","");
  159.  
  160. private $xml='';
  161. private $length = 0;
  162. private $stringCount = 0;
  163. private $styleCount = 0;
  164. private $stringTab = array();
  165. private $styleTab = array();
  166. private $resourceIDs = array();
  167. private $ns = array();
  168. private $cur_ns = NULL;
  169. private $root = NULL;
  170. private $line = 0;
  171.  
  172. //----------------------
  173. // 内部私有函数
  174. //----------------------
  175. private function getElement($path){
  176. if (!$this->root) return NULL;
  177. $ps = explode('/', $path);
  178. $r = $this->root;
  179. foreach ($ps as $v){
  180. if (preg_match('/([^\[]+)\[([0-9]+)\]$/', $v, $ms)){
  181. $v = $ms[1];
  182. $off = $ms[2];
  183. }else {
  184. $off = 0;
  185. }
  186. foreach ($r['child'] as $c){
  187. if ($c['type'] == self::START_TAG && $c['ns_name'] == $v){
  188. if ($off == 0){
  189. $r = $c; continue 2;
  190. }else {
  191. $off--;
  192. }
  193. }
  194. }
  195. // 没有找到节点
  196. return NULL;
  197. }
  198. return $r;
  199. }
  200.  
  201. private function parseBlock($need = 0){
  202. $o = 0;
  203. $type = $this->get32($o);
  204. if ($need && $type != $need) throw new Exception('Block Type Error', 1);
  205. $size = $this->get32($o);
  206. if ($size < 8 || $size > $this->length) throw new Exception('Block Size Error', 2);
  207. $left = $this->length - $size;
  208.  
  209. $props = false;
  210. switch ($type){
  211. case self::AXML_FILE:
  212. $props = array(
  213. 'line' => 0,
  214. 'tag' => '<?xml version="1.0" encoding="utf-8"?>'
  215. );
  216. break;
  217. case self::STRING_BLOCK:
  218. $this->stringCount = $this->get32($o);
  219. $this->styleCount = $this->get32($o);
  220. $o += 4;
  221. $strOffset = $this->get32($o);
  222. $styOffset = $this->get32($o);
  223. $strListOffset = $this->get32array($o, $this->stringCount);
  224. $styListOffset = $this->get32array($o, $this->styleCount);
  225. $this->stringTab = $this->stringCount > 0 ? $this->getStringTab($strOffset, $strListOffset) : array();
  226. $this->styleTab = $this->styleCount > 0 ? $this->getStringTab($styOffset, $styListOffset) : array();
  227. $o = $size;
  228. break;
  229. case self::RESOURCEIDS:
  230. $count = $size / 4 - 2;
  231. $this->resourceIDs = $this->get32array($o, $count);
  232. break;
  233. case self::START_NAMESPACE:
  234. $o += 8;
  235. $prefix = $this->get32($o);
  236. $uri = $this->get32($o);
  237.  
  238. if (empty($this->cur_ns)){
  239. $this->cur_ns = array();
  240. $this->ns[] = &$this->cur_ns;
  241. }
  242. $this->cur_ns[$uri] = $prefix;
  243. break;
  244. case self::END_NAMESPACE:
  245. $o += 8;
  246. $prefix = $this->get32($o);
  247. $uri = $this->get32($o);
  248.  
  249. if (empty($this->cur_ns)) break;
  250. unset($this->cur_ns[$uri]);
  251. break;
  252. case self::START_TAG:
  253. $line = $this->get32($o);
  254.  
  255. $o += 4;
  256. $attrs = array();
  257. $props = array(
  258. 'line' => $line,
  259. 'ns' => $this->getNameSpace($this->get32($o)),
  260. 'name' => $this->getString($this->get32($o)),
  261. 'flag' => $this->get32($o),
  262. 'count' => $this->get16($o),
  263. 'id' => $this->get16($o)-1,
  264. 'class' => $this->get16($o)-1,
  265. 'style' => $this->get16($o)-1,
  266. 'attrs' => &$attrs
  267. );
  268. $props['ns_name'] = $props['ns'].$props['name'];
  269. for ($i=0; $i < $props['count']; $i++){
  270. $a = array(
  271. 'ns' => $this->getNameSpace($this->get32($o)),
  272. 'name' => $this->getString($this->get32($o)),
  273. 'val_str' => $this->get32($o),
  274. 'val_type' => $this->get32($o),
  275. 'val_data' => $this->get32($o)
  276. );
  277. $a['ns_name'] = $a['ns'].$a['name'];
  278. $a['val_type'] >>= 24;
  279. $attrs[] = $a;
  280. }
  281. // 处理TAG字符串
  282. $tag = "<{$props['ns_name']}";
  283. foreach ($this->cur_ns as $uri => $prefix){
  284. $uri = $this->getString($uri);
  285. $prefix = $this->getString($prefix);
  286. $tag .= " xmlns:{$prefix}=\"{$uri}\"";
  287. }
  288. foreach ($props['attrs'] as $a){
  289. $tag .= " {$a['ns_name']}=\"".
  290. $this->getAttributeValue($a).
  291. '"';
  292. }
  293. $tag .= '>';
  294. $props['tag'] = $tag;
  295.  
  296. unset($this->cur_ns);
  297. $this->cur_ns = array();
  298. $this->ns[] = &$this->cur_ns;
  299. $left = -1;
  300. break;
  301. case self::END_TAG:
  302. $line = $this->get32($o);
  303. $o += 4;
  304. $props = array(
  305. 'line' => $line,
  306. 'ns' => $this->getNameSpace($this->get32($o)),
  307. 'name' => $this->getString($this->get32($o))
  308. );
  309. $props['ns_name'] = $props['ns'].$props['name'];
  310. $props['tag'] = "</{$props['ns_name']}>";
  311. if (count($this->ns) > 1){
  312. array_pop($this->ns);
  313. unset($this->cur_ns);
  314. $this->cur_ns = array_pop($this->ns);
  315. $this->ns[] = &$this->cur_ns;
  316. }
  317. break;
  318. case self::TEXT:
  319. $o += 8;
  320. $props = array(
  321. 'tag' => $this->getString($this->get32($o))
  322. );
  323. $o += 8;
  324. break;
  325. default:
  326. throw new Exception('Block Type Error', 3);
  327. break;
  328. }
  329.  
  330. $this->skip($o);
  331. $child = array();
  332. while ($this->length > $left){
  333. $c = $this->parseBlock();
  334. if ($props && $c) $child[] = $c;
  335. if ($left == -1 && $c['type'] == self::END_TAG){
  336. $left = $this->length;
  337. break;
  338. }
  339. }
  340. if ($this->length != $left) throw new Exception('Block Overflow Error', 4);
  341. if ($props){
  342. $props['type'] = $type;
  343. $props['size'] = $size;
  344. $props['child'] = $child;
  345. return $props;
  346. }else {
  347. return false;
  348. }
  349. }
  350.  
  351. private function getAttributeValue($a){
  352. $type = &$a['val_type'];
  353. $data = &$a['val_data'];
  354. switch ($type){
  355. case self::TYPE_STRING:
  356. return $this->getString($a['val_str']);
  357. case self::TYPE_ATTRIBUTE:
  358. return sprintf('?%s%08X', self::_getPackage($data), $data);
  359. case self::TYPE_REFERENCE:
  360. return sprintf('@%s%08X', self::_getPackage($data), $data);
  361. case self::TYPE_INT_HEX:
  362. return sprintf('0x%08X', $data);
  363. case self::TYPE_INT_BOOLEAN:
  364. return ($data != 0 ? 'true' : 'false');
  365. case self::TYPE_INT_COLOR_ARGB8:
  366. case self::TYPE_INT_COLOR_RGB8:
  367. case self::TYPE_INT_COLOR_ARGB4:
  368. case self::TYPE_INT_COLOR_RGB4:
  369. return sprintf('#%08X', $data);
  370. case self::TYPE_DIMENSION:
  371. return $this->_complexToFloat($data).self::$DIMENSION_UNITS[$data & self::UNIT_MASK];
  372. case self::TYPE_FRACTION:
  373. return $this->_complexToFloat($data).self::$FRACTION_UNITS[$data & self::UNIT_MASK];
  374. case self::TYPE_FLOAT:
  375. return $this->_int2float($data);
  376. }
  377. if ($type >=self::TYPE_INT_DEC && $type < self::TYPE_INT_COLOR_ARGB8){
  378. return (string)$data;
  379. }
  380. return sprintf('<0x%X, type 0x%02X>', $data, $type);
  381. }
  382.  
  383. private function _complexToFloat($data){
  384. return (float)($data & 0xFFFFFF00) * self::$RADIX_MULTS[($data>>4) & 3];
  385. }
  386. private function _int2float($v) {
  387. $x = ($v & ((1 << 23) - 1)) + (1 << 23) * ($v >> 31 | 1);
  388. $exp = ($v >> 23 & 0xFF) - 127;
  389. return $x * pow(2, $exp - 23);
  390. }
  391. private static function _getPackage($data){
  392. return ($data >> 24 == 1) ? 'android:' : '';
  393. }
  394.  
  395. private function getStringTab($base, $list){
  396. $tab = array();
  397. foreach ($list as $off){
  398. $off += $base;
  399. $len = $this->get16($off);
  400. $mask = ($len >> 0x8) & 0xFF;
  401. $len = $len & 0xFF;
  402. if ($len == $mask){
  403. if ($off + $len > $this->length) throw new Exception('String Table Overflow', 11);
  404. $tab[] = substr($this->xml, $off, $len);
  405. }else {
  406. if ($off + $len * 2 > $this->length) throw new Exception('String Table Overflow', 11);
  407. $str = substr($this->xml, $off, $len * 2);
  408. //$tab[] = mb_convert_encoding($str, 'UTF-8', 'UCS-2LE');
  409. $tab[] = iconv('UCS-2LE','UTF-8',$str);
  410. }
  411. }
  412. return $tab;
  413. }
  414. private function getString($id){
  415. if ($id > -1 && $id < $this->stringCount){
  416. return $this->stringTab[$id];
  417. }else {
  418. return '';
  419. }
  420. }
  421. private function getNameSpace($uri){
  422. for ($i=count($this->ns); $i > 0; ){
  423. $ns = $this->ns[--$i];
  424. if (isset($ns[$uri])){
  425. $ns = $this->getString($ns[$uri]);
  426. if (!empty($ns)) $ns .= ':';
  427. return $ns;
  428. }
  429. }
  430. return '';
  431. }
  432. private function get32(&$off){
  433. $int = unpack('V', substr($this->xml, $off, 4));
  434. $off += 4;
  435. return array_shift($int);
  436. }
  437. private function get32array(&$off, $size){
  438. if ($size <= 0) return NULL;
  439. $arr = unpack('V*', substr($this->xml, $off, 4 * $size));
  440. if (count($arr) != $size) throw new Exception('Array Size Error', 10);
  441. $off += 4 * $size;
  442. return $arr;
  443. }
  444. private function get16(&$off){
  445. $int = unpack('v', substr($this->xml, $off, 2));
  446. $off += 2;
  447. return array_shift($int);
  448. }
  449. private function skip($size){
  450. $this->xml = substr($this->xml, $size);
  451. $this->length -= $size;
  452. }
  453. }
  454. ?>

php获取apk信息的更多相关文章

  1. 获取apk信息工具(android SDK的aapt工具)

    aapt命令是android SDK 中的一个工具,功能强大,比如在windows平台获取apk包的信息. 使用该工具准备条件,也即获取aapt.exe文件的方式(2选1即可): 安装android ...

  2. Linux系统上使用php获取apk信息

    最近在做一个apk商城,需要在用户上传了apk之后系统自动读取apk信息(包名,版本号等),后台语言使用的是php,需要php去调用系统的aapt命令去读取apk信息,在Linux系统上安装aapt的 ...

  3. java通过解析文件获取apk版本等信息

    import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import ...

  4. 获取apk的签名信息

    在接入第三方功能时,经常要注册提交apk的签名信息 (sha1签名)?,下面列出相关步骤. 获取apk签名信息的步骤: 1)修改apk后缀名为zip,解压得到其中的META-INF文件夹; 2)把ME ...

  5. [置顶] Android Studio apk打包以及获取apk签名信息

    首先说下Android Studio 主要分为以下几步 填写你的签名的一些信息 (例如签名的文件名.省份.密码 别名 就是你比如叫xxx 但是别名是xx张三 认证年限就是apk过期默认是25年 其他就 ...

  6. C#获取apk版本信息

    获取很多人都会问我为什么要写这个博客,原因很简单,这次研发apk版本信息的时候网上查了很多的资料都没有这方面的信息,因此这次功能完了想写下方法,如果以后博友们遇到了可以直接copy,不用花很多的时间, ...

  7. aapt命令获取apk具体信息(包名、版本号号、版本号名称、兼容api级别、启动Activity等)

    aapt命令获取apk具体信息(包名.版本号号.版本号名称.兼容api级别.启动Activity等) 第一步:找到aapt 找到sdk的根文件夹,然后找到build-tools文件夹.然后会看到一些b ...

  8. Android apk签名详解——AS签名、获取签名信息、系统签名、命令行签名

    Apk签名,每一个Android开发者都不陌生.它就是对我们的apk加了一个校验参数,防止apk被掉包.一开始做Android开发,就接触到了apk签名:后来在微信开放平台.高德地图等平台注册时,需要 ...

  9. Unity3d获取APK签名及公钥的方法

    在Unity3d项目中获取APK包签名公钥的方法,核心思想就是通过JNI调用Android提供的方法.不过Unity3d提供了比JNI更上一层的类AndroidJavaObject以及继承它的Andr ...

随机推荐

  1. avalon.js实践 svg地图配置工具

    MVVM模式,在很多复杂交互逻辑下面,有很大的优势.现在相关的框架也很多,现在项目中使用了avalon.js,选择它的原因,是兼容性的考虑,当然也要支持下国内开发大牛,至于性能方面的,没有实际测试过, ...

  2. Html 笔记1

    标题(Heading)是通过 <h1> - <h6> 等标签进行定义的. <h1>这是标题</h1> 段落是通过 <p> 标签进行定义的. ...

  3. Orchard 源码探索(Application_Start)之异步委托调用

    2014年5月26日 10:26:31 晴 ASP.NET 接收到对应用程序中任何资源的第一个请求时,名为ApplicationManager 的类会创建一个应用程序域.应用程序域为全局变量提供应用程 ...

  4. cdn与http缓存

    http缓存与cdn相关技术   摘要:最近要做这个主题的组内分享,所以准备了一个星期,查了比较多的资料.准备的过程虽然很烦很耗时间,不过因为需要查很多的资料,因此整个过程下来,对这方面的知识影响更加 ...

  5. Linux宕机最安全的重启方法(你肯定不知道)

    Linux 内核虽然号称“不死族”,几乎不会崩溃或者死机,但是特殊情况下,还是有一定几率会宕机的.因为 Linux 广泛用于生产环境,所以每一次宕机都会引起相当大的损失.本文介绍在它死机至后,一种温柔 ...

  6. SSH Session Recorder

    If you want to record your root ssh session  create a file .bash_profile  . and copy below line by l ...

  7. UI设计中与字号有关的知识

    在我们设计APP.设计前端页面时,免不了要和各种文字大小打交道.字体的大小有多种单位,不明究里的话使用起来很容易出问题.今天整理了这方面的东西做了个图片,方便查看. 图上的资料来自互联网,感谢大家的负 ...

  8. Android updater-scripts(Edify Script)各函数详细说明(转)

    这是Android系统来运行updater-scripts的Edify语言的基本介绍. 大部分的Edify命名都是函数,当调用这些函数结束的时候,会返回数据给脚本.当然,你也可以使用这些函数的返回值来 ...

  9. 【POJ】2492 A bug's life ——种类并查集

    A Bug's Life Time Limit: 10000MS   Memory Limit: 65536K Total Submissions: 28211   Accepted: 9177 De ...

  10. opennebula kvm attach disk

    openNebula hotPlug disk or nic 网络检索关键字(Network search keywords) 208.117.233.122 virsh attach disk vi ...