在Android上运行PHP
为安卓交叉编译ARM版的PHP
目前手头上有一个古老的Android平板,系统为Android2.2,CPU 是armv5的架构,可以说是很古老了
想作为一个简易的服务器使用,便开始自己折腾.
本教程操作都在centos
docker容器内.基本工具都类似.
yum update && yum upgrade && yum install wget make perl -y
不用安装gcc
1.下载交叉编译工具 https://pan.baidu.com/s/1micZBWc
直连下载 wget http://share.suconghou.cn/files/arm/crossx86-arm-linux-musleabi-1.1.12.tar.xz
下载后解压,并添加bin到环境变量tar Jxf crossx86-arm-linux-musleabi-1.1.12.tar.xz
export PATH=/arm-linux-musleabi/bin:$PATH
之后,使用arm-linux-musleabi-gcc -v
可以验证
2.修改musl-libc库,目的是修改查找的DNS配置文件.
cd /tmp && wget --no-check-certificate https://www.musl-libc.org/releases/musl-1.1.16.tar.gz
下载并解压tar zxf musl-1.1.16.tar.gz && cd musl-1.1.16
替换1: 替换/etc/resolv.conf
grep -rn "/etc/resolv.conf" .
即可查找到有两个文件包含它.
接下来,我们把它替换掉,把路径替换为安卓安装文件夹可写的路径
sed -i "s{/etc/resolv.conf{/data/data/cn.suconghou.hello/files/resolv.conf{" ./src/network/resolvconf.c
sed -i "s{/etc/resolv.conf{/data/data/cn.suconghou.hello/files/resolv.conf{" ./include/resolv.h
可以再次查找,以验证是否替换成功
替换2: 替换/etc/hosts
grep -rn "/etc/hosts" .
即可查找到有三个文件,其中有一个是注释
下载执行替换,同样替换为一个我们可以写入的路径
sed -i "s{/etc/hosts{/data/data/cn.suconghou.hello/files/hosts{" ./src/network/getnameinfo.c
sed -i "s{/etc/hosts{/data/data/cn.suconghou.hello/files/hosts{" ./src/network/lookup_name.c
再次查找以验证是否替换成功
替换3: 替换/bin/sh
,使我们可以使用android的sh
grep -rn "/bin/sh" .
即可查找到较多结果,我们需要修改
./include/paths.h
./src/legacy/getusershell.c
./src/misc/wordexp.c
./src/process/system.c
./src/stdio/popen.c
这5个文件
sed -i "s{/bin/sh{/system/bin/sh{" ./include/paths.h
sed -i "s{/bin/sh{/system/bin/sh{" ./src/legacy/getusershell.c
sed -i "s{/bin/sh{/system/bin/sh{" ./src/misc/wordexp.c
sed -i "s{/bin/sh{/system/bin/sh{" ./src/process/system.c
sed -i "s{/bin/sh{/system/bin/sh{" ./src/stdio/popen.c
同样可以再次查找验证是否替换.
然后开始编译我们修改后的musl
./configure --prefix="/arm-linux-musleabi/arm-linux-musleabi" CC="arm-linux-musleabi-gcc"
make -j4 && make install
编译约需要5分钟,ls -lh /arm-linux-musleabi/arm-linux-musleabi/lib/
这些文件就是编译后生成的新文件.
注意这里编译使用的是arm-linux-musleabi-gcc而不是gcc,事实上,从头到尾我们都不需要gcc
之后开始第三步,编译PHP
3. 编译PHP
下载PHP最新源码,并解压
cd /tmp && wget http://php.net/distributions/php-7.1.8.tar.xz && tar xJf php-7.1.8.tar.xz && cd php-7.1.8
替换1: 同样,我们需要替换sh的路径, grep -rn "/bin/sh" .
有较多结果,我们需要替换./ext/standard/proc_open.c
sed -i "s{/bin/sh{/system/bin/sh{" ./ext/standard/proc_open.c
执行下面命令,把我们的编译命令都替换为交叉编译的命令
export HOST="arm-linux-musleabi"
export CC="arm-linux-musleabi-gcc"
export CXX="arm-linux-musleabi-g++"
export AR="arm-linux-musleabi-ar"
export LD="arm-linux-musleabi-ld"
export RANLIB="arm-linux-musleabi-ranlib"
export STRIP="arm-linux-musleabi-strip"
export CPPFLAGS="-I/deps/include"
export LDFLAGS="-L/deps/lib"
export SYSROOT_MUSL="/arm-linux-musleabi/arm-linux-musleabi"
我们先最小化编译PHP,生成Makefile
LDFLAGS="-static -L/deps/lib" CFLAGS="--sysroot=/arm-linux-musleabi/arm-linux-musleabi -Os" CXXFLAGS="--sysroot=/arm-linux-musleabi/arm-linux-musleabi -Os" ./configure --host=arm-linux-musleabi --enable-inline-optimization --enable-static=yes --enable-shared=no --without-pear --disable-cgi --disable-opcache --disable-fpm --disable-phpdbg --disable-all --enable-cli --enable-tokenizer
生成Makefile后,我们要修改Makefile使其静态编译.
sed -i "s{-I/usr/include{ {" Makefile
sed -i "s{-export-dynamic{-all-static{" Makefile
然后 make -j4 && make install
可以编译成功
原先的strip
命令,可以使用arm-linux-musleabi-strip
代替
添加其他扩展需要我们自己下载编译,下面这个几个是编译CURL所必须的.
1. zlib
cd /tmp && wget http://zlib.net/zlib-1.2.11.tar.gz
tar zxf zlib-1.2.11.tar.gz && cd zlib-1.2.11
CFLAGS="--sysroot=$SYSROOT_MUSL -Os" \
./configure \
--prefix=/deps \
--static
make && make install
2. bz2
cd /tmp && wget http://www.bzip.org/1.0.6/bzip2-1.0.6.tar.gz
tar zxf bzip2-1.0.6.tar.gz && cd bzip2-1.0.6
# 把 Makefile 里 CFLAGS 里的 -O2 改为 -Os 后面的 -g去掉 , 前面几行gcc部分等写死的直接删除
make install PREFIX=/deps
这些删除
# To assist in cross-compiling
CC=gcc
AR=ar
RANLIB=ranlib
LDFLAGS=
3. openssl
cd /tmp && wget https://www.openssl.org/source/openssl-1.0.2l.tar.gz
tar zxf openssl-1.0.2l.tar.gz && cd openssl-1.0.2l
CFLAGS="--sysroot=$SYSROOT_MUSL -static" \
./Configure \
linux-armv4 \
no-shared \
--prefix="/deps" \
--with-zlib-lib="/deps/lib" \
--with-zlib-include="/deps/include"
# 把 Makefile 里 CFLAG 里的 -O3 改为 -Os (vi 查找,第一个就是)
make && make install
4. curl
cd /tmp && wget https://curl.haxx.se/download/curl-7.54.0.tar.gz
tar zxf curl-7.54.0.tar.gz && cd curl-7.54.0
CC="arm-linux-musleabi-gcc --sysroot=$SYSROOT_MUSL" \
CXX="arm-linux-musleabi-g++ --sysroot=$SYSROOT_MUSL" \
CPPFLAGS="-I/deps/include" \
LDFLAGS="-static -L/deps/lib" \
./configure \
--prefix="/deps" \
--enable-zlib \
--disable-shared \
--with-ssl="/deps" \
--enable-static \
--host=$HOST
# 把 Makefile 里 CFLAGS 里的 -O2 改为 -Os
make -j4 && make install
包含我们需要的一些扩展 , 然后编译PHP(上次编译后,需make clean)
这次我们指定php.ini的文件位置
--with-config-file-scan-dir=/data/data/cn.suconghou.hello/files/conf.d --with-config-file-path=/data/data/cn.suconghou.hello/files
LDFLAGS="-static -L/deps/lib" CFLAGS="--sysroot=/arm-linux-musleabi/arm-linux-musleabi -Os" CXXFLAGS="--sysroot=/arm-linux-musleabi/arm-linux-musleabi -Os" ./configure --with-config-file-scan-dir="/data/data/cn.suconghou.hello/files/conf.d" --with-config-file-path="/data/data/cn.suconghou.hello/files" --host=arm-linux-musleabi --enable-inline-optimization --enable-static=yes --enable-shared=no --without-pear --disable-cgi --disable-opcache --disable-fpm --disable-phpdbg --disable-all --enable-cli --enable-tokenizer --enable-session --enable-json --enable-mbstring --enable-mbregex --enable-filter --enable-hash --enable-zip --enable-phar --with-sqlite3 --with-openssl=/deps --with-curl=/deps --with-zlib-dir=/deps
添加 --enable-zip --with-zlib-dir=/deps
启用zip和zlib扩展
--enable-pdo --with-pdo-sqlite --enable-sockets --enable-posix --enable-ftp
编译启用越多扩展,PHP进程的内存占用会稍微增加
同上面一样
生成Makefile后,我们要修改Makefile使其静态编译.
sed -i "s{-I/usr/include{ {" Makefile
sed -i "s{-export-dynamic{-all-static{" Makefile
然后 make -j4
编译,生成的文件在sapi/cli
文件夹中,编译已经成功,由于这次启用了phar,make install
时需要调用php命令Generating phar.php
,但php可执行文件在Linux x86_64
下无法执行,是arm环境的.因此不能执行make install
,但编译是完好的.
使用arm-linux-musleabi-strip
命令,可为我们编译的可执行文件瘦身.
最后编译的文件,能够运行于android2.2,服务于项目 https://github.com/suconghou/androidphp
问题
file_get_contents访问https时报错
file_get_contents(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed
这是由于证书引起的问题,使用curl访问可以正常访问.
使用下面语句可以查看openssl的默认证书配置
var_dump(openssl_get_cert_locations());
或者配置 file_get_contents 不验证https证书.
$stream_opts = [
"ssl" => [
"verify_peer"=>false,
"verify_peer_name"=>false,
]
];
$response = file_get_contents("https://www.example.com", false, stream_context_create($stream_opts));
或者在 php.ini 中添加 openssl.cafile=/path/to/cacert.pem
证书下载 https://curl.haxx.se/ca/cacert.pem