Install extension for macOS built-in PHP

macOS High Sierra 10.13.3 ships with PHP 7.1.7. I’m trying to install an extension for the built-in PHP. I tried the pecl command but no lucky because SIP (System Integrity Protection) protection. I can’t add file under the directory /usr/lib/php that default php extension directory.

It’s a little difficult but I installed an extension success by compiling manually

Prepare

  • Install packages
brew install autoconf pcre
  • Download PHP source files for built-in PHP
xcode-select --install
  • Edit the /etc/php.ini, change the extension_dir to /usr/local/lib/php/extensions. The directory is writable. You should make the directory yourself.
  • Copy all extension files from /usr/lib/php/extensions to /usr/local/lib/php/extensions
  • Download the extension file and compile it
  • Edit /usr/bin/php-config, find line
extension_dir='/usr/local/lib/php/extensions/no-debug-non-zts-20090626'

and replace it with

extension_dir='/usr/local/lib/php/extensions'

Compile extension

For example, I compile swoole extension with these steps.

  • Download swoole-2.1.1.tgz from pecl.php.net
  • Unzip the file and compile the extension
tar xzvf swoole-2.1.1.tgz
cd swoole-2.1.1
phpize
./configure
make
make install

在macOS下用homebrew安装php 7.1以及pecl

用homebrew默认安装的php 7.1没有包含pecl命令。但是重新安装可以解决这个问题,如果出现libpng不兼容问题,可以加上-s参数

brew remove php71
brew install php71 --with-pear

MediaWiki的维护脚本

MediaWiki的 maintenance 目录下存放着维护脚本,记录一下。

createAndPromote.php

用于创建或者修改已经存在的用户。参数如下

php createAndPromote.php [--bureaucrat] [--sysop] [--bot] [--custom-groups=<group1>,<group2>] [--force] username [password]

示例

php createAndPromote.php --bureaucrat --sysop --custom-groups=developer WikiSysop mypassword

配置windows上的git commit时的默认编辑器

在Win下使用github的Git Shell,每次commit时都会弹出记事本,使用不是太爽,想换成vim才顺手。操作步骤如下

  • 安装gvim
  • 将gvim的目录加入Path环境变量中,在 我的电脑 – 属性 - 高级 - 环境变量中修改
  • 配置git
git config --global core.editor gvim
  • 重启Git Shell即可生效!

php的libev扩展

pecl上新添了一个ev扩展,目前版本是0.2.0,已经stable。这个扩展为php提供了libev库的接口。

ev is a PECL extension providing inteface to libev library – high performance full-featured event loop written in C.

ABOUT LIBEV
Libev is an event loop: you register interest in certain events (such as a file descriptor being readable or a timeout occurring), and it will manage these event sources and provide your program with events.

那么什么是libev呢,从网上摘录一段:

libev 是高性能事件循环/事件模型的网络库,并且包含大量新特性。
它是继lievent和Event perl module之后的一套全新网络库。它追求的目标:速度更快,bug更少,特性更多,体积更小。
它和libevent很像,按照作者的介绍,可以作为libevent的替代者,能够提供更高的性能。并不需要复杂的配置。

看起来和之前提到的libevent大有渊源,但是这个扩展的作者显然比较活跃,一周内提交了3个版本。

代码示例

timer的使用

stop();
    // Stop the watcher if further calls cause more than 10 iterations
    Ev::iteration() >= 10 and $w->stop();
});

// 创建一个已停止的timer,手工start才有效
$w_stopped = EvTimer::createStopped(10, 5, function($w) {
    echo \"Callback of a timer created as stoppedn\";

    // Stop the watcher after 2 iterations
    Ev::iteration() >= 2 and $w->stop();
});

// Loop until Ev::stop() is called or all of watchers stop
Ev::run();

// Start and look if it works
$w_stopped->start();
echo \"Run single iterationn\";
Ev::run(Ev::RUN_ONCE);

echo \"Restart the second watcher and try to handle the same events, but don\'t blockn\";
$w2->again();
Ev::run(Ev::RUN_NOWAIT);

$w = new EvTimer(10, 0, function() {});
echo \"Running a blocking loopn\";
Ev::run();
echo \"ENDn\";
?>

输出内容


2 seconds elapsed
is called every second, is launched after 2 seconds
iteration = 1
is called every second, is launched after 2 seconds
iteration = 2
is called every second, is launched after 2 seconds
iteration = 3
is called every second, is launched after 2 seconds
iteration = 4
is called every second, is launched after 2 seconds
iteration = 5
Run single iteration
Callback of a timer created as stopped
Restart the second watcher and try to handle the same events, but don\'t block
Running a blocking loop
is called every second, is launched after 2 seconds
iteration = 8
is called every second, is launched after 2 seconds
iteration = 9
is called every second, is launched after 2 seconds
iteration = 10
END

I/O事件

例1

例2

stop();
    // Stop write watcher
    $w->stop();

    $in = \"HEAD / HTTP/1.1rn\";
    $in .= \"Host: google.co.ukrn\";
    $in .= \"Connection: Closernrn\";

    if (!socket_write($socket, $in, strlen($in))) {
        trigger_error(\"Failed writing $in to socket\", E_USER_ERROR);
    }

    $read_watcher = new EvIo($socket, Ev::READ, function ($w, $re)
        use ($socket, $e_nonblocking) {
        // Socket is readable. recv() 20 bytes using non-blocking mode
        $ret = socket_recv($socket, $out, 20, MSG_DONTWAIT);

        if ($ret) {
            echo $out;
        } elseif ($ret === 0) {
            // All read
            $w->stop();
            socket_close($socket);
            return;
        }

        // Caught EINPROGRESS, EAGAIN, or EWOULDBLOCK
        if (in_array(socket_last_error(), $e_nonblocking)) {
            return;
        }

        $w->stop();
        socket_close($socket);
    });

    Ev::run();
});

$result = socket_connect($socket, $address, $service_port);

Ev::run();
?>

输出

HTTP/1.1 301 Moved Permanently
Location: http://www.google.co.uk/
Content-Type: text/html; charset=UTF-8
Date: Sun, 23 Dec 2012 16:08:27 GMT
Expires: Tue, 22 Jan 2013 16:08:27 GMT
Cache-Control: public, max-age=2592000
Server: gws
Content-Length: 221
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Connection: close

源码

源码放在bitbucket

mac下快速安装php 5.4

手头的笔记本升级到了OS X 10.8了,但是偶尔还需要写点php调剂一下。看看自带的php版本?

PHP 5.3.13 with Suhosin-Patch (cli) (built: Jun 20 2012 17:05:20)
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2012 Zend Technologies

对于追新族来说,必须得升级到php 5.4才开心。借助homebrew很快完成升级:

安装过程

三行即可。


brew tap homebrew/dupes
brew tap josegonzalez/homebrew-php
brew install php54

这样安装的php路径在/usr/local/bin/php,版本信息:

/usr/local/bin/php -v
PHP 5.4.4 (cli) (built: Jul 27 2012 08:42:32)
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2012 Zend Technologies

php的异步http请求类

基于上次写的关于php的libevent扩展的应用,我实现了一个异步的http请求类。

代码在github上:https://github.com/volca/AsyncHttpClient

使用示例

如下,在request的时候能够定义请求完成之后的callback函数。


 $base
);

for($i = 0; $i < 10; $i++) {
    $client = new AsyncHttpClient($uri, $config);
    $client->request(function($result) {
        echo "Result len:";
        echo strlen($result['response']);
        // parse response with Zend_Http_Response
        $response = Zend_Http_Response::fromString($result['response']);              
        echo $response->getBody();
        echo "\n";
    });
}

event_base_loop($base);
echo "done\n";

目前的实现比较初级,只做了get方法的封装,如果需要http上传或者post,还需要另外实现。另外这个类也需要php的libevent扩展

Update 2011.11.17

将这个类修改为继承自Zend_Http_Client,这样我可以少写一些代码,顺带也实现了文件http上传以及post(未经测试),代码中的使用示例也已经更新。

关于php的libevent扩展的应用

php有个libevent扩展,在一年前我曾经拿它实现了一个thrift socket server,虽然我没有把它放在正式的场合来使用,但是我觉得这个扩展应该可以有更广泛的用途,比如:

  • phpDaemon — 一个异步的服务器端开发框架.
  • tail – 用php实现类似unix下的tail命令行
  • ZeroMQ + libevent in PHP – 用php和ZeroMQ实现的一个事件驱动服务器端

我所想到的一个比较实用的使用场景是,在页面中利用libevent请求多个http接口来获得数据。若是在从前,一个可行的办法是利用curl_multi_exec来同时请求好几个接口,但是这个办法需要用一个do … while循环来完成请求,很是坑爹。那么看看采用libevent的例子:

代码实例 http.php

为了省事,这个php脚本仅仅是重复抓取一个网页5次,并且回调的逻辑我没怎么做处理,仅仅是echo出来而已,可以通过下面命令行来运行这个例子:

php http.php "www.baidu.com"

代码中的http_get($argv[1])这行虽然是靠一个命令行顺序执行,但是不会阻塞后面的代码,直接就进行下一次请求了。而且我们看看回调方法部分是不是很像用javascript调用ajax写的回调方法?这都是php 5.3中闭包的功劳。


event_set($event_fd, $fd, EV_WRITE | EV_PERSIST, function($fd, $events, $arg) {
    //回调方法,后续处理随意
    echo fread($fd, 4096);
    if(feof($fd)) {
        fclose($fd);
	event_base_loopexit($arg[1]);
	echo "done";
    }
}, array($event_fd, $base_fd));

想到更多

在mysqlnd,memcached…这些php扩展中,都已经有delay回调的实现,如果能好好利用,对性能提升岂不是有莫大的帮助?或者在libevent扩展的基础上,实现一个事件驱动的开发框架,也是可行的。

Update 2011.11.10

在这个代码的基础上实现了一个异步http请求的客户端

Update 2011.10.28

event_base_loop是会阻塞后续代码执行的,所以我调整了示例代码,使用同一个event_base,并且用stream_socket_client来进行异步连接,另外在/etc/hosts指定域名的ip会对执行速度有帮助。

php文档更新

php.net最近更新了php文档,比较有用的是新增的pman工具。pman是一个命令行小工具,方便查看php函数的本地帮助文档,但是不包含php.net的评论数据。简单的试用心得如下:

安装pman

使用传说中的pear来安装pman

sudo pear install doc.php.net/pman

如果pear版本比较老,需要先升级pear才可以继续

sudo pear upgrade pear

pman使用方法

pman的使用方法很傻瓜,比如我们想查看strlen的帮助信息:

pman strlen

帮助文本的内容是彩色的,能和chm版本的php帮助文档媲美。pman的详细使用帮助如下

#pman --help
man, version 1.6c

usage: man [-adfhktwW] [section] [-M path] [-P pager] [-S list]
	[-m system] [-p string] name ...

  a : find all matching entries
  c : do not use cat file
  d : print gobs of debugging information
  D : as for -d, but also display the pages
  f : same as whatis(1)
  h : print this help message
  k : same as apropos(1)
  K : search for a string in all pages
  t : use troff to format pages for printing
  w : print location of man page(s) that would be displayed
      (if no name given: print directories that would be searched)
  W : as for -w, but display filenames only

  C file   : use `file' as configuration file
  M path   : set search path for manual pages to `path'
  P pager  : use program `pager' to display pages
  S list   : colon separated section list
  m system : search for alternate system's man pages
  p string : string tells which preprocessors to run
               e - [n]eqn(1)   p - pic(1)    t - tbl(1)
               g - grap(1)     r - refer(1)  v - vgrind(1)

还有一个好处是在vim里查看php帮助信息更方便了,结合完美

:!pman strlen

用git部署php站点

在小站点上,直接用git来部署php代码相当方便,你的远程站点以及本地版本库都有一个版本控制,追踪问题或者回滚是很轻松的事情。下面介绍用git部署时的设置步骤

在远程服务器的设置

假定你需要部署的代码在/var/www/yoursite

cd /var/www/yoursite
git init .
git config receive.denyCurrentBranch ignore
git config --bool receive.denyNonFastForwards false
cd .git/hooks
wget https://gist.githubusercontent.com/volca/9482044/raw/344a590af350b997db3819fa21426dfe8bc140f4/post-update
chmod +x post-update

在本地git库中新增配置


[remote "prod"]
        url = your-ssh-username@your-host:/var/www/yoursite/

这样就算设置完成了。

如果你想把本地的代码推送到远程服务器,下面简单的步骤就可以做到

git pull
git push prod

注意事项

如果远程服务器上git的配置目录.git暴露在外部可访问的位置,请在web服务器上设置这个目录不可见。