当前位置:首页 > PHP教程 > php应用 > 列表

php获取apk包信息的方法

发布:smiling 来源: PHP粉丝网  添加日期:2021-03-30 20:41:22 浏览: 评论:0 

这篇文章主要介绍了php获取apk包信息的方法,非常实用的功能,需要的朋友可以参考下,有时候在使用php上传安卓apk包的时候,我们需要获取安卓apk包内的信息,本文以实例形式讲述了php获取apk包信息的方法。具体实现方法如下:

  1. <?php 
  2. /*解析安卓apk包中的压缩XML文件,还原和读取XML内容 
  3. 依赖功能:需要PHP的ZIP包函数支持。*/ 
  4. include('./Apkparser.php'); 
  5. $appObj  = new Apkparser();  
  6. $targetFile = a.apk;//apk所在的路径地址 
  7. $res   = $appObj->open($targetFile); 
  8. $appObj->getAppName();     // 应用名称 
  9. $appObj->getPackage();    // 应用包名 
  10. $appObj->getVersionName();  // 版本名称 
  11. $appObj->getVersionCode();  // 版本代码 
  12. ?> 

以下是Apkparser类包,把以下代码复制出来保存为Apkparser.php就可以执行以上代码。

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

感兴趣的朋友可以调试运行一下本文实例,相信会对大家的php程序开发带来一定的启发。

Tags: php获取apk包

分享到: