V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
heguangyu5
V2EX  ›  PHP

PHP 编译器 BPC 6.4 发布,支持 nullable typehint,成功编译 webman, PHP 项目二进制打包, 源码保护/代码加密, 软件授权 All in One!

  •  
  •   heguangyu5 · 203 天前 · 908 次点击
    这是一个创建于 203 天前的主题,其中的信息可能已经有所发展或是发生改变。

    不了解 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 查看效果

      • http://localhost:8787/sayhi.txt
      • http://localhost:8787/test
      • http://localhost:8787/user/101
      • http://localhost:8787/
      • http://localhost:8787/index/view
      • http://localhost:8787/index/json
      • http://localhost:8787/404-not-found

    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 [email protected]: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

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

    BPC Playground

    4 条回复    2023-10-11 20:43:41 +08:00
    akjarjash
        1
    akjarjash  
       203 天前
    很希望 PHP 可以开发桌面软件但是不用搭建 PHP 运行环境,加油^_^
    JingKeWu
        2
    JingKeWu  
       201 天前
    点个赞 下一步能 laravel 就好了
    loginv2
        3
    loginv2  
       200 天前
    @akjarjash 这种需求一般需要去研究系统的 API ,门槛儿也是系统的 API ,无论换什么语言都一样,除非像 Qt 那样做个大而全的封装。考虑到 PHP 这方面的积累,感觉是个超级巨大的工程,还不如随大流用 js 做
    akjarjash
        4
    akjarjash  
       198 天前
    @loginv2 哈哈 也是
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2666 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 10:39 · PVG 18:39 · LAX 03:39 · JFK 06:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.