PHP 编译器 BPC 编译实战: tinyfilemanager (一个非常好的编译入门示例) - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
heguangyu5
V2EX    PHP

PHP 编译器 BPC 编译实战: tinyfilemanager (一个非常好的编译入门示例)

  •  1
     
  •   heguangyu5 2023-10-20 15:44:38 +08:00 1227 次点击
    这是一个创建于 723 天前的主题,其中的信息可能已经有所发展或是发生改变。

    昨天看到 peachpie 的 issue 里有一个 can ot work woth tinyfilemanager , 就点进去看了下这个 tinyfilemanager.

    Tiny File Manager 是一个 PHP 实现的单文件版的文件管理器, 4300 行代码, 实现了文件/目录管理,上传本地/网络文件,文件搜索,多语言/主题切换,压缩/解压 zip 文件等功能.

    在线 Demo 在这里: https://tinyfilemanager.github.io/demo/

    于是就想着拿 BPC 来编译一下,继而发现这是一个很好的 BPC 编译示例:

    1. 文件个数少,最多 3 个文件,容易说清楚
    2. BPC 编译时的常见问题都有
    3. 编译结果可以真的拿来用,不是个 hello world

    接下来就分享下编译过程,如果你能成功编译这个项目,那么大多数的其它 PHP 项目都能自己编译了.

    1.安装 BPC 编译器

    编译第 1 步当然是要安装 BPC 编译器,如果你是 ubuntu 18.04 系统,可以参考 Manual Installation 手动安装,使用起来也方便些.

    考虑到不少网友应该不是 ubuntu 18.04 的系统,这里采用 docker 安装:

    root@hgydebian12:~# docker run -it heguangyu5/bpc-compiler ... Status: Downloaded newer image for heguangyu5/bpc-compiler:latest root@1fb84d5cb51d:/bpc-workspace# bpc bpc/6.5.0 Usage: bpc [options] <input-files> [-- script args] see bpc -h for help with command line options root@1fb84d5cb51d:/bpc-workspace# exit 

    安装好之后退出 docker.

    2. 编译 tinyfilemanager

    要编译 tinyfilemanager, 需要对其源码做一些修改,具体修改了哪些地方稍后再说,现在先来编译运行.

    root@hgydebian12:~# git clone https://github.com/heguangyu5/tinyfilemanager.git Cloning into 'tinyfilemanager'... ... root@hgydebian12:~# cd tinyfilemanager/ root@hgydebian12:~# docker run -v `pwd`:/bpc-workspace -it heguangyu5/bpc-compiler root@d7107d2fabef:/bpc-workspace# ls 

    注意,这里多加了参数

    -v `pwd`:/bpc-workspace 

    将本机的 tinyfilemanager 目录映射到了 docker image 里的 /bpc-workspace,接下来执行一下 make 就编译好了.

    root@d7107d2fabef:/bpc-workspace# make ... generate code [1/2] /bpc-workspace/tinyfilemanager.php [2/2] /bpc-workspace/translation.json output prologue copy althttpd.c althttpd.h althttpd-bpc.scm generate build.ninja run ninja [7/7] link ../tinyfilemanager (statically linked) root@d7107d2fabef:/bpc-workspace# exit 

    退出 docker, 编译好的 tinyfilemanager 就在当前目录下:

    root@hgydebian12:~/tinyfilemanager# ls -lh tinyfilemanager -rwxr-xr-x 1 root root 19M Oct 20 12:22 tinyfilemanager 

    3. 运行 tinyfilemanager

    ldd 一下会发现缺少一些类库,当然可能在你的机器上不缺或者缺少的不一样:

    root@hgydebian12:~/tinyfilemanager# ldd tinyfilemanager ... libgmodule-2.0.so.0 => not found libgio-2.0.so.0 => not found libgobject-2.0.so.0 => not found libglib-2.0.so.0 => not found ... libcurl.so.4 => not found ... 

    在 ubuntu 18.04 / 20.04 / 22.04 以及 Debian 12 上,补上缺少的类库 tinyfilemanager 就能正常运行了, 运行命令是在当前目录执行:

    root@hgydebian12:~/tinyfilemanager# mkdir -p /tmp/tinyfilemanager/tmp && mkdir -p /tmp/tinyfilemanager/public && chown -R www-data:www-data /tmp/tinyfilemanager && ./tinyfilemanager -project-name bpc-workspace -port 7878 -home-page tinyfilemanager.php -root /tmp/tinyfilemanager/public -user www-data Listening for HTTP requests on 0.0.0.0:7878 

    在其它 linux 发行版上,或者不想安装缺少的类库,也可以使用 docker 来运行:

    root@hgydebian12:~/tinyfilemanager# make run-docker-docker-build ... Status: Downloaded newer image for heguangyu5/bpc-base:latest Listening for HTTP requests on 0.0.0.0:7878 

    此时访问 http://localhost:7878 或者 http://IP:7878 就能看到登录界面了.

    tinyfilemanager 默认有两个用户:

    admin admin@123 user 12345 

    4. 对 tinyfilemanager.php 做了哪些修改?

    @see git commit

    1. FM_Config::save()

      tinyfilemanager.php 的原本逻辑是将设置参数保存在 $CONFIG 变量中, 当参数变化时,直接修改 tinyfilemanager.php 文件自身来完成保存.

      BPC 编译后,只有一个二进制文件,显然这个逻辑需要调整,我们增加了一个 const CONFIG_FILE = '../config.json'; 将设置参数保存到 ../config.json 文件中.

      然后在一开始读取这个文件来初始化 $CONFIG.

    2. __DIR__.'/config.php'

      tinyfilemanager.php 支持使用 config.php 来覆盖默认选项,通过is_readable($config_file) 来判断是否 include 进来.

      BPC 可以通过调用内置函数 include_silent($config_file) 来实现同样的目的.

      我们知道 PHP include 一个文件时,如果这个文件不存在,会报一个 warning,然后继续执行,BPC 的这个include_silent() 函数如果遇到文件不存在,不会报 warning,然后继续执行.

    3. if (defined('__BPC__')) { /* BPC code*/ } else { /* PHP code */ }

      这个结构在 BPC 编译时只会保留下 BPC code, if/elsePHP code 直接丢掉了,类似于 C 语言的#ifdef #else #endif.

      当你需要在 PHP 环境下和在 BPC 编译时执行不同代码时,就可以用它.

    4. $_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(32));

      我们不想 link openssl 扩展,因为整个 tinyfilemanager.php 里只有这里用到.

    5. [] => array()

      BPC 自身不支持[]这样的数组写法,如果不想改代码,可以通过 phptobpc 进行转换.

    6. $use_curl = true;

      BPC 的copy不支持 copy url,所以从 URL 上传文件功能要用 curl 实现.

    7. FM_Zipper_Tar

      BPC 尚未实现 class PharData, 所以不支持压缩/解压tar文件.

      这里使用 if (defined('__BPC__')) 在 BPC 编译时消掉$tar = new FM_Zipper_Tar();代码是因为在 BPC 编译时,如果一个 class 从未声明过,那么它不能出现在代码里.

    8. translation.json

      BPC 支持将资源文件编译进二进制,默认后缀是.php,.inc,.phtml的文件被识别为代码文件,其它文件都认为是资源文件.编译时可以通过参数 --php-exts 来设置后缀.

      资源文件被 url 请求到时会返回其内容,如果要在 PHP 代码中获取资源文件,可以使用 BPC 内置函数resource_get_contents($resource_file) 来获取.

    9. if ($iswin && class_exists("COM")) {

      BPC 不支持 windows,也没有class COM,所以new COM()不能出现在代码里.

    5. 关于 bpc.conf

    @see git commit

    bpc.conf 定义了一个项目用到的扩展和static link时需要额外添加的 link 参数.

    BPC 6.5 支持的所有扩展列表如下:

    (extensions php-std php-posix php-date php-pcre php-mbstring php-json php-fileinfo php-curl php-sysvsem php-zlib php-session php-filter php-pdo php-pdo_mysql php-pdo_sqlite php-openssl php-ctype php-pcntl php-tinycdb php-hash php-scws php-xml php-iconv php-gd php-zip php-event php-mysqli php-gmp ) 

    tinyfilemanager.php 只用到了一部分,把没用到的扩展去掉,在 static link 时可以减小最终生成的二进制文件大小.

    6. 关于 Makefile

    @see git commit

    tinyfilemanager: bpc -v \ --static \ --althttpd \ -c bpc.conf \ -d max_execution_time=30 \ -d upload_max_filesize=50M \ -d post_max_size=60M \ -d memory_limit=512M \ -d log_errors=on \ -d date.timezOne=Asia/Shanghai \ -d sys_temp_dir=/tmp/tinyfilemanager/tmp \ -d session.gc_maxlifetime=604800 \ -d session.cookie_httpOnly=1 \ tinyfilemanager.php \ translation.json 
    • -v 显示编译过程,-v2 -v3 -v4 可以看到更多细节
    • --static 表示要 static link
    • --althttpd 表示要编译成 althttpd server, 详见PHP 编译器 BPC 6.2 发布,直接编译 php 文件为 web server!
    • -c 指定此次编译要用的bpc.conf,如果不指定,默认使用 /usr/local/etc/bpc.conf
    • -d 设定 php.ini 选项
    • tinyfilemanager.php translation.json 要编译的 PHP 源码文件和资源文件可以当作参数传入,也可以一行一个写在一个文件里(比如src.list)通过参数 --input-file src.list 传入.
    clean: @rm -rf .bpc-build-* md5.map 

    编译过程中生成的 scheme 代码 .scm.bpc-build-PID 目录里, 编译过程中会将 php 文件名,函数名进行 md5, md5 对照表保存在 md5.map 里.

    run-docker-docker-build: mkdir -p /tmp/tinyfilemanager/tmp && mkdir -p /tmp/tinyfilemanager/public && chown -R www-data:www-data /tmp/tinyfilemanager && docker run -v `pwd`:/bpc-app -v /tmp/tinyfilemanager:/tmp/tinyfilemanager -p 7878:7878 -it heguangyu5/bpc-base ./tinyfilemanager -project-name bpc-workspace -port 7878 -home-page tinyfilemanager.php -root /tmp/tinyfilemanager/public -user www-data 

    注意前边编译时设定了 php.ini 选项 sys_temp_dir=/tmp/tinyfilemanager/tmp, 这个目录用于保存临时文件和 session 文件.

    之所以要设定一个 tmp 目录有两个原因:

    1. tinyfilemanager 处理 URL 上传时,会生成一个临时文件,然后再把临时文件rename public 目录,当以 docker 方式运行时,从 docker 内部 rename 显然会失败.
    2. 登录时会生成 session,session 文件当没有指定 session.save_path 时会保存到 sys_tem_dir 中,这样我们在 docker 外部就能看到这些 session 文件.
    ./tinyfilemanager -project-name bpc-workspace -port 7878 -home-page tinyfilemanager.php -root /tmp/tinyfilemanager/public -user www-data 
    • -project-name 编译时 PHP 源代码所在的目录名
    • -port althttpd 监听的端口
    • -home-page 默认首页,不指定时为 index.php
    • -root 运行根目录
    • -user 以哪个用户身份运行
    目前尚无回复
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2694 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 12:09 PVG 20:09 LAX 05:09 JFK 08:09
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86