FreePBX 13 does not work on php 7.0.1

前几天安装 Magento 2,竟然说要 php 5.5 以上版本。本不追新的我,想到反正要用到 remi repo,那就装个最新的 php 7.0.1。结果 Magento 2 倒是能运行,但 FreePBX 13 的 web UI 出不来了,显示成空白页。我估计是 FreePBX 所用的 php 语法不够规范,简单排查了一下,根本没看出是哪里的毛病。我估计对 php 7.0.1 来说,FreePBX 到处是毛病。虽然此时 asterisk 仍正常运行,但我不能让 web UI 长期瘫痪啊,赶紧找了个时间拆了 php 7.0.1,换上了 php 5.6。这是目前兼容性最好的版本,FreePBX 和 Magento 2 均能运行,证明对 php 环境不能过于追新。

Change FreePBX default MySQL connection

我可能吹毛求疵了:我感觉如果要修改 FreePBX 里默认的 MySQL 的连接位置好麻烦。

我修改成 MySQL socket 方式连接,而且也修改了 socket file 的位置,然后要修改 FreePBX 好多个文件才能让 FreePBX 对接 MySQL。大部分文件属于 FreePBX 配置文件,还好办,象填表格一样填就是。但 /var/www/html/admin/modules/userman/DB_Helper.class.php 根本没为 MySQL socket 连接方式考虑,DSN 只兼容 host 连接,所以要大改 262 行(以FreePBX 2.11.0.39为例)。

要改成多行:


if (preg_match('/^unix\((.+)\)$/', $amp_conf['AMPDBHOST'], $matches) === 1) {
	$ampdbsocket = $matches[1];
	$dsn = "mysql:unix_socket=".$ampdbsocket.";dbname=".$amp_conf['AMPDBNAME'];
}
else {
	$dsn = "mysql:host=".$amp_conf['AMPDBHOST'].";dbname=".$amp_conf['AMPDBNAME'];
}

直接修改程序是我最不愿意的。FreePBX 似乎也没提供安全升级的办法,所以 User Management 模块一升级,上述修改就作废,FreePBX web portal 就出错。

Magento not rebuilding image cache

I changed a server for Magento sites. When I migrated the sites, they looked fine. However after I flushed Magento image cache, all sites stopped working. Web pages were not completed. The code stopped rendering after the first product image’s “src”. But there was no error message afterwards.

At first I thought it was file permission problem. But it was not.

Then I thought it was some rubbish left over after flushing cache. So I took the advice by removing the folder media/catalog/product/cache and clearing everything under var. But the problem was still there.

Then I realised it was php not generating images for Magento. Magento requires php-gd to generate images. My new server did not have php-gd installed. If I was installing a Magento instance, I would not get through. But I migrated the sites. So they “looked” fine.

After installed php-gd, product images came back.

By the way, Magento requires some other PHP extensions to run. I took the chance to install them all.
pdo_mysql
simplexml
mcrypt
hash
gd
dom
iconv
curl
soap

Ngnix 502 bad gateway error after a recent php-fpm update

I recently updated php-fpm from 5.4.16 to 5.5.16. After the update, Nginx comes up with 502 bad gateway error. Googling the error pointed me to look into permission of php socket file.

In php-fpm 5.4.16, if no value is given to listen.mode, php socket file is assumed to 0666.

But in php-fpm 5.5.16, if no value is given to listen.mode, php socket file is assumed to 0660.

That is why Nginx no longer has permission to php socket and occurs 502 error.

Hands on GeoIP for Nginx on Fedora and CentOS

最近研究了一下如何根据用户的 IP 获得他的地理位置(我只关心 country 级,不关心 city 级),区别性地在 Ngnix 层面做一些限制性访问。这里用到 GeoIP 软件包和 MaxMind 的数据库。

在 Fedora 20 下,Nginx (目前 1.4.7) 依赖于 GeoIP。等于说,装好 Nginx,ngx_http_geoip_module 自然就启用了,只要在两个配置文件略作修改。

Fedora nginx -V output
Fedora nginx -V output

1. 在/etc/nginx/nginx.conf 里添加


http {

...

geoip_country /usr/share/GeoIP/GeoIP.dat;

...

}

2. 在 /etc/nginx/fastcgi_params 里添加


fastcgi_param GEOIP_COUNTRY_CODE $geoip_country_code;
 fastcgi_param GEOIP_COUNTRY_NAME $geoip_country_name;

还有其他参数可用,请自行查手册。重启 Nginx 就可以使用 GeoIP 的信息了。

在 CentOS 6.5 下,事情要复杂一些。网上说 CentOS 下的 Nginx 同样依赖于 GeoIP,可在我这里事实并非如此。同样是最新的 1.4.7 版,Nginx for CentOS 是不带 ngx_http_geoip_module 编译的。即使我用 yum install GeoIP 安装了 GeoIP 软件包,但 Nginx 不从源码编译就不能启用 geoip 模块。

CentOS nginx -V output
CentOS nginx -V output

着重提一下,我说的 CentOS 6.5 是 VPS 版,Nginx 和 GeoIP 无依赖是不是这个版本特有的?不得而知。我不想为之专门装一次 CentOS 来探究。我也不想从源码编译 Nginx,因为我太喜欢 yum,就为一个 ngx_http_geoip_module 搞砸了其他功能就不值得了。

退而求其次,CentOS 下不妨用 php 调用 GeoIP,只是感觉同样功能用 php 实现会消耗更多资源。另外,Nginx 能进行全面的限制,而 php 无法利用 GeoIP 信息限制对静态文件的访问。但是,Nginx 的全面限制也只能阻止低级用户,不可能阻止稍有点 IT 知识、一心要绕开地理位置限制来访问的用户,所以 php 对动态文件的限制其实也起到了相同的效果。

CentOS 下,安装 GeoIP for php,首先要装有 GeoIP,前面已经说了,要单独装:


yum install GeoIP

然后,安装  php-pecl-geoip:


yum install php-pecl-geoip

哈哈,都是我喜欢的yum。然后重启一下 php-fpm,即可在 php 下获得 geoip 信息。函数有很多,geoip_country_code_by_name()、geoip_country_name_by_name() 等等,请自行查手册。

顺便提一下,CentOS 6.5 VPS 版安装 GeoIP 后,带来的 country 数据库(GeoIP.dat, 6 Sep, 2011)有 1,183,408 字节,而 Fedora 20 的 GeoIP country(GeoLiteCountry.dat, 18 Jun, 2013) 数据库只有 581,110 字节,从 MaxMind 网站上下载最新的 GeoLite Country 数据库(GeoIP.dat, 每月第一个周二更新)也只有668,134 字节。考虑到 MaxMind 的数据库是分免费和收费的,那么,CentOS GeoIP.dat 这么大,是不是更接近于收费版?我不知道收费版是啥样的,因此无从考证。

Change PHP directives in Magento

Today a Magento store owner asked me why he could not create a new attribute set based on an existing one. I took a look into his store and found out the existing attribute set has many custom attributes, which led to new attribute set creation would take more than 30 seconds. But 30 seconds is the default PHP max execution time, which is set in php.ini and has not been optimised for Magento backend operation.

My immediate reaction was changing the default value of max_execution_time to 120. I added a line in /etc/php-fpm.d/www.conf, where is my preferential place to set server wide PHP directives rather than /etc/php.ini.


php_admin_value[max_execution_time] = 120

After a while, I had another thought. I do not like to extend PHP max execution time for most of other websites on the same server. Even for the Magento store, longer execution time is only needed for the backend operations. So how can I specify different PHP directives for different websites? Particularly, how can I specify longer execution time or larger memory limit for Magento admin users?

My first idea was creating separate php-fpm (Yes, I am using php-fpm.) profiles for this purpose. However, I rejected this idea after 2 seconds, because:

  1. I do not like to create more PHP daemons into the valuable server memory.
  2. If Magento frontend and backend are on the same domain, I have no way to assign a corresponding daemon.

So, can I implement changing run-time PHP directives using a Magento module? Of course. I had a Magento module called Msdk (Magento SDK). I just need to add this feature to Msdk.

Firstly, I need to find a proper event to catch. The event should be dispatched only once per request, and earliest possible when it can distinguish frontend or adminhtml route. The earliest event is “controller_front_init_before” except some database events, which are not recommend to catch anyway. But “controller_front_init_before” can not distinguish frontend or adminhtml route, i.e. it can only be put into global section in config.xml. Following the event timeline, I find “frontend or adminhtml route” is the best event to catch.

Secondly, I put one “controller_front_init_before” event catching into frontend section and another into adminhtml section in config.xml of Msdk module.

Thirdly, write two observers in a Helper or a Model to apply PHP directives.

Lastly, modify system.xml to allow users to set PHP directives in Magento System Configuration.

It sounds complicated but actually not. I finished it in a couple of hours.

BTW, Msdk is one of my free modules. But I am not going to launch it now with only one new feature. Watch the space for updated news.

PEAR Mail.php

我想在服务器上用 Gmail SMTP 代替 sendmail 发送邮件,并不想用 Zend_Mail,只想找一个轻量级的解决方案。

一找就找到 Pear Mail。提示说只要用


pear install Mail

然后在程序里


include_once "Mail.php";

我照着做了,可是提示:

Warning: include_once(Net/SMTP.php): failed to open stream: No such file or directory in mail/Mail/smtp.php on line 348
PHP Warning: include_once(): Failed opening ‘Net/SMTP.php’ for inclusion (include_path=’.:/usr/lib/php’) in mail/Mail/smtp.php on line 348
PHP Fatal error: Class ‘Net_SMTP’ not found inmail/Mail/smtp.php on line 349

原来还需要安装一个依赖包


pear install Net_SMTP

Remove php-eaccelerator before updating php 5.3 to 5.4

今天用 yum update 升级基于 CentOS 的服务器碰到一系列的 errors。

Yum update errors
Yum update errors

我用了 –skip-broken 这个开关,不能解决问题。

因为 errors 太多,我实在没兴致仔细看,曾经想重装 OS 得了。但终究有一条 error 引起我的注意:

Error: Package: 1:php-eaccelerator-0.9.6.1-17.el6.remi.x86_64 (@remi)
Requires: php-common(x86-64) = 5.3.16

我尝试着卸载了 php-eaccelerator:


yum remove php-eaccelerator

然后再升级:


yum update

竟然错误没有了。升级成功!

那就再把 php-eaccelerator 装回去吧。


yum install php-eaccelerator

装不上。可能是 remi 的 php 和 epel 的 php-eaccelerator 不兼容吧。

php is_numeric

某些 php 函数的返回值毫无规律可循。比如

is_numeric("123")

返回 true;

is_numeric(" 123")

(前导空格)返回 true;而

is_numeric("123 ")

(后导空格)返回 false。

php 有灵活的语法,但每遇这种情况,我总是羡慕其他语言的严谨。

Machine convert xls to csv

Linux is an excellent OS. Today something again proved my choice.

I was looking for a solution to convert Excel xls to csv format. This conversion is required by a Magento dataflow project.

Magento native dataflow comes with an XML Excel parser. For some reasons, it does not convert my xls files. I think it may be due to limited functionality of Magento XML Excel parser class, or encoding problem.

I need something which can reliably convert xls files from 3rd parties, which we have no control over how they produce xls files.

I was thinking of another php independent class called ExcelReader. However, ExcelReader goes beyond what I need. All I need is convert xls to csv, make ready for dataflow.

After a day’s research, finally xls2csv caught my attention. I would have found it earlier if I had searched by “linux command line convert xls to csv” earlier. It runs perfectly well on Fedora and CentOS as I tested.

Installation is straight forward. Run


yum install catdoc

FYI, yum install xls2csv, installs something totally different. I have not figured out what it is.