使用Tideways监控php代码

最近研究了php性能调控相关工具,推荐一个tideways,还有一个xhgui界面化分析工具,帮助我们监控代码的运行。

关于怎么搭建,这里有一篇文章讲的很详细。

一些文章的补充:

1.  如果tideways安装失败,可以用以下方法安装:

wget https://github.com/tideways/php-xhprof-extension/archive/v4.1.5.tar.gz -O php-xhprof-extension-4.1.5.tar.gz
tar xzf php-xhprof-extension-4.1.5.tar.gz 
cd php-xhprof-extension-4.1.5 
phpize  
./configure --with-php-config=/php-config-path
make && make install 

2. 文章中给的是nginx 的配置,关于apache,php-value的写法如下(包含在httpd-vhost.conf或者.htaccess中):

<IfModule php7_module>
    php-value auto_prepend_file "/xhgui/path/to/external/header.php"
</IfModule>

3. install.php里会安装composer, 如果你已经安装了composer,可以手动执行 composer install 代替,如果失败,可以尝试执行 composer update

搭建好之后运行的效果如下:

Apache – RewriteRule指令

平常开发里,重载应该不会少,今天又仔细看了一遍apache文档,关于RewriteRule这一节,下面是我的总结。

首先RewriteRule的语法是这样的:

RewriteRule Pattern Substitution [flags]

1. Pattern会匹配到什么?

在服务器级别(<VirtualHost>)的配置中,会匹配整个url,包括最前面的/,所以写rule时,应该^/
而在目录级别(<Directory>或.htaccess)的配置中, 会除去url里当前目录的前缀,并且不会匹配前面的/.

比如/documentroot/html/下有.htaccess

RewriteRule ^test.php test2.php
访问
GET /html/test.php
会匹配到test.php
GET /html/a/test.php
会匹配到a/test.php

但是要注意的是,此时基准目录是html,也就是说上面的匹配不会重载到html/a/test2.php,目标还是目录html下的test.php,如果想重载到目录a下的test.php,那么使用

RewriteBase /html/a

还有一点是, pattern匹配只会匹配到REQUEST_URI为止,换句话说QUERY_STRING是不会被匹配到的,如果想要用QUERY_STRING做判断使用

RewriteCond %{QUERY_STRING}

2. Substitution会有什么值?

常见的可能是filesystem_path或url_path( 即相对于DOCUMENT_ROOT ),比如/www/a.hml, 那mod_rewrite是怎么判断是前者还是后者,因为从表面看两种情况都有可能,规则是这样,如果/www目录( 即根目录下www文件夹 )存在,该参数会被当做文件目录,否则则会被当做url_path,或者/www不存在但是有Alias指令存在,那么可以使用 [PT] 标志让他强制当做目录,例如 (服务器级别配置下)

Alias /abc /xyz (xyz为真实目录)
RewriteRule ^/def/test.php /abc/test.php [PT]

关于query_string,一般来说query_string会原封不动的传入,例如(服务器级别配置下)

RewriteRule ^/arg/([0-9]+)/?$ test.php
访问
GET /arg/1?name=1 
相当于
GET /test.php?name=1

如果想修改query_string,那么只需要在Substitution后面跟上?  例如:

RewriteRule ^arg/([0-9]+)/?$ test.php?foo=bar
那么情况就变了,访问
GET /arg/1?name=1 
相当于
GET /test.php?foo=bar

如果想合并新的和旧的query_string,那么加上标志 [QSA] 即可

RewriteRule ^arg/([0-9]+)/?$ test.php?foo=bar [QSA]

RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^a/([0-9]+)/?$ test.php?a=1&%1

RewriteRule ^a/([0-9]+)/?$ test.php?a=1&%{QUERY_STRING}
总结有限,如有错误,请指正。

Let’s Encrypt ,给你的网站上https!

前几天给我们网站的所有域名都换了https证书,用的是Let‘s Encrypt。

Let‘s Encrypt是一个免费的https证书提供平台,包括chrome,firefox在内的主流浏览器都支持。重点是免费,不过有效期是90天,到期得重新更新证书。

EEF有一个certbot工具可以自动化的在你的网站部署https证书,我试了一下,对centos的支持好像不太友好,于是google一下,搜到了的一篇博客,写得很好。利用的另外一种方式部署。

首先创建一个目录:

mkdir ~/ssl && cd ~/ssl

然后我们需要一个账户和网站的私钥。

openssl genrsa 4096 > account.key  //账户私钥,用来识别身份
openssl genrsa 4096 > domain.key   // 域名私钥

接下来要创建CSR(Certificate Signing Request,证书签名请求)文件

openssl req -new -sha256 -key domain.key -out domain.csr

这里,因为需要交互,填的信息比较多,包括国家,公司,域名等等,输错了就得重来。所以我做了一个expect脚本,用来自动化填写信息。脚本如下,供参考

auto_crs.sh
#!/usr/bin/expect

set timeout 10
spawn openssl req -new -sha256 -key domain.key -out domain.csr
expect {
 "*Country Name*" {send "zh\r"}
}
expect {
 "*Province Name*" {send "Beijing\r"}
}
expect {
 "*Locality Name*" {send "Chaoyang\r"}
}
expect {
 "*Organization Name*" {send "xxx\r"}
}
expect {
 "*Organizational Unit Name*" {send "xxx\r"}
}
expect {
 "*Common Name*" {send "www.xxx.com\r"}
}
expect {
 "*Email Address*" {send "xxx@xxx.com\r"}
}
expect {
 "*challenge password*" {send "xxx\r"}
}
expect {
 "*An optional company name*" {send "xxx\r"}
}

interact

chmod +x auto_crs.sh

然后当前目录下会生成一个domain.csr文件,然后我们就可以生成证书了。

CA 在签发 DV(Domain Validation)证书时,需要验证域名所有权。传统 CA 的验证方式一般是往 admin@yoursite.com 发验证邮件,而 Let’s Encrypt 是在你的服务器上生成一个随机验证文件,再通过创建 CSR 时指定的域名访问,如果可以访问则表明你对这个域名有控制权。

所以,我们需要设置一下服务器,比如我们要验证对www.example.com的控制权。以apache为例,设置httpd.conf或者vhost文件:

先创建一个目录用来存放验证文件,

mkdir ~/challenge

然后更改配置

<IfModule alias_module>
     Alias /.well-known/acme-challenge/ /home/xxx/challenge/
</IfModule>

证书服务器会先在challenge目录创建一个随机文件,然后访问www.example.com/.well-known/challenge/随机文件,如果访问正常,则可以验证你对网站的控制权。

然后,我们用acme-tiny这个工具生成证书, 下载脚本:

wget https://raw.githubusercontent.com/diafygi/acme-tiny/master/acme_tiny.py

指定账户私钥、CSR 以及验证目录,执行脚本:

python acme_tiny.py --account-key ./account.key --csr ./domain.csr --acme-dir ~/challenges/ > ./signed.crt

如果一起ok,那么会生成一个crt文件,这就是我们要的证书。

搞定网站证书后,还要下载 Let’s Encrypt 的中间证书:

wget -O - https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem > intermediate.pem
cat signed.crt intermediate.pem > chained.pem

最后修改,打开ssl module,修改httpd-ssl.conf文件(先Include),增加证书相关配置,然后重启apache即可。

对于多域名设置,没有深究,我写了一个脚本来设置多域名,如下,供参考:

#!/bin/bash

cd ~/ssl/
domain=$1
dir=`ls -al|grep ${domain} > /dev/null;echo $?`
if [ ${dir} -eq "0" ];then
echo "Domain exists"
exit
fi

cp -R ssl-www.example.com/ ssl-${domain}/ && cd ssl-${domain}/
sed -i 's/www.example.com/'${domain}'/g' auto.csr.sh
./auto_csr.sh
./renew_cert.sh

关于公私钥位数,我用的是4096位,想了一下,除了在ssl握手时会使用一次非对称,传输一次公钥,后面都是使用随机字串对称加密,所以并不会影响性能或者可以忽略不计,使用4096位更加安全。

另外,部署后可以在Qualys上test一下。

参考:

https://imququ.com/post/letsencrypt-certificate.html

https://letsencrypt.org/

www.certbot.com

用php创建一个守护进程

参考文章

示例代码

想到之前看到linux下,nohup和&一起使用可以创建一个后台job,例如:

nohup ping www.google.com & 1>/dev/null 2&>1

意思是让ping命令不接受hangup信号,也就脱离了终端的控制。该命令会在后台变成一个job:

[1]  33765

[1]表示job号码,33765代表进程id。使用jobs可以列出所有的jobs,也可以使用ps -ef|grep查看

bg %num命令可以将一个job后台执行

fg %num命令可以将一个命令前台执行  // num代表job号码

ctrl + z可以将一个job挂起暂停

kill %num 或 kill pid可以终止某个job

Apache – RewriteBase指令的错误理解

之前错误的认为RewriteBase只会影响RewriteRule指令在匹配url时,是完全匹配还是不包含域名匹配。这种理解不正确,看个例子:

假如我们的服务器目录下有/a/b/目录,对于这个目录,我们使用了Alias指令

Alias /a /root/b
// 即我们访问www.server-name.com/a/index.html会返回/root/b/index.html

这时, 如果我们访问www.server-name.com/a/old.html,且在/root/b下有.htaccess文件,内容如下:

RewriteEngien On

RewriteBase /a

RewriteRule ^old\.html$ new.html

会发生什么?

分析一下:

  1. 因为Alias指令的存在,所以:/a/old.html  =>  /root/b/old.html
  2. 因为 b目录下有.htaccess文件,所以:/root/b/old.html  =>  /root/b/new.html
  3. 这里就体现RewriteBase的功能了,因为设置成/a,所以:/root/b/new.html  =>  /a/new.html。
  4. 最后,因为Alias指令,/a/new.html  =>  /root/b/new.html

关于第三点,回到刚开始我错误的理解,就是RewriteRule在匹配url时,是怎么匹配的?我的理解是以.htaccess文件所在目录为基准的,举个例子:假如.htaccess文件在/a/b/c目录下,那么当我们访问www.sn.com/a/b/c/d/old.html,那么是从/d开始匹配的,即匹配/b/old.html。

所以RewriteBase是目录级重写的基准,即当我们用RewriteRule不是重定向或者代理时,如何寻找新的目录或文件。