有时候在使用php上传安卓apk包的时候,我们需要获取安卓apk包内的信息,,本文以实例形式讲述了php获取apk包信息的方法。具体实现方法如下:
open($targetfile);$appobj->getappname();// 应用名称$appobj->getpackage(); // 应用包名$appobj->getversionname(); // 版本名称$appobj->getversioncode(); // 版本代码?>
以下是apkparser类包,把以下代码复制出来保存为apkparser.php就可以执行以上代码
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 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 $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' => '');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 $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 = 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 ', $data, $type); } private function _complextofloat($data){return (float)($data & 0xffffff00) * self::$radix_mults[($data>>4) & 3]; } private function _int2float($v) {$x = ($v & ((1 > 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');}}return $tab; } private function getstring($id){if ($id > -1 && $id 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 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; }}//---------------------//apkparser类包结束 //---------------------?>
感兴趣的朋友可以调试运行一下本文实例,相信会对大家的php程序开发带来一定的启发。
