类库下载 PHP类库 PHP获取APK的包信息

PHP获取APK的包信息

Oct 08, 2016 pm 05:35 PM

php上传安卓apk包的时候,需要获取安卓apk包内的信息
<?php

/*解析安卓apk包中的压缩XML文件,还原和读取XML内容

依赖功能:需要PHP的ZIP包函数支持。*/

include(&#39;./Apkparser.php&#39;);

$appObj    = new Apkparser(); 

$targetFile = a.apk;//apk所在的路径地址

$res     = $appObj->open($targetFile);

$appObj->getAppName();         // 应用名称

$appObj->getPackage();        // 应用包名

$appObj->getVersionName();    // 版本名称

$appObj->getVersionCode();    // 版本代码
?>
以下是Apkparser类包,把以下代码复制出来保存为Apkparser.php就可以执行以上代码
<?php
class ApkParser{
//----------------------
// 公共函数,供外部调用
//----------------------
  public function open($apk_file, $xml_file=&#39;AndroidManifest.xml&#39;){
    $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 &#39;&#39;;
 
    if ($node[&#39;type&#39;] == self::END_TAG) $lv--;
    $xml = @($node[&#39;line&#39;] == 0 || $node[&#39;line&#39;] == $this->line) ? &#39;&#39; : "\n".str_repeat(&#39;  &#39;, $lv);
    $xml .= $node[&#39;tag&#39;];
    $this->line = @$node[&#39;line&#39;];
    foreach ($node[&#39;child&#39;] as $c){
      $xml .= $this->getXML($c, $lv+1);
    }
    return $xml;
  }
 
  public function getPackage(){
    return $this->getAttribute(&#39;manifest&#39;, &#39;package&#39;);
  }
 
  public function getVersionName(){
    return $this->getAttribute(&#39;manifest&#39;, &#39;android:versionName&#39;);
  }
 
  public function getVersionCode(){
    return $this->getAttribute(&#39;manifest&#39;, &#39;android:versionCode&#39;);
  }
 
  public function getAppName(){
    return $this->getAttribute(&#39;manifest/application&#39;, &#39;android:name&#39;);
  }
 
  public function getMainActivity(){
    for ($id=0; true; $id++){
      $act = $this->getAttribute("manifest/application/activity[{$id}]/intent-filter/action", &#39;android:name&#39;);
      if (!$act) break;
      if ($act == &#39;android.intent.action.MAIN&#39;) return $this->getActivity($id);
    }
    return NULL;
  }
 
  public function getActivity($idx=0){
    $idx = intval($idx);
    return $this->getAttribute("manifest/application/activity[{$idx}]", &#39;android:name&#39;);
  }
 
  public function getAttribute($path, $name){
    $r = $this->getElement($path);
    if (is_null($r)) return NULL;
 
    if (isset($r[&#39;attrs&#39;])){
      foreach ($r[&#39;attrs&#39;] as $a){
        if ($a[&#39;ns_name&#39;] == $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=&#39;&#39;;
  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(&#39;/&#39;, $path);
    $r  = $this->root;
    foreach ($ps as $v){
      if (preg_match(&#39;/([^\[]+)\[([0-9]+)\]$/&#39;, $v, $ms)){
        $v = $ms[1];
        $off = $ms[2];
      }else {
        $off = 0;
      }
      foreach ($r[&#39;child&#39;] as $c){
        if ($c[&#39;type&#39;] == self::START_TAG && $c[&#39;ns_name&#39;] == $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(&#39;Block Type Error&#39;, 1);
    $size = $this->get32($o);
    if ($size < 8 || $size > $this->length) throw new Exception(&#39;Block Size Error&#39;, 2);
    $left = $this->length - $size;
 
    $props = false;
    switch ($type){
      case self::AXML_FILE:
        $props = array(
          &#39;line&#39; => 0,
          &#39;tag&#39; => &#39;<?xml version="1.0" encoding="utf-8"?>&#39;
        );
      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(
          &#39;line&#39; => $line,
          &#39;ns&#39; => $this->getNameSpace($this->get32($o)),
          &#39;name&#39; => $this->getString($this->get32($o)),
          &#39;flag&#39; => $this->get32($o),
          &#39;count&#39; => $this->get16($o),
          &#39;id&#39; => $this->get16($o)-1,
          &#39;class&#39; => $this->get16($o)-1,
          &#39;style&#39; => $this->get16($o)-1,
          &#39;attrs&#39; => &$attrs
        );
        $props[&#39;ns_name&#39;] = $props[&#39;ns&#39;].$props[&#39;name&#39;];
        for ($i=0; $i < $props[&#39;count&#39;]; $i++){
          $a = array(
            &#39;ns&#39; => $this->getNameSpace($this->get32($o)),
            &#39;name&#39; => $this->getString($this->get32($o)),
            &#39;val_str&#39; => $this->get32($o),
            &#39;val_type&#39; => $this->get32($o),
            &#39;val_data&#39; => $this->get32($o)
          );
          $a[&#39;ns_name&#39;] = $a[&#39;ns&#39;].$a[&#39;name&#39;];
          $a[&#39;val_type&#39;] >>= 24;
          $attrs[] = $a;
        }
        // 处理TAG字符串
        $tag = "<{$props[&#39;ns_name&#39;]}";
        foreach ($this->cur_ns as $uri => $prefix){
          $uri = $this->getString($uri);
          $prefix = $this->getString($prefix);
          $tag .= " xmlns:{$prefix}=\"{$uri}\"";
        }
        foreach ($props[&#39;attrs&#39;] as $a){
          $tag .= " {$a[&#39;ns_name&#39;]}=\"".
              $this->getAttributeValue($a).
              &#39;"&#39;;
        }
        $tag .= &#39;>&#39;;
        $props[&#39;tag&#39;] = $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(
          &#39;line&#39; => $line,
          &#39;ns&#39; => $this->getNameSpace($this->get32($o)),
          &#39;name&#39; => $this->getString($this->get32($o))
        );
        $props[&#39;ns_name&#39;] = $props[&#39;ns&#39;].$props[&#39;name&#39;];
        $props[&#39;tag&#39;] = "</{$props[&#39;ns_name&#39;]}>";
        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(
          &#39;tag&#39; => $this->getString($this->get32($o))
        );
        $o += 8;
      break;
      default:
        throw new Exception(&#39;Block Type Error&#39;, 3);
      break;
    }
 
    $this->skip($o);
    $child = array();
    while ($this->length > $left){
      $c = $this->parseBlock();
      if ($props && $c) $child[] = $c;
      if ($left == -1 && $c[&#39;type&#39;] == self::END_TAG){
        $left = $this->length;
        break;
      }
    }
    if ($this->length != $left) throw new Exception(&#39;Block Overflow Error&#39;, 4);
    if ($props){
      $props[&#39;type&#39;] = $type;
      $props[&#39;size&#39;] = $size;
      $props[&#39;child&#39;] = $child;
      return $props;
    }else {
      return false;
    }
  }
 
  private function getAttributeValue($a){
    $type = &$a[&#39;val_type&#39;];
    $data = &$a[&#39;val_data&#39;];
    switch ($type){
      case self::TYPE_STRING:
        return $this->getString($a[&#39;val_str&#39;]);
      case self::TYPE_ATTRIBUTE:
        return sprintf(&#39;?%s%08X&#39;, self::_getPackage($data), $data);
      case self::TYPE_REFERENCE:
        return sprintf(&#39;@%s%08X&#39;, self::_getPackage($data), $data);
      case self::TYPE_INT_HEX:
        return sprintf(&#39;0x%08X&#39;, $data);
      case self::TYPE_INT_BOOLEAN:
        return ($data != 0 ? &#39;true&#39; : &#39;false&#39;);
      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(&#39;#%08X&#39;, $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(&#39;<0x%X, type 0x%02X>&#39;, $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) ? &#39;android:&#39; : &#39;&#39;;
  }
 
  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(&#39;String Table Overflow&#39;, 11);
        $tab[] = substr($this->xml, $off, $len);
      }else {
        if ($off + $len * 2 > $this->length) throw new Exception(&#39;String Table Overflow&#39;, 11);
        $str = substr($this->xml, $off, $len * 2);
        $tab[] = mb_convert_encoding($str, &#39;UTF-8&#39;, &#39;UCS-2LE&#39;);
      }
    }
    return $tab;
  }
  private function getString($id){
    if ($id > -1 && $id < $this->stringCount){
      return $this->stringTab[$id];
    }else {
      return &#39;&#39;;
    }
  }
  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 .= &#39;:&#39;;
        return $ns;
      }
    }
    return &#39;&#39;;
  }
  private function get32(&$off){
    $int = unpack(&#39;V&#39;, substr($this->xml, $off, 4));
    $off += 4;
    return array_shift($int);
  }
  private function get32array(&$off, $size){
    if ($size <= 0) return NULL;
    $arr = unpack(&#39;V*&#39;, substr($this->xml, $off, 4 * $size));
    if (count($arr) != $size) throw new Exception(&#39;Array Size Error&#39;, 10);
    $off += 4 * $size;
    return $arr;
  }
  private function get16(&$off){
    $int = unpack(&#39;v&#39;, substr($this->xml, $off, 2));
    $off += 2;
    return array_shift($int);
  }
  private function skip($size){
    $this->xml = substr($this->xml, $size);
    $this->length -= $size;
  }
}
?>
로그인 후 복사
<br/>
로그인 후 복사


본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)