php读取apk文件信息的方式大致有两种:
一种是借助于桥接方式启动java来读取包内容;
二是借助于外调aapt,获取包内容。
今天说的是外调aapt方式。
这种方式的弊端,是会降低服务器的安全性,我今天要说的,就是要权限控制+selinux来对启动exec的php环境,进行配置,以支持aapt读取apk包内容。
环境:
centos7.1 + nginx +php5.4 +mysql + laravel
首先要说的是,不要停用selinux,这个系统自带的安全工具,一定程度上来说是比较有用的,对系统的防护能够起到支持作用。它能够细化到对进程的权限控制,因此是很不错的。
安装aapt:
可参照这个地址的内容:http://www.aichengxu.com/view/25283
摘录一下,以防丢失。
首先,安装apktool包
1. wget http://android-apktool.googlecode.com/files/apktool-install-linux-r04-brut1.tar.bz2
2.
tar -jxvf apktool-install-linux-r04-brut1.tar.bz2
3.
mv aapt /usr/bin
mv apktool /usr/bin
以上三步,完成了apktool包的安装
那么在64位操作系统下去执行aapt命令的话会报一下错误:
-bash: /usr/bin/aapt: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory
原因在于:64位系统中安装了32位程序。 apktool是32位
那么为了解决以上问题,我们需要安装:glibc.i686,zlib.i686,libstdc++.i686
如果你是云主机,那么很可能执行以下明步骤的时候会提示你:
No package glibc.i686 available
No package zlib.i686 available.
No package libstdc.i686 available.
原因是云主机一般配置的都是纯净64位系统
到这个步骤的时候,我们就要去修改yum 配置文件了,如下:
在/etc/yum.conf里面有
exclude选项,把这行删掉就可以了
现在去执行以下三步操作,那么appt命令就可以正常执行了
1.yum install glibc.i686之后发现如下错误error while loading shared libraries: libz.so.1,ok继续安装libz2.sudo yum install zlib.i686之后发现error while loading shared libraries: libstdc++.so.6,执行3.sudo yum install libstdc++.i686
安装7z:
7z官网上就可找到链接。
另外可在这里下载:http://sourceforge.net/projects/p7zip/files/p7zip/9.38.1/p7zip_9.38.1_x86_linux_bin.tar.bz2
下载之后解压了,运行install.sh就行了,无需编译。
到此为止,我们已经完成了工具的安装。
这两个工具的作用:
aapt当然是直接获取xml文件中的描述性内容;7z用来解压apk文件,抽取其中的图标文件用来在网站上直观地显示。
谨慎起见,请把安装的这两个工具,拷贝到网站的public/bin目录,这样做的目的,是为了不改变系统目录的selinux标签,也无需改变目录权限。
如果正常情况下,路径是:/usr/bin/aapt 和 /usr/local/bin/7z;没有的话,可以whereis命令。
可以试验一下,运行aapt和7z命令,看是否正常执行。
下面是关键一步:
为你的应用程序目录,添加selinux可执行标签:
chcon -R -h -t httpd_sys_script_exec_t bin/
当然,bin目录的权限也要设置好:
chmod -R 766 bin/
完成apk解析的php函数过程了:
大致的贴一下,可参考:
//读取apk文件信息
function PopApkInfo($apk_file)
{
exec('/www/public/bin/aapt dump badging '.$apk_file, $out, $return);
$temp_path = '/www/public/uploads/icon/'.md5($apk_file).'/';
$relative_path='/uploads/icon/'.md5($apk_file).'/';
if($return == 0)
{
mkdir($temp_path);
$str_out = implode("\n", $out);
$out = null;
#icon
$pattern_icon = "/icon='(.+)'/isU";
preg_match($pattern_icon, $str_out, $m);
$info['icon'] = $m[1];
if($info['icon'])
{
$command = '/www/public/bin/7z e ' . $apk_file . ' -y -aos -o' . $temp_path . ' ' . $info['icon'];
exec($command);
$barPosition=strrpos($info['icon'],'/');
if($barPosition != false)
{
$iconPath=substr($info['icon'], $barPosition);
}
else
{
$iconPath=$info['icon'];
}
$info['icon'] = $relative_path . $iconPath;
}
#对外显示名称
$pattern_name = "/application: label='(.*)'/isU";
preg_match($pattern_name, $str_out,$m);
$info['lable']=$m[1];
#内部名称,软件唯一的
$pattern_sys_name = "/package: name='(.*)'/isU";
preg_match($pattern_sys_name, $str_out,$m);
$info['sys_name']=$m[1];
#内部版本名称,用于检查升级
$pattern_version_code = "/versionCode='(.*)'/isU";
preg_match($pattern_version_code, $str_out,$m);
$info['version_code']=$m[1];
#对外显示的版本名称
$pattern_version = "/versionName='(.*)'/isU";
preg_match($pattern_version, $str_out,$m);
$info['version']=$m[1];
#系统
$pattern_sdk = "/sdkVersion:'(.*)'/isU";
if(preg_match($pattern_sdk, $str_out,$m))
{
$info['sdk_version']=$m[1];
if($info['sdk_version'])
{
$sdk_names = array(3=>"1.5",4=>"1.6",7=>"2.1",8=>"2.2",10=>'2.3.3',11=>"3.0",12=>"3.1",13=>"3.2",14=>"4.0");
if($sdk_names[$info['sdk_version']])
{
$info['os_req'] = "Android {$sdk_names[$info['sdk_version']]}";
}
}
}
#权限
$pattern_perm = "/uses-permission:'(.*)'/isU";
preg_match_all($pattern_perm, $str_out,$m);
if(isset($m[1]))
{
foreach($m[1] as $mm)
{
$info['permissions'][] = $mm;
}
}
#需要的功能(硬件支持)
$pattern_features = "/uses-feature:'(.*)'/isU";
preg_match_all($pattern_features, $str_out,$m);
if(isset($m[1]))
{
foreach($m[1] as $mm)
{
$info['features'][] = $mm;
}
}
$info['apk_info'] = $str_out;
return $info;
}
return false;
}
}