记一次PHPStorm Xdebug Docker PHP 调试问题

记一次PHPStorm Xdebug Docker PHP 调试问题

背景

在这之前一直在用 Virtual Box 上的 Ubuntu v16.04.4 虚拟机在做测试环境,随着项目增加,12G硬盘大小的虚拟机会经常报磁盘已满,不断的删日志才能维持工作。于是我就想着再开一台虚拟机,硬盘设置个20G,(还是这么小气)。用的 ubuntu1 v16.04.10,(为啥不上ubuntu18,这个虚拟机软件太老装新系统,发现有性能问题,估计有指令不兼容问题)

我的是Mac环境,(之前也用过Windows)Virtual Box(后简称vbox),装好Ubuntu后,配置NAT网络,就开始装Docker软件,安装步骤是严格按照官网的步骤来的。
https://docs.docker.com/v17.09/engine/installation/linux/docker-ce/ubuntu/#install-using-the-repository

好吧,我承认我的环境有点非主流。这是有历史原因的。

开始造

安装好vbox、ocker,配置好Docker mirror,就开始用docker-compose 拉起测试环境。

Docker Remote API

开始在PHPStorm配置第二台Docker。这里遇到了很多次connection refused。我参考这为老哥的方法一,配置怎么都不生效。换第二个方案就好了。这是第一个坑。

将ubuntu那的 docker Daemon API 端口映射到Vbox nat网络上,我就不细讲了

得到Connection Successful的结果后。开始进行下一步。

PHPStorm php 运行环境

开始配置 PHP :: CLI Interpreter.

选择远程 Docker, Server 选择我们刚刚配置好的 server,在选择我们要调试的 php容器,(这个容器是在 php:7.1.21-cli-jessie 基础上构建的)。

然后就遇到这个问题:

 failed to parse validation script output

phpstorm_helper

当时出问题,没截图,这是网上找了个报错信息一样的图

通过搜索发现需要一个phpstorm_helper docker镜像。

于是在另外一台Ubuntu虚拟机上 docker save, 再到现在Ubuntu 上 docker import 搞定。

再点击刷新还是 failed to parse validation script output
然后,就又是在百度,谷歌,必应~~~
~~~

PHPStorm<->Docker 抓包

还是无果,去洗了下脸,想起网上有人用抓包定位这个问题。我这本地的PHPStorem和vbox里面的Docker Daemon通信就是用的tcp啊。

打开Wireshark,抓包。

通过抓包发现,PHPStorem 与 Docker 之间的请求就是:1.获取当前所有镜像,2.基于你选择的PHP镜像,来创建一个容器。3.运行容器,4.获取容器输出,5.删除容器。根据那一行红色的报错信息,我估计是在运行容器时,输出的内容不是phpstorm预期的,导致报错。由于最后一个操作是删除容器,我就不好调查这个创建的容器到底咋回事了。

于是就抓包,并模拟请求,在删除命令前止住。这样来调查这个创建的容器。

创建容器请求

转换为curl命令:

$ curl -X POST --header "Content-Type:application/json" http://127.0.0.1:52376/v1.24/containers/create -d '{"AttachStdin":true,"OpenStdin":true,"Env":["JETBRAINS_REMOTE_RUN=1"],"Cmd":["-dxdebug.remote_enable=0","/opt/.phpstorm_helpers/phpinfo.php"],"Entrypoint":["php"],"Image":"sha256:292111a5a867f13da8759d3388908b376cf455ecaece86785ea97e9b46f5255f","Volumes":{},"ExposedPorts":{},"HostConfig":{"Binds":["/Users/paulxu/Jumei/compose/portia/php/phpspider:/opt/project:rw"],"Links":[],"LogConfig":{"Type":null,"Config":null},"VolumesFrom":["abeb0f2ead37c672b838726ff9bef51bb1011235c8712dc687f7b7135610cbb2:rw"]}}'

这里的image的id是,作为PHP脚本运行的镜像的ID。

接触容器

对应curl命令:

$ curl -X POST --header "Content-Type:application/json" http://127.0.0.1:52376/v1.24/containers/f434099c2157c1a0cabea5131d9c2a5b8d809cc1e1289abcffb95eb7cf7fc4d0/attach?stdin=true&stdout=true&stderr=true&stream=true

这里的容器ID是上一个创建容器请求的返回值。

开始运行容器

curl 命令:

$ curl -X POST --header "Content-Type:application/json" http://127.0.0.1:52376/v1.24/containers/f434099c2157c1a0cabea5131d9c2a5b8d809cc1e1289abcffb95eb7cf7fc4d0/start

获取输出内容

转换为Curl命令:
curl -X POST –header “Content-Type:application/json” http://127.0.0.1:52376/v1.24/containers/f434099c2157c1a0cabea5131d9c2a5b8d809cc1e1289abcffb95eb7cf7fc4d0/wait

  • 我去看了下老环境的输出如下:

通过docker ps -a,找到通过api创建的容器

检查容器的日志

如下是新环境容器的报错信息:

Could not open input file: /opt/.phpstorm_helpers/phpinfo.php

我在打包的时候,记得是没有往镜像里打包这个文件的。通过查阅刚刚抓包的API参数,发现他有把一个容器作为磁盘挂载在这个新容器上。

来通过docker inspect [container ID] 检查两个容器有何不同。

如下是有问题的镜像

如下是正常的容器。

通过对比,我估计PHP容器所挂载的磁盘容器有问题。

检查容器磁盘

接下来我又细致检查了两个作为磁盘的容器。

如下是有问题的容器。

如下是正常的容器。

这两个作为磁盘的容器都是基于 phpstorm_helpers:PS-181.5281.35镜像构建的。都是基于同一个容器构建的会有什么问题呢?

接下来我检查了下 IMAGE ID,不一样。怎么会不一样呢。我查了下我的命令命令历史记录, docker savedocker import

结案

哦,这, saveloadexportimport。 我命令搞混了。在新环境删除了错误的镜像。重新让PHPStorm检查下就好了。

附上成功图:

PHP拓展 mysql、mysqli、pdo_mysql 区别与选择

今天是2020年,PHP连接MySQL有什么接口呢?还在用mysql函数?试试mysqli、pdo_mysql吧?那mysqli和pdo_mysql又有什么异同呢?来看看

PHP_mysql

PHP-MySQL 是 PHP 操作 MySQL 资料库最原始的 Extension

为了让自己强大起来,mysql 自己为安全也做了很多努力。以前例的 SQL 叙述来说,在sql 语句中使用 变量 直接拼接 的地方容易被 SQL Injection。后来于是发展出了 mysql_escape_string() (备注:5.3.0之后弃用) 以及
mysql_real_escape_string()解决此问题。

php_mysqli

PHP-MySQLi 的 i 代表 Improvement ,提更了相对进阶的功能,就 Extension 而言,本身也增加了安全性.

MySQL增强扩展,可以用于使用 MySQL4.1.3或更新版本中新的高级特性。其特点为:面向对象接口 、prepared语句支持、多语句执行支持、事务支持 、增强的调试能力、嵌入式服务支持 、预处理方式完全解决了sql注入的问题。不过其也有缺点, 就是只支持mysql数据库。如果你要是不操作其他的数据库,这无疑是最好的选择。

PDO_mysql

其功能类似于JDBC、ODBC、DBI之类接口。

PDO是PHP5.1之后才支持的,他为访问数据库采用了一致性的接口,有非常多的操作却是MySQL扩展库所不具备的:

1). PDO真正的以底层实现的统一接口数库操作接口
2). PDO支持更高级的DB特性操作,如:存储过程的调度等,mysql原生库是不支持的.
3). PDO是php官方的PECL库,兼容性稳定性必然要高于MySQL Extension,可以直接使用 pecl upgrade pdo 命令升级

过渡

那我自己举例,我最早接触的就是php_mysql 拓展,就是一个个的函数,封装一下就面向对象了。后来又听人说mysqli更好,更安全。发现从mysql过渡到mysqli,就是find mysql, repalce mysqli 这么简单。而PDO呢,对外提供的是完全的面向对象的API,而我们mysqli 同时对外暴露了 函数式和 面向对象 API。所以,你用mysqli面向对象那种方式,再切换到PDO 也很容易。

用PDO的好处是,PDO支持多种数据库,而MySQLi只支持MySQL,一但你掌握了就你可以使用连接多种数据库。

bind

php_mysql不能 Bind Column ,以前例的 SQL 叙述来说,$location 的地方容易被 SQL Injection。后来于是发展出了 mysql_escape_string() (备注:5.3.0之后弃用) 以及 mysql_real_escape_string()来解决这个问题,不过这麽一搞,整个叙述会变得複杂且丑陋,而且如果栏位多了,可以想见会是怎样的 情形.

在 PHP-MySQLi 中有了不少进步,除了透过 Bind Column 来解决上述问题,而且也多援 Transaction, Multi Query ,

并且同时提供了 Object oriented style (下面这段 PHP-MySQLi 范例的写法) 和 Procedural style

直观对比

特性、指标 PHP的mysqli扩展 PDO (使用PDO MySQL驱动和MySQL Native驱动) PHP的mysql扩展
引入的PHP版本 5.0 5.0 3.0之前
PHP5.x是否包含
MySQL开发状态 活跃 在PHP5.3中活跃 仅维护
在MySQL新项目中的建议使用程度 建议 建议 不建议
API的字符集支持
服务端prepare语句的支持情况
客户端prepare语句的支持情况
存储过程支持情况
多语句执行支持情况 大多数
是否支持所有MySQL4.1以上功能 大多数
参数命名 不支持 支持 不支持
API 编程范式 OOP + 函数式 OOP 函数式
对象映射(Object Mapping) 不支持 支持 不支持

结语

其实从php_mysql, mysqli,pdo_mysql 得过渡就可以看到php自己的设计哲学,不要以很强硬的方式推倒以前的,要慢慢过渡,设计规则让用户慢慢适应。php_mysql->mysqli->pod_mysql, 从过程编码到过程和OOP兼得的mysqli,再到纯OOP的pdo_mysql. 慢慢得大家都用pdo了,mysql也淡出了php的版本。

PHP Opcache 使用

Opcache 是PHP上简单好用,立马见效的优化神器,鸟哥都推荐,那我也要用啊。

Opcache 介绍

Opcache 呢。它的目标是提供一个自由、 开放,和健全的框架用于缓存和优化PHP的中间代码。

OPcache 通过将 PHP 脚本预编译的字节码存储到共享内存中来提升 PHP 的性能, 存储预编译字节码的好处就是 省去了每次加载和解析 PHP 脚本的开销。

PHP 5.5.0 及后续版本中已经绑定了 OPcache 扩展。 对于 PHP 5.25.35.4 版本可以使用 » PECL 扩展中的 OPcache 库。

— 摘自 PHP.net

注意,它和 Alternative PHP Cache (APC) 是一个开放自由的PHP opcode 缓存,是两个东西,别搞混了。

安装

PHP 5.5.0 及后续版本

OPcache 只能编译为共享扩展。 如果你使用 --disable-all 参数 禁用了默认扩展的构建, 那么必须使用 --enable-opcache 选项来开启 OPcache。

编译之后,就可以使用 zend_extension 指令来将 OPcache 扩展加载到 PHP 中。

PHP 5.4 以及更低版本

pecl 下载安装

运行时配置

/php/php.ini

[opcache]
; dll地址
zend_extension=php_opcache.dll

; 启用该拓展打开
opcache.enable=1

; 在cli模式页开启opcache加速 
opcache.enable_cli=1

; 可用内存, 酌情而定, 单位为:Mb
opcache.memory_consumption=128

; Zend Optimizer + 暂存池中字符串的占内存总量.(单位:MB)
opcache.interned_strings_buffer=8

; 对多缓存文件限制, 命中率不到 100% 的话, 可以试着提高这个值
opcache.max_accelerated_files=4000

; 启用,那么 OPcache 会每隔 opcache.revalidate_freq 设定的秒数 检查脚本是否更新。如果禁用此选项,你必须使用 opcache_reset() 或者 opcache_invalidate() 函数来手动重置 OPcache,也可以 通过重启 Web 服务器来清空
opcache.validate_timestamps=0

; Opcache 会在一定时间内去检查文件的修改时间, 这里设置检查的时间周期, 默认为 2, 设置为 0 会导致针对每个请求, OPcache 都会检查脚本更新。单位:秒。 
opcache.revalidate_freq=60

; 打开快速关闭, 打开这个在PHP Request Shutdown的时候回收内存的速度会提高
opcache.fast_shutdown=1

; opcache 不保存注释,减少opcode大小
opcache.save_comments=0


; 启用或禁用在共享内存中的 opcode 缓存。
opcache.file_cache_only=0

;设置不缓存的黑名单
; opcache.blacklist_filename=/png/php/opcache_blacklist

; 配置二级缓存目录并启用二级缓存。 默认值为空字符串 "",表示禁用基于文件的缓存。
opcache.file_cache=/var/www/html/php_cache/
; opcache.file_cache=/var/www/php/cache

更多配置见: php.net

配置好之后,我们运行phpinfo试试看。

如果能看到这界面,说明这个拓展装好了,

注意看到标红,这个说明命中次数,为啥7次呢,因为这个页面我刷行了7次。

使用

opcache_compile_file

该函数可以用于在不用运行某个 PHP 脚本的情况下,编译该 PHP 脚本并将其添加到字节码缓存中去。 该函数可用于在 Web 服务器重启之后初始化缓存,以供后续请求调用。

<?php
/**
* @params string $file 被编译的 PHP 脚本的路径。
* @return boolean 便已成功否
*/
function opcache_compile_file ( string $file ) : boolean

注意事项,Opcache 倾向于编译面向对象编程的代码。并且是在不运行脚本的情况下去编译,也就是它不会判断该脚本在运行时,哪些代码肯定会被执行,哪些不会被执行。也不会判断你的代码执行顺序。它会假设你的代码都会被执行,所以,一些函数的重复定义,会报错。

opcache_invalidate

该函数的作用是使得指定脚本的字节码缓存失效。 如果 force 没有设置或者传入的是 FALSE,那么只有当脚本的修改时间 比对应字节码的时间更新,脚本的缓存才会失效。

<?php
/**
 * @param string $script    缓存需要被作废对应的脚本路径
 * @param bool   $force     
如果该参数设置为TRUE,那么不管是否必要,该脚本的缓存都将被废除。
 * @return bool 成功否,如果脚本的字节码缓存失效设置成功或者该脚本本来就没有缓存,则返回 TRUE;如果字节码缓存被禁用,则返回FALSE。
 */
function opcache_invalidate ( string $script [, boolean $force = FALSE ] ) : boolean

opcache_is_script_cached

此函数检查PHP脚本是否已缓存在OPCache中。这可用于更轻松地检测特定脚本的缓存“变化”。

<?php
/**
 * @param string $file  需要被检查的脚本路径
 * @return bool 如果被Opcache缓存就返回true
 */
function opcache_is_script_cached ( string $file ) : bool

opcache_reset

该函数将重置整个字节码缓存。 在调用 opcache_reset() 之后,所有的脚本将会重新载入并且在下次被点击的时候重新解析。

<?php
/**
 * @return bool 如果字节码缓存被重置成功,则返回 TRUE;如果字节码缓存被禁用,则返回 FALSE。
 */
function opcache_reset ( void ) : boolean

使用说明: 该函数不能和 opcache_compile_file 函数在同一个脚本生命周期调用。 reset 需要用脚本单独调用。

实战

<?php
// file: opcach_init.php
define('DS', DIRECTORY_SEPARATOR);
$basePath = $argv[1];
if (empty($basePath)) {
    $basePath = __DIR__ . DS . '..' . DS . 'php_project';
}
//opcache_reset();  // 不能先reset,再刷缓存,需要在另外一个脚本运行。
//sleep(2);
opcache_compile_files($basePath);
function opcache_compile_files($dir) {
    foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)) as $v) {
        if(!$v->isDir() && preg_match('%\.php$%', $v->getRealPath())) {
            opcache_invalidate($v->getRealPath(), true);
            opcache_compile_file($v->getRealPath());
            echo $v->getRealPath()."\n";
        }
    }
}

PHP cli 模式下运行该命令,就会为该目录,以及子目录下php文件生成Opcache 缓存。

$ php ./opcach_init.php ./../php_project/

cachetool

官方网站github

兼容性

  • CacheTool 5.x works with PHP >=7.2
  • CacheTool 4.x works with PHP >=7.1
  • CacheTool 3.x works with PHP >=5.5.9
  • CacheTool 2.x works with PHP >=5.5.9
  • CacheTool 1.x works with PHP >=5.3.3

下载

  1. githup 下载 cachetool.phar:
  1. 从 composer 下载
$ composer require gordalina/cachetool

$ composer require gordalina/cachetool:~1.0

使用


$ php cachetool.phar --help $ php cachetool.phar apcu:cache:info --fcgi $ php cachetool.phar apcu:cache:info --fcgi=127.0.0.1:9000 $ php cachetool.phar opcache:status --fcgi=/var/run/php5-fpm.sock $ php cachetool.phar opcache:status --cli $ php cachetool.phar opcache:status --web --web-path=/path/to/your/document/root --web-url=http://url-to-your-document.root

Laravel 加速

Laravel 一时爽,上线火葬场。赶紧优化一下,不然Laravel做的项目就只剩下优雅的代码了。

好慢

是的,在Laravel开发模式下,有时候会有种在开发JSP应用的感觉一样,改一下重启一下Tomcat的那种速度。

发布到线上,访问的人一多CPU就100%了。

这篇文章就是来改进这个的,让你的Laravel应用加速。

官方推荐

以下Laravel自己优化自己的一些操作。

## 类映射加载优化 ,额,这个命令在Laravel5.6 被移除了
$ php artisan optimize
$ php artisan clear-compiled ## 清理上面的缓存

## 把配置信息 缓存一下
$ php artisan config:cache
$ php artisan config:clear  ## 清理缓存

## 把路由缓存一下
$ php artisan route:cache
$ php artisan route:clear ## 清理缓存

如果你在开发Laravel 过程中,配置没改,路由没改,那么可以把配置,和路由缓存加速一下。

composer 优化

接下来就是路由加速

来自

生成 classmap

执行命令

$ composer dump-autoload --optimize
$ composer dump-autoload -o  ## 或者是简写

这个命令的本质是将 PSR-4/PSR-0 的规则转化为了 classmap 的规则, 因为 classmap 中包含了所有类名与类文件路径的对应关系,所以加载器不再需要到文件系统中查找文件了。可以从 classmap 中直接找到类文件的路径。

权威的(Authoritative)classmap

$ composer dump-autoload --classmap-authoritative
$ composer dump-autoload -a 

执行这个命令隐含的也执行了 Level-1 的命令, 即同样也是生成了 classmap,区别在于当加载器在 classmap 中找不到目标类时,不会再去文件系统中查找(即隐含的认为 classmap 中就是所有合法的类,不会有其他的类了,除非法调用)

注意事项
如果你的项目在运行时会生成类,使用这个优化策略会找不到这些新生成的类。

使用 APCu cache

$ composer dump-autoload --apcu

使用这个策略需要安装 apcu 扩展。
apcu 可以理解为一块内存,并且可以在多进程中共享。
这种策略是为了在 Level-1 中 classmap 中找不到目标类时,将在文件系统中找到的结果存储到共享内存中, 当下次再查找时就可以从内存中直接返回,不用再去文件系统中再次查找。

在生产环境下,这个策略一般也会与 Level-1 一起使用, 执行composer dump-autoload -o –apcu, 这样,即使生产环境下生成了新的类,只需要文件系统中查找一次即可被缓存 , 弥补了Level-2/A 的缺陷。

Opcache 加速

PHP 5.5 都默认打包了该扩展。在配置中启用即可。

下面是一个简单的默认配置:

/etc/php/7.3/fpm/conf.d/10-opcache.ini

; configuration for php opcache module
; priority=10
zend_extension=opcache.so

opcache.enable=1

opcache.memory_consumption=128

opcache.interned_strings_buffer=8

opcache.max_accelerated_files=4000

opcache.revalidate_freq=60

WordPress 加速

自建的Wordpress打开那么慢,想查个资料等半天,那我为啥不去百度呢?停停停,那我还自建什么站,找个写作平台入住就完事了呗。回来,我们还是优化一下自己的博客站点吧。

转圈圈

一访问自建的Wordpress博客,就是——爱的魔力转圈圈。那么如何优化加速自己的博客网站呢。

静态资源 缓存

通过 nginx 配置, 把WordPress里面的jscsspng, jpeg, gif, woff等资源,开启浏览器缓存。

文件路径: /etc/nginx/sites-enabled/wp.www.conf

server {

        location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)
        {
            expires      1d;
        }

        location ~ .*\.(js|css)
        {
            expires      1d;
        }
}

CDN加速

还可以把这些静态资源放到CDN上,这样加载js,css,png…这些资源就不用和我们html一起挤那根小水管了。

启用Opcache

为Wordpress运行的环境开启Opcache,在php-fpm 中配置, cli 中配置,只影响 php 明亮行程序。

文件路径: /etc/php/7.3/fpm/conf.d/10-opcache.ini

; configuration for php opcache module
; priority=10
zend_extension=opcache.so

opcache.enable=1

opcache.memory_consumption=128

opcache.interned_strings_buffer=8

opcache.max_accelerated_files=4000

opcache.revalidate_freq=60

一些插件

使用WordPress插件加速。这些插件放链接了,自己了解。

WP Fastest Cache 插件

wp fastest cache

WP Optimize 插件

WP Optimize