`
junpub
  • 浏览: 10012 次
社区版块
存档分类
最新评论

PHP获取android文件的相关信息

    博客分类:
  • php
阅读更多
/**
解析安卓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 获取安卓apk信息”时,我们通常是指通过PHP脚本来解析和提取Android应用(APK)的元数据,如应用名称、版本号、权限、图标等。这个过程涉及到对APK文件的解包和分析,而不仅仅局限于读取简单的文本...

    php获取apk信息包名应用名版本

    在PHP环境中,我们可能需要获取APK文件的一些元数据信息,例如包名、应用名称、版本名称、支持的屏幕尺寸和语言等。这在自动化部署、应用分析或者构建与APK相关的服务时非常有用。以下是如何使用PHP来实现这些功能的...

    PHP 读取 Android APK XML文件,无需JDK

    在给定的场景中,我们需要使用PHP来处理Android APK文件,这是一个包含Android应用所有资源和代码的压缩文件。APK文件是基于Java的,通常需要JDK(Java Development Kit)来解析其内部结构,但在这个特定情况下,...

    安卓文件下载上传解压相关-android上传图片php接收.rar

    在安卓(Android)平台上,文件的下载、上传和解压是常见的操作,尤其涉及到用户交互时,例如上传图片到服务器。本示例中,我们关注的是一个安卓应用如何上传图片到PHP服务器,以及如何处理服务器端的数据。我们将...

    制作个php网页,当访问该PHP页面时自动下载文件,本例为下载APK APP安装包.zip

    PHP的`$_SERVER`全局数组包含了诸如`REQUEST_URI`, `HTTP_HOST`, `PHP_SELF`等信息,可用于构建完整的URL和文件路径。注意URL与文件系统的路径格式差异,URL通常使用正斜杠,而文件系统路径可能依赖于操作系统。 7...

    android通过PHP操作mysql例子

    在Android开发中,有时我们需要与服务器进行数据交互,例如存储用户信息、获取商品列表等,这时可以使用PHP作为服务器端语言来处理数据,并通过MySQL数据库存储这些数据。本示例将详细讲解如何在Android应用中通过...

    ecshop 客户端包含服务端php接口文件,android客户端和ios客户端

    ECShop iOS客户端将与Android客户端类似,使用PHP接口与服务器交互,获取商品信息、处理订单、管理用户账户等。 PHP接口文件是ECShop客户端与服务器间通信的关键。这些文件通常位于ECShop服务器的后端,负责处理...

    Android 和php交互上传图片文件功能

    Android与PHP之间的图片上传功能涉及到客户端与服务器端的通信协议、文件处理、网络请求、安全策略等多个方面。理解并掌握这些知识点对于开发稳健、高效的移动应用至关重要。同时,随着技术的发展,现代框架和库提供...

    连接android和php+mysql数据库

    在 test.php 文件中,可以输入一些简单的 PHP 代码,例如输出“Welcome, I am connecting Android to PHP, MySQL”。 创建 MySQL 数据库和表 在 phpmyadmin 中,可以创建一个新的数据库和表。例如,可以创建一个名...

    PHP解析APK包获取所有信息

    本文将深入探讨如何利用PHP解析APK包,获取其中包含的各种元数据,如应用名称、版本信息、图标名以及包名等关键信息。 首先,我们需要了解APK文件的本质。APK是Android系统中应用的安装包格式,它实际上是一个ZIP...

    安卓客户端上传文件到php服务器

    在安卓应用开发中,将文件从客户端上传到服务器是一个常见的需求。本项目专注于使用OkHttp组件结合PHP服务器的Ajax处理来实现这一功能。下面将详细解释这个过程中的关键知识点。 首先,**安卓客户端**通常使用HTTP...

    android手机文件上传和下载

    在Android平台上,文件的上传和下载是常见的操作,尤其在移动应用中,用户可能需要将本地数据同步到云端,或者从服务器获取数据。本教程主要涵盖两个方面:Android手机文件的上传和下载,以及如何使用XAMPP搭建后端...

    Android开发简单获取网页数据

    在Android开发中,获取网页数据是一项常见的任务,无论是从ASPX、PHP或其他类型的网页服务器获取信息,都是通过网络请求来实现的。本文将详细介绍如何在Android应用中简单地获取网页数据,以及涉及到的关键技术。 ...

    php入口文件自动判断手机web端跳转

    综上所述,实现“php入口文件自动判断手机web端跳转”的主要步骤包括获取并解析User-Agent信息、检测屏幕分辨率或者利用JavaScript辅助判断。结合这些方法,可以有效地为你的PHP应用创建一个响应式的入口,为不同...

    php作为服务器接收iOS/Android上传的图片

    对于多部分表单数据,可以使用PHP的`$_FILES`全局变量来获取上传的文件信息。然后,PHP可以将图片保存到服务器的指定目录,使用`move_uploaded_file()`函数完成这个操作。 5. **图片加水印**:虽然本例中并未实际...

    php获取apk包信息的方法

    标题中提到的“php获取apk包信息的方法”涉及的是如何使用PHP语言来解析安卓应用的安装包(APK文件),从而获取APK文件中包含的特定信息。在Android平台,APK文件是一个ZIP格式的压缩包,用于分发和安装移动应用。...

    Android market api for php

    标题中的“Android Market API for PHP”指的是一个PHP库或服务,它允许开发者通过编程方式与Google Play(原Android Market)进行交互,获取有关应用商店中应用程序的信息,如排名、评分、评论等。这个API通常对...

    基于PHP的应用+安卓数据管理系统php版正式版源码.zip

    安卓客户端通过发送HTTP请求来获取或更新数据,PHP服务器端处理这些请求,操作数据库,并将结果返回给客户端。 开发这样一个系统,开发者需要掌握PHP基础知识,如面向对象编程、错误处理、数据库操作等,还需要理解...

    安卓Android源码——与php服务器交互实例源码.zip

    在安卓(Android)开发中,与服务器进行交互是常见的需求,尤其当涉及到数据的获取、存储或更新时。本实例源码着重展示了如何在Android应用中通过PHP服务器进行数据通信。下面将详细解释这一过程涉及的关键知识点。 ...

    android文件的上传和下载+后台完整代码

    - Android中的文件上传通常使用`Multipart`请求,因为它们可以携带不同类型的文件数据和元信息。 - `OkHttp`库提供了方便的`RequestBody`接口,可以创建`MultipartBody`以封装文件和元数据。 - 文件读取可能需要`...

Global site tag (gtag.js) - Google Analytics