php7.1新特性

Allow specifying keys in list()
Square bracket syntax for array destructuring assignment

下面这个支持效果,还是不错的

list($a, $b) = array($b, $a);
[$a, $b] = [$b, $a];

foreach ($points as ["x" => $x, "y" => $y]) {
    var_dump($x, $y);
}

这个在遍历的时候会很方便,也很强大
感觉这两个特性会使数组使用便捷一些

Nullable Types
这个就是一个简写的标量或null,用处有,但感觉不大

Generalize support of negative string offsets
这个特性好,可以简化一些简单的字符串处理

Support Class Constant Visibility
暂时想不到太大用处,只是将类常量完善了

Void Return Type
这个限制函数返回值有用
同时希望miexd,number什么的也尽快出来

Catching Multiple Exception Types
多cacth异常感觉没什么用,可能还是不太会用异常吧

深入剖析PHP输入流 php://input与POST/GET的区别

PHP输入流php://input
在使用xml-rpc的时候,server端获取client数据,主要是通过php输入流input,而不是$_POST数组。所以,这里主要探讨php输入流php://input
对于php://input介绍,PHP官方手册文档有一段话对它进行了很明确地概述:

“php://input allows you to read raw POST data. It is a less memory intensive alternative to $HTTP_RAW_POST_DATA and does not need any special php.ini directives. php://input is not available with enctype=”multipart/form-data”.

继续阅读深入剖析PHP输入流 php://input与POST/GET的区别

若非去空格,请慎用trim

trim — 去除字符串首尾处的空白字符(或者其他字符)
用法:
string trim ( string $str [, string $charlist = ” \t\n\r\0\x0B” ] )

trim函数大家应该不会陌生,从4.1.0 新增可选的 charlist 参数。默认的用法就不多说了,说说在使用到第二个参数的情况:

$path = trim(dirname(__FILE__), ‘/’).’/’; // 保证$path只有一个/结束

这种用法也是没有问题的。那什么情况下会出问题?再举个例子:

$domain = trim(‘www.example.com.tw’, ‘www.’); // 大家期望的结果是example.com.tw,可实际的结果却是example.com.t,tw中的w没了。

问题出现在第二个参数$charlist,它代表的是一个字符列表,而不是一个单纯的字符串,所以tw的w属于www.这个列表中的一员,被一起去掉了。具体可以再参考trim

替代方法:

$domain = preg_replace(‘/^www\.|www\.$/’, ”, ‘www.example.com.tw’);

Call to undefined function imagettftext()解决方法

在一个新环境中装Tipask v2.5的时候发现后台验证码无法显示。出错的函数是imagettftext(),由于index.php使用了error_reporting(0)将错误隐去,导致这次莫名的错误,去掉,错误立马出现:

Fatal error: Call to undefined function imagettftext()

现在我们就明确了,出现错误的原因是PHP编译时没有加上FreeType。
继续阅读Call to undefined function imagettftext()解决方法

一个快速获取/更新 Let’s encrypt 证书的脚本

调用 acme_tiny.py 认证、获取、更新证书,不需要额外的依赖。

下载到本地

# wget https://raw.githubusercontent.com/xdtianyu/scripts/master/lets-encrypt/letsencrypt.conf
# wget https://raw.githubusercontent.com/xdtianyu/scripts/master/lets-encrypt/letsencrypt.sh
wget https://raw.githubusercontent.com/carpliyz/Lets-encrypt/master/letsencrypt.conf
wget https://raw.githubusercontent.com/carpliyz/Lets-encrypt/master/letsencrypt.sh
chmod +x letsencrypt.sh

配置文件

只需要修改 DOMAIN_KEY DOMAIN_DIR DOMAINS 为你自己的信息

ACCOUNT_KEY=”letsencrypt-account.key”
DOMAIN_KEY=”example.com.key”
DOMAIN_DIR=”/var/www/example.com”
DOMAINS=”DNS:example.com,DNS:whatever.example.com”

执行过程中会自动生成需要的 key 文件。

运行

./letsencrypt.sh letsencrypt.conf

注意

需要已经绑定域名到 /var/www/example.com 目录,即通过 http://example.com http://whatever.example.com 可以访问到 /var/www/example.com 目录,用于域名的验证

看到以下信息表示生成/更新成功

Generate CSR…
Parsing account key…
Parsing CSR…
Registering account…
Already registered!
Verifying www.hdj.me…
www.hdj.me verified!
Signing certificate…
Certificate signed!
New cert: www.chained.crt has been generated

生成证书包括

-rw-r–r– 1 root root 3.2K Dec 28 17:04 letsencrypt-account.key
-rw-r–r– 1 root root 192 Dec 28 17:03 letsencrypt.conf
-rwxr-xr-x 1 root root 1.7K Dec 28 16:57 letsencrypt.sh
-rw-r–r– 1 root root 1.7K Dec 24 00:58 lets-encrypt-x1-cross-signed.pem
-rw-r–r– 1 root root 3.4K Dec 29 08:38 www.chained.crt
-rw-r–r– 1 root root 1.8K Dec 29 08:38 www.crt
-rw-r–r– 1 root root 920 Dec 29 08:37 www.csr
-rw-r–r– 1 root root 1.7K Dec 28 17:04 example.com.key

nginx配置

listen 443 ssl;
ssl_certificate /path/letsencrypt/www.chained.crt;
ssl_certificate_key /path/letsencrypt/example.com.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

cron 定时任务

每个月自动更新一次证书,可以在脚本最后加入 service nginx reload等重新加载服务。

0 0 1 * * /etc/nginx/certs/letsencrypt.sh /etc/nginx/certs/letsencrypt.conf >> /var/log/lets-encrypt.log 2>&1

Let’s Encrypt 试用

Let's Encrypt

听说Let’s Encrypt已经开始Public Beta了,于是马上开始试用。Let’s Encrypt 是一个新的数字证书认证机构,它通过自动化的过程消除创建和安装证书的复杂性,为网站提供免费的 SSL/TLS 证书。

以下是使用 Let’s Encrypt 的过程:

获取客户端并执行

-- 注意python版本要求>=2.7
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
./letsencrypt-auto --agree-dev-preview --server https://acme-v01.api.letsencrypt.org/directory auth

一、选择认证方式

在安装一些依赖包后,Let’s Encrypt 将弹出 TUI 界面要求选择认证的方式:手动或独立。这里为了省事,选择独立认证。

二、接着输入 Email 地址

三、同意许可协议

四、输入域名

在此,输入 hdj.me 和 www.hdj.me,多个域名使用逗号或空格分隔。

也可以选择命令行模式:

./letsencrypt-auto certonly -a manual --debug -d www.hdj.me

五、完成

当看到下列消息时,说明认证已经成功完成:

– Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/linuxtoy.org/fullchain.pem. Your cert will
expire on 2016-01-25. To obtain a new version of the certificate in
the future, simply run Let’s Encrypt again.

Let’s Encrypt 将认证的信息保存于 /etc/letsencrypt 目录。

然后,在 NGINX 的配置文件中将下面两行设置成 Let’s Encrypt 的实际路径即可:

ssl_certificate /etc/letsencrypt/live/www.hdj.me/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.hdj.me/privkey.pem;

上一张预览图:
QQ截图20151216182945

值得注意的是:
目前 Let’s Encrypt 的证书有效期为 90 天,之后需要手动续期。另外,在请求证书认证时会有频率限制。总的来说,证书的认证过程还是非常容易的,而且又是免费,所以对此有需要的朋友不妨一试。

记一次关于in_array的问题

先介绍一下需求背景:

发票方式:
0=捐赠(不要问我为什么,历史原因)
1=对中寄送
2=索取
3=电子发票

现在要对用户提交的数据进行检测:

if(!in_array($_POST['invoice_action'], array(0,1,2,3))){
    throw new Exception('请选择正确的发票方式');
}

这个时候出现一个问题,如果压根就不存在$_POST[‘invoice_action’]这个值,为什么没有抛出异常?
经确认,这就是PHP作为弱类型语言的一个坑!!!没错,这是一个坑!!!
看一下这组代码:

echo in_array('', array(0)) ? 1 : 0;     // 结果:1
echo in_array(null, array(0)) ? 1 : 0;   // 结果:1
echo in_array(false, array(0)) ? 1 : 0;  // 结果:1

这么大一个坑,我们要怎么绕过或者填起呢?
方法一:in_array支持第三个参数,强制对数据类型检测

echo in_array('', array(0), true) ? 1 : 0;     // 结果:0
echo in_array(null, array(0), true) ? 1 : 0;   // 结果:0
echo in_array(false, array(0), true) ? 1 : 0;  // 结果:0

方法二:依然是数据类型方向,把数组中的0改为字符串

echo in_array('', array('0'), true) ? 1 : 0;     // 结果:0
echo in_array(null, array('0'), true) ? 1 : 0;   // 结果:0
echo in_array(false, array('0'), true) ? 1 : 0;  // 结果:0

php的慢速日志引起的Mysql2013错误

Description:
————
If mysql query is longer as request_slowlog_timeout, connection breaks.

Test script:

<?php
// request_slowlog_timeout = 10s  (at /etc/php5/fpm/php-fpm.conf)

// $mysqli =
// ...
$query = "SELECT SLEEP (15)";

$res = $mysqli->query($query);
if (!$res) {
	echo $mysqli->error; // Error Code: 2013. Lost connection to MySQL server during query
	exit;
}

Expected result:
—————-
connection must be preserved and the request should be executed

https://bugs.php.net/bug.php?id=67087&edit=3

又一道PHP优先级的坑爹题

先看看题目

echo '1'.print(2)+3;

正确的结果应该是

511

对于这个答案,我只说“!@##¥%¥%……”,没办法答案确实没错。
那么我们来分析一下为什么会是这个答案,如标题所言这是一道坑爹的的优先级的PHP题目,那就按优先级的思路的分析(反推)。
1、先执行print

print(2)+3;//等同于print(2+3),这时缓冲区输出5。别问我为什么,手册里说的

2、print是一个函数,有返回结果,int类型

print(5);//结果等于1,这时候echo '1'.1,这个时候缓冲区又输出了11

3、最终的结果(按输出顺序):511

坑爹呀!