/** 解析安卓apk包中的压缩XML文件,还原和读取XML内容 依赖功能:需要PHP的ZIP包函数支持。 */ include('Apkparser.php'); $appObj = new Apkparser(); $targetFile = 'baidu.apk';//apk所在的路径地址 $res = $appObj->open($targetFile); echo $appObj->getAppName(); // 应用名称 echo '<br>'.$appObj->getPackage(); // 应用包名 echo '<br>'.$appObj->getVersionName(); // 版本名称 echo '<br>'.$appObj->getVersionCode(); // 版本代码
以下是Apkparser类包,把以下代码复制出来保存为Apkparser.php就可以执行以上代码
<?php class ApkParser{ //---------------------- // 公共函数,供外部调用 //---------------------- public function open($apk_file, $xml_file='AndroidManifest.xml'){ $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 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'); } } 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信息”时,我们通常是指通过PHP脚本来解析和提取Android应用(APK)的元数据,如应用名称、版本号、权限、图标等。这个过程涉及到对APK文件的解包和分析,而不仅仅局限于读取简单的文本...
在PHP环境中,我们可能需要获取APK文件的一些元数据信息,例如包名、应用名称、版本名称、支持的屏幕尺寸和语言等。这在自动化部署、应用分析或者构建与APK相关的服务时非常有用。以下是如何使用PHP来实现这些功能的...
在给定的场景中,我们需要使用PHP来处理Android APK文件,这是一个包含Android应用所有资源和代码的压缩文件。APK文件是基于Java的,通常需要JDK(Java Development Kit)来解析其内部结构,但在这个特定情况下,...
在安卓(Android)平台上,文件的下载、上传和解压是常见的操作,尤其涉及到用户交互时,例如上传图片到服务器。本示例中,我们关注的是一个安卓应用如何上传图片到PHP服务器,以及如何处理服务器端的数据。我们将...
PHP的`$_SERVER`全局数组包含了诸如`REQUEST_URI`, `HTTP_HOST`, `PHP_SELF`等信息,可用于构建完整的URL和文件路径。注意URL与文件系统的路径格式差异,URL通常使用正斜杠,而文件系统路径可能依赖于操作系统。 7...
在Android开发中,有时我们需要与服务器进行数据交互,例如存储用户信息、获取商品列表等,这时可以使用PHP作为服务器端语言来处理数据,并通过MySQL数据库存储这些数据。本示例将详细讲解如何在Android应用中通过...
ECShop iOS客户端将与Android客户端类似,使用PHP接口与服务器交互,获取商品信息、处理订单、管理用户账户等。 PHP接口文件是ECShop客户端与服务器间通信的关键。这些文件通常位于ECShop服务器的后端,负责处理...
Android与PHP之间的图片上传功能涉及到客户端与服务器端的通信协议、文件处理、网络请求、安全策略等多个方面。理解并掌握这些知识点对于开发稳健、高效的移动应用至关重要。同时,随着技术的发展,现代框架和库提供...
在 test.php 文件中,可以输入一些简单的 PHP 代码,例如输出“Welcome, I am connecting Android to PHP, MySQL”。 创建 MySQL 数据库和表 在 phpmyadmin 中,可以创建一个新的数据库和表。例如,可以创建一个名...
本文将深入探讨如何利用PHP解析APK包,获取其中包含的各种元数据,如应用名称、版本信息、图标名以及包名等关键信息。 首先,我们需要了解APK文件的本质。APK是Android系统中应用的安装包格式,它实际上是一个ZIP...
在安卓应用开发中,将文件从客户端上传到服务器是一个常见的需求。本项目专注于使用OkHttp组件结合PHP服务器的Ajax处理来实现这一功能。下面将详细解释这个过程中的关键知识点。 首先,**安卓客户端**通常使用HTTP...
在Android平台上,文件的上传和下载是常见的操作,尤其在移动应用中,用户可能需要将本地数据同步到云端,或者从服务器获取数据。本教程主要涵盖两个方面:Android手机文件的上传和下载,以及如何使用XAMPP搭建后端...
在Android开发中,获取网页数据是一项常见的任务,无论是从ASPX、PHP或其他类型的网页服务器获取信息,都是通过网络请求来实现的。本文将详细介绍如何在Android应用中简单地获取网页数据,以及涉及到的关键技术。 ...
综上所述,实现“php入口文件自动判断手机web端跳转”的主要步骤包括获取并解析User-Agent信息、检测屏幕分辨率或者利用JavaScript辅助判断。结合这些方法,可以有效地为你的PHP应用创建一个响应式的入口,为不同...
对于多部分表单数据,可以使用PHP的`$_FILES`全局变量来获取上传的文件信息。然后,PHP可以将图片保存到服务器的指定目录,使用`move_uploaded_file()`函数完成这个操作。 5. **图片加水印**:虽然本例中并未实际...
标题中提到的“php获取apk包信息的方法”涉及的是如何使用PHP语言来解析安卓应用的安装包(APK文件),从而获取APK文件中包含的特定信息。在Android平台,APK文件是一个ZIP格式的压缩包,用于分发和安装移动应用。...
标题中的“Android Market API for PHP”指的是一个PHP库或服务,它允许开发者通过编程方式与Google Play(原Android Market)进行交互,获取有关应用商店中应用程序的信息,如排名、评分、评论等。这个API通常对...
安卓客户端通过发送HTTP请求来获取或更新数据,PHP服务器端处理这些请求,操作数据库,并将结果返回给客户端。 开发这样一个系统,开发者需要掌握PHP基础知识,如面向对象编程、错误处理、数据库操作等,还需要理解...
在安卓(Android)开发中,与服务器进行交互是常见的需求,尤其当涉及到数据的获取、存储或更新时。本实例源码着重展示了如何在Android应用中通过PHP服务器进行数据通信。下面将详细解释这一过程涉及的关键知识点。 ...
- Android中的文件上传通常使用`Multipart`请求,因为它们可以携带不同类型的文件数据和元信息。 - `OkHttp`库提供了方便的`RequestBody`接口,可以创建`MultipartBody`以封装文件和元数据。 - 文件读取可能需要`...