蛮荆

PHP 边边角角

2020-02-09

Ubuntu 快速安装 PHP

PHP 7.2

sudo add-apt-repository ppa:ondrej/php && sudo apt-get update

# 稳定版本
sudo apt-get -y install php7.2

# 开发版:
# sudo apt-get -y install php7.2-dev

sudo apt-get install -y php7.2-fpm php7.2-mysql php7.2-curl php7.2-json php7.2-mbstring php7.2-xml php7.2-intl

sudo apt-get install openssl

sudo apt-get install php7.2-gd -y &&
sudo apt-get install php7.2-soap -y &&
sudo apt-get install php7.2-gmp -y &&
sudo apt-get install php7.2-odbc -y &&
sudo apt-get install php7.2-pspell -y &&
sudo apt-get install php7.2-bcmath -y &&
sudo apt-get install php7.2-enchant -y &&
sudo apt-get install php7.2-imap -y &&
sudo apt-get install php7.2-ldap -y &&
sudo apt-get install php7.2-opcache -y &&
sudo apt-get install php7.2-readline -y &&
sudo apt-get install php7.2-sqlite3 -y &&
sudo apt-get install php7.2-xmlrpc -y &&
sudo apt-get install php7.2-bz2 -y &&
sudo apt-get install php7.2-interbase -y &&
sudo apt-get install php7.2-pgsql -y &&
sudo apt-get install php7.2-recode -y &&
sudo apt-get install php7.2-sybase -y &&
sudo apt-get install php7.2-xsl -y &&
sudo apt-get install php7.2-cgi -y &&
sudo apt-get install php7.2-dba -y &&
sudo apt-get install php7.2-phpdbg -y &&
sudo apt-get install php7.2-snmp -y &&
sudo apt-get install php7.2-tidy -y &&
sudo apt-get install php7.2-redis -y && 
sudo apt-get install php7.2-memcache -y &&
sudo apt install php7.2-xdebug -y && 
sudo apt-get install php7.2-zip -y

PHP 7.4

sudo add-apt-repository ppa:ondrej/php && sudo apt-get update

sudo apt-get -y install php7.4

sudo apt-get install -y php7.4-fpm php7.4-mysql php7.4-curl php7.4-json php7.4-mbstring php7.4-xml php7.4-intl

sudo apt-get install openssl

sudo apt-get install php7.4-gd -y &&
sudo apt-get install php7.4-soap -y &&
sudo apt-get install php7.4-gmp -y &&
sudo apt-get install php7.4-odbc -y &&
sudo apt-get install php7.4-pspell -y &&
sudo apt-get install php7.4-bcmath -y &&
sudo apt-get install php7.4-enchant -y &&
sudo apt-get install php7.4-imap -y &&
sudo apt-get install php7.4-ldap -y &&
sudo apt-get install php7.4-opcache -y &&
sudo apt-get install php7.4-readline -y &&
sudo apt-get install php7.4-sqlite3 -y &&
sudo apt-get install php7.4-xmlrpc -y &&
sudo apt-get install php7.4-bz2 -y &&
sudo apt-get install php7.4-interbase -y &&
sudo apt-get install php7.4-pgsql -y &&
sudo apt-get install php7.4-recode -y &&
sudo apt-get install php7.4-sybase -y &&
sudo apt-get install php7.4-xsl -y &&
sudo apt-get install php7.4-cgi -y &&
sudo apt-get install php7.4-dba -y &&
sudo apt-get install php7.4-phpdbg -y &&
sudo apt-get install php7.4-snmp -y &&
sudo apt-get install php7.4-tidy -y &&
sudo apt-get install php7.4-redis -y &&
sudo apt-get install php7.4-memcache -y &&
sudo apt install php7.4-xdebug -y &&
sudo apt-get install php7.4-zip -y

PHP 优点

  1. 完善的面向对象编程支持,主要包括
    • namespace 处理命名冲突
    • interface 分离实现与接口
    • traits 代码混入(mixin)支持
    • 类型系统 限制函数参数、返回值、类成员的类型
  2. 完善的依赖管理体系,这一点主要由 composer 实现
  3. 支持 FFI(foreign function interface),可以很方便的跟各种C语言库(如 TensorFlow)交互,极大地扩展了 PHP 的能力
  4. 更加安全,主要是引入了更加现代更加安全的密码学类库 libsodium
  5. 性能不断提升,PHP7.4 的性能大约是 PHP5.6 的 3 倍,比 PHP7.0 也快了近 18%, 主要的性能提升来自于 PHP7.0 的 zval 重构,而 PHP7.4 也能过引入 preload 特性进一步加快了代码的执行速度,PHP8.0 将引入 JIT 技术,性能会有更大的提升

PHP 不足

  1. 不支持泛型。程序员无法限制PHP的数组的成员类型。
  2. 运行时类型检查。PHP的参数类型检查是在代码执行的过程完成的,降低了执行效率。
  3. 不支持多核。PHP虚拟机就是一个C语言的 while 循环,边读取边执行。如果想跑满多核,只能利用多进程或都多线程,多线程存在同步问题,多进程存在IPC问题。
  4. PHP本身和扩展都使用C语言开发,要想深入理解PHP,单写PHP代码是不够的。这在一定程度上增加了改进PHP的门槛。
  5. 性能相比编译语言依然差很远
  6. 生态

PHP7 比 PHP5 性能提升在哪里

1、变量存储字节减小,减少内存占用,提升变量操作速度 2、改善数组结构,数组元素和 hash 映射表被分配在同一块内存里,降低了内存占用、提升了 cpu 缓存命中率 3、改进了函数的调用机制,通过优化参数传递的环节,减少了一些指令,提高执行效率

生命周期

  1. 模块初始化阶段 (Module init):即调用每个拓展源码中的的 PHP_MINIT_FUNCTION 中的方法初始化模块,进行一些模块所需变量的申请,内存分配等
  2. 请求初始化阶段 (Request init):即接受到客户端的请求后调用每个拓展的 PHP_RINIT_FUNCTION 中的方法,初始化 PHP 脚本的执行环境
  3. 执行该 PHP 脚本
  4. 请求结束 (Request Shutdown):这时候调用每个拓展的 PHP_RSHUTDOWN_FUNCTION 方法清理请求现场,并且 Zend Engine 开始回收变量和内存
  5. 关闭模块 (Module shutdown):Web 服务器退出或者命令行脚本执行完毕退出会调用拓展源码中的 PHP_MSHUTDOWN_FUNCTION 方法

主流框架请求声明周期

  1. 用户向入口脚本 index.php 发起请求
  2. 入口脚本加载应用配置并创建一个应用实例去处理请求
  3. 应用通过请求组件解析请求的路由
  4. 应用创建一个控制器实例去处理请求
  5. 控制器创建一个动作实例并针对操作执行过滤器
  6. 如果任何一个过滤器返回失败,则动作取消
  7. 如果所有过滤器都通过,动作将被执行
  8. 动作会加载一个数据模型,或许是来自数据库
  9. 动作会渲染一个视图,把数据模型提供给它
  10. 渲染结果返回给响应组件
  11. 响应组件发送渲染结果给用户浏览器

php://input 是什么

php://input 是个只读流,用于获取请求体,返回整个 HTTP 请求中,除去 HTTP 头部的全部原始内容,而不管是什么 Content Type(或称为编码方式)。 相比较之下,$_POST 只支持 application/x-www-form-urlencoded 和 multipart/form-data-encoded 两种 Content Type。 其中前一种就是简单的 HTML 表单以 method=“post” 提交时的形式,后一种主要是用于上传文档。因此,对于诸如 application/json 等 Content Type, 这往往是在 AJAX 场景下使用,那么使用 $_POST 得到的是空的内容,这时就必须使用 php://input。

相比较于 $HTTP_RAW_POST_DATA ,php://input 无需额外地在 php.ini 中激活 always-populateraw-post-data ,而且对于内存的压力也比较小, 当编码方式为 multipart/form-data-encoded 时,php://input 是无效的。这种情况一般为上传文档。这 种情况可以使用传统的 $_FILES 或者 Yii 框架中的 yii\web\UploadedFile。

获取请求头

  • getallheaders(),该方法仅在将 PHP 作为 Apache 的一个模块运行时有效
  • http_get_request_headers(), 该方法要求 PHP 启用 HTTP 扩展
  • $SERVER 数组的方法,需要遍历整个数组,并将所有以 HTTP* 元素加入到集合中去。并且要将所有 HTTP_HEADER_NAME 转换成 Header-Name 的形式,根据不同的 PHP 环境采用有效的方法来获取请求头部

502 报错

问题原因分析:502 bade gateway 一般都是 upstream 出错,对于 PHP,造成 502 的原因常见的就是脚本执行超过 timeout 设置时间或者 timeout 设置过大,导致 PHP 进程长时间不能释放。

控制 PHP 脚本执行时间的配置有两种:

  1. php.ini 文件中 max_execution_time (全局配置)
  2. php-fpm.conf 中 request_terminate_timeout

如何解决

  1. 适当增大 php 脚本执行时间,通过修改 php.ini 或 php-fpm.conf 来配置
  2. 从根本原因出发,定位 php 脚本, 查出真正导致 php 执行时间过长的原因 (例如 循环嵌套过多,数据库死锁)
  3. 高并发的话考虑 php-fpm.conf 中的 max_children 最大子进程数
  4. 是否启动 php-fpm

请手动释放你的资源

点击阅读原文

安全配置

  • error_reporting 设置为 Off:不要暴露错误信息给用户,开发的时候可以设置为 ON
  • safe_mode 设置为 Off
  • register_globals 设置为 Off
  • 禁用以下函数:system、exec、passthru、shell_exec、proc_open、popen
  • open_basedir 设置为 /tmp, 这样可以让 session 信息有存储权限,同时设置单独的网站根目录
  • expose_php 设置为 Off
  • allow_url_fopen 设置为 Off
  • allow_url_include 设置为 Off

监听方式

Nginx 中的 fastcgi_pass 为什么有时候是 unix:/tmp/php-fpm.sock,有时候是 127.0.0.1:9000 ?

UNIX Domain Socket 是一种 IPC 机制,它不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,而是直接将应用层数据从一个进程拷贝到另一个进程。

两种方式的区别在于:

  • UNIX Domain Socket 适用于 PHP 和 Nginx 在同一服务器,不经过协议层和网卡,可以避免数据传输经过 TCP 层造成导致 TIME_WAIT 连接过多的问题
  • IP 地址 两种模式都支持 (无论 Nginx 和 PHP 是否位于同一服务器)
# IP 地址方式:
php-fpm.conf: listen = 127.0.0.1:9000;
nginx.conf:   fastcgi_pass 127.0.0.1:9000;

# UNIX Domain Socket 方式:
php-fpm.conf: listen = /tmp/php-fpm.socknginx.conf;
nginx.conf:   fastcgi_pass  unix:/tmp/php-fpm.sock;

长连接方案

虽然能实现,但是无法克服 PHP 的先天性缺陷,导致请求和响应对应容易出问题。

每个语言都有适用的场景,PHP 目前依旧适用的场景就是管理后台 API + 中小系统 + 大型系统中需要快速迭代并验证的模块功能。

Reference

转载申请

本作品采用 知识共享署名 4.0 国际许可协议 进行许可,转载时请注明原文链接,图片在使用时请保留全部内容,商业转载请联系作者获得授权。