PHP编译器BPC6.4发布,成功编译webman,PHP项目二进制打包,源码保护,软件授权 All in One!

不了解BPC是什么的可以翻看之前的文章.

简言之,BPC可以将PHP代码最终转译成C语言,然后编译成动态链接库或者可执行程序,实现 PHP Native AOT!

how BPC works

0. 前置说明

本文所述的所有操作都是在 Ubuntu 18.04 amd64 上完成的,但这并不是说BPC只能在 Ubuntu 18.04 上运行.

BPC编译器自身已验证过可以在 Ubuntu 18.04 / 20. 04 / 22.04 上运行,编译结果还可以在 Debian 12 上运行, 参看 wordpress的例子.

1. 快速体验二进制版的webman

  1. 下载编译好的二进制文件 start

  2. 加上可执行权限 chmod +x start

  3. 运行 mkdir /tmp/x && mv start /tmp/x && cd /tmp/x && ./start start

  4. 另外打开一个终端

    ~$ tree /tmp/x/
    /tmp/x/
    ├── runtime
    │   ├── logs
    │   │   └── workerman.log
    │   ├── views
    │   └── webman.pid
    └── start
    3 directories, 3 files
  5. 访问以下url查看效果

2. 亲自动手编译webman

  1. 参看文档下载安装 BPC

    ~$ bpc
    bpc/6.4.0
    Usage: bpc [options] <input-files> [-- script args]
    see bpc -h for help with command line options
  2. 下载安装phptobpc 来解决BPC不支持的语法特性

    phptobpc就是个phar文件,下载回来后加上可执行权限,放到 ~/bin/ 或者 /usr/local/bin/ 目录下即可.
    由于是phar文件,当然需要php解释器,sudo apt install php-cli 即可.

    ~$ phptobpc 
    Usage: php phptobpc.php file.php
  3. 参照以下 git repo README.md 开头的 BPC Notes 编译安装webman依赖

    1. psr-log-1.1.4

    2. psr-container-2.0.1

    3. nikic-fast-route-1.3.0

    4. monolog-2.x-branch

    5. workerman-4.1-branch

    6. webman-framework

    结果如下:

    ~$ cd /usr/local/lib/
    ​
    /usr/local/lib$ ls *psr*
    libpsr-container_u-4.4a.a   libpsr-log_u-4.4a.a   psr-container.heap  psr-log.heap
    libpsr-container_u-4.4a.so  libpsr-log_u-4.4a.so  psr-container.sch   psr-log.sch
    ​
    /usr/local/lib$ ls *fastroute*
    fastroute.heap  fastroute.sch  libfastroute_u-4.4a.a  libfastroute_u-4.4a.so
    ​
    /usr/local/lib$ ls *monolog*
    libmonolog_u-4.4a.a  libmonolog_u-4.4a.so  monolog.heap  monolog.sch
    ​
    /usr/local/lib$ ls *workerman*
    libworkerman_u-4.4a.a  libworkerman_u-4.4a.so  workerman.heap  workerman.sch
    ​
    /usr/local/lib$ ls *webman*
    libwebman_u-4.4a.a  libwebman_u-4.4a.so  webman.heap  webman.sch
  4. 编译运行webman

    ~$ git clone git@github.com:heguangyu5/bpc-webman.git
    ~$ cd bpc-webman/
    ~/bpc-webman$ make
    ...
    output prologue
    generate main.c
    generate build.ninja
    run ninja
    [34/34] link ../start (statically linked)
    mv start ../
    make[1]: Leaving directory '~/bpc-webman/build'
    ~/bpc-webman$ ./start start
    Workerman[./start] start in DEBUG mode
    --------------------------------------------- WORKERMAN ----------------------------------------------
    Workerman version:4.1.10          PHP version:7.2.19-bpc           Event-Loop:\Workerman\Events\Event
    ---------------------------------------------- WORKERS -----------------------------------------------
    proto   user            worker          listen                 processes    status 
    tcp     hgy             webman          http://0.0.0.0:8787    16            [OK]            
    ------------------------------------------------------------------------------------------------------
    Press Ctrl+C to stop. Start success.

4. 关于webman代码调整的说明

webman-framework

  1. src/App.php 不支持依赖注入

    依赖注入需要获取到callback或者controller每个method的参数的详细信息,BPC目前不提供这些信息,所以依赖注入部分的代码都给注释掉了, @see src/App.php#L322

  2. src/Context.php 简化实现

    BPC尚未实现SplObjectStorage, 所以临时使用一个array替代了原来的代码

  3. src/support/App.php Worker::$eventLoopClass 固定为 \Workerman\Events\Event, 不可配置

  4. src/App.php::getController() 要求目录及文件名全部小写.

    编译成二进制后,目录和文件的概念都没有了,所以也就不能scanDir了,根据url找到controller的逻辑必须固定下来,不能scanDir+strtolower来实现.

  5. src/Config.php src/Route.php src/support/App.php 和第4点一样,由于不能scanDir,config文件必须想个办法明确列出来.

webman

  1. support/helpers.php 定义了一个常量 BASE_PATH_REAL 用于当需要读写硬盘文件时用

  2. config/view.php 编译时为了区分静态资源文件(css/js/html/图片等)和view文件, 将view_suffix 配置为 phtml

  3. vendor/autoload.php BPC不需要composer,所以需要一个手写的 autoloader.php

5. 下一步: 如何编译我自己的项目?

参看 webman Makefile 里的编译命令:

bpc -v
  --static
  -c bpc.conf
  -u psr-log
  -u psr-container
  -u fastroute
  -u monolog
  -u workerman
  -u webman
  -d display_errors=on
  --input-file src.list

将你项目的外部依赖像 psr-log/container, fastroute, monolog 等一样,编译成 .so/.a, 然后通过参数 -u YOUR_LIB link进来, 然后把项目自身的静态资源和php文件加到src.list里编译就好了.

6. 关于BPC不支持的语法特性和扩展怎么解决?

等待BPC升级新版本.

翻阅过之前文章的网友应该知道,BPC并不是我们公司的主营业务,它最初是为了解决云招OurATS招聘管理系统本地部署而生的一个 side project ,目前OurATS自身的需求已经完善解决,所以BPC目前处在稳定期,更新和维护要看OurATS的需求来进行,请大家期望不要太高.

确实有需求的网友可以在公司层面和我们进行深度合作,我们乐意提供相应的技术支持.

语法特性涉及到BPC编译器的核心部分,因此实现起来一般不会很快,所以能用phptobpc解决的,可以用phptobpc解决.

php扩展开发较为容易,简单的几天可以开发一个,复杂的需要几周时间,比如开发 event(core) 扩展用了3天,开发 mysqli 扩展用了2周.

目前BPC有3个大的特性尚未实现,提前知悉以免白忙一场:

  1. trait

    简单的trait就相当于copy paste, monolog-2.x里有用到几个trait,就是通过代码替换完成编译的.

  2. class typed properties

    BPC 支持 function/method type hints,但不支持 return type (可通过phptobpc去掉).

  3. Generator / Fiber

7. 如何保障编译后的程序运行没问题?

PHPUnit.

我们维护着一个BPC可编译的phpunit版本: bpc-phpunit.phar-4.8.36.

使用php运行phpunit tests没问题,然后再用bpc编译运行这些tests还没问题,那就是没问题.

nikic-fast-route-1.3.0monolog-2.x-branch 的 phpunit tests 就是使用 bpc-phpunit.phar-4.8.36 跑过的,所以可以确保没问题.

另外,我们也有一本收费的电子书 《PHPUnit in Action — The Easy Way》 介绍了云招OurATS 10多年来的测试心得,有需要的可以看看.

8. 关于软件授权

这里说的软件授权不是BPC编译器自身的license,而是你自己项目的授权.

比如你自己的项目中可能会有如下授权检测代码:

if (/* 没有通过授权检测 */) {
 die('请购买授权后再使用');
}

BPC的解决方案是在生成的scheme代码中随机插入授权检测代码,数量可由一个参数控制,通过插入足够多的授权检测(比如10万个)来增加破解时间,简单粗暴.

请参看文档 06_Licensing

9. BPC Playground

bpc.dev 上可以在线试用BPC编译器, 已内置了一些示例项目代码, 欢迎大家试玩儿~

BPC Playground

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 4
CodingHePing

顶!

6个月前 评论

NB 会出社区版吗?

6个月前 评论
heguangyu5 (楼主) 6个月前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!