Vim+XDebug调试PHP

感谢老黑鸟哥发布的《PHP调试指南》(via)。要不是他们,我可能还在用echo/var_dump调试PHP代码。是他们解救了我,引导我走向光明,感激涕零中……本文是对指南中的《Vim + Xdebug + DBGp》一章的一些补充。

原理上,这种调试方式主要依靠Vim的插件“remote PHP debugger”来实现,该插件实现了一个DBGP服务端。调试的时候Xdebug将会与服务端建立一个连接进行通信,接收服务端的调试指令并返回调试结果。 Read the rest of this entry »

Windows系统上MySQLdb for Python 2.6

Windows平台 上,MySQLdb官方编译的二进制包貌似最高只支持Python 2.5,按照论坛里的帖子下载了一个非官方编译的版本,但是有两个问题:

  1. 要另外下载两个动态连接库文件:libguide40.dll和libmmd.dll;
  2. 会有一个警告信息:
    >>> import MySQLdb
    C:\Python26\lib\site-packages\MySQLdb\__init__.py:34: DeprecationWarning: the sets module is deprecated
      from sets import ImmutableSet

发现个不错的版本,不会有上面的问题:http://www.thescotties.com/mysql-python/test/

[PHP]Base32编码/解码

一时兴起研究起BASE32,其实编码解码都还算简单,按照RFC 4648

编码:

  1. 将输入字符串的每个字符转成ASCII码;
  2. 以5个bit为一组进行二进制分割,最后一个字符如果不足5位的话就补零;
  3. 补高位转回十进制作为码表索引,参照码表就得到最终编码的字串;
         +--first octet--+-second octet--+--third octet--+
         |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|
         +-----------+---+-------+-------+---+-----------+
         |5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0|
         +--1.index--+--2.index--+--3.index--+--4.index--+

解码:

  1. 参见码表,将输入字符串取得码表索引(8位);
  2. 将索引去掉前面3位,转成5位;
  3. 组合5位,再按8位一组进行分割,就取得了字符的ASCII码;
                        1          2          3
          01234567 89012345 67890123 45678901 23456789
         +--------+--------+--------+--------+--------+
         |< 1 >< 2| >< 3 ><|.4 >< 5.|>< 6 ><.|7 >< 8 >|
         +--------+--------+--------+--------+--------+
                                                 <===> 8th character
                                           <====> 7th character
                                      <===> 6th character
                                <====> 5th character
                          <====> 4th character
                     <===> 3rd character
               <====> 2nd character
          <===> 1st character

Read the rest of this entry »

批量文件编码转换

脚本文件 convert.sh:

#!/bin/sh
convert() {
    echo -ne "convert $1 ...\n"
    file -i $1 | awk -F = '$2 != "utf-8" && $2 != "unknown" {\
        print "iconv -f gb2312 -t utf-8 -o '$1'.tmp '$1'"\
    }' | sh
    [ -f ""$1.tmp"" ] && mv "$1.tmp" $1
}

run() {
    for file in `find $1 -type f -name "*.php" | grep -v bbs`
    do
        convert $file
    done
}

run $1

./convert.sh uchome/

Python通过正则表达式选取callback

最近在瞎想怎么通过xpath去精确抓取文章的正文,跟parselets类似的想法,只不过更简单。

代码设计上采用正则表达式匹配URL,再选择callback handler的方式,主要参考web.py的分发器(Dispatcher)。

#!/bin/env python

import re, sys

# Define parser first.
def baidu(username):
    # Business logic
    return "Using parser Baidu. and the user's name is: %s." % username

def qzone(uin):
    # Business logic
    return "Using parser Qzone, and the user's QQ is: %s." % uin

# From web.py
def group(seq, size):#{{{
    """
    Returns an iterator over a series of lists of length size from iterable.

        >>> list(group([1,2,3,4], 2))
        [[1, 2], [3, 4]]
        >>> list(group([1,2,3,4,5], 2))
        [[1, 2], [3, 4], [5]]
    """
    def take(seq, n):
        for i in xrange(n):
            yield seq.next()

    if not hasattr(seq, 'next'):
        seq = iter(seq)
    while True:
        x = list(take(seq, size))
        if x:
            yield x
        else:
            break
#}}}

def parser_init(url,mapping):
    for pat, what in group(mapping,2):
        result = re.compile('^' + pat + '$').match(url)
        if result:
            return what, [x for x in result.groups()]
    return None, None

if __name__ == '__main__':
    mapping = (
            'http://(?:hi|space).baidu.com/([^/]+)(?:/.*)?','baidu',
            'http://(\d+).qzone.qq.com(?:/.*)?','qzone',
            )

    (func, args) = parser_init(sys.argv[1],mapping)
    if func:
        callback = func

        if func in globals():
            callback = globals()[func]

        if callable(callback):
            print callback(*args)
    else:
        print 'No parser found.';

当然,这个实现比较老土一些,全部用function的方式回调,没有用类,可以参考web.py去做适当的修改。

选好图,会对意

关于沟通,一幅好图总是能胜过千言万语:

(From: http://extremepresentation.typepad.com/blog/2006/09/choosing_a_good.html)

相关的一本书:《用图表说话

使用trash代替rm

在/usr/bin/目录创建一个trash文件:

#! /bin/sh

DATE=`date +%Y%m%d`
TRASH="$HOME/.trash"

# Make sure the dest directionry is exists.
if [ ! -d $TRASH ]; then
    mkdir $TRASH
    if [ ! -z $SUDO_USER ]; then
        chown $SUDO_USER $TRASH
        chgrp $SUDO_GID $TRASH
    fi
fi

if [ ! -d $TRASH/$DATE ]; then
    mkdir $TRASH/$DATE
    if [ ! -z $SUDO_USER ]; then
        chown $SUDO_USER $TRASH/$DATE
        chgrp $SUDO_GID $TRASH/$DATE
    fi
fi

while [ $# -gt 0 ]
do
    if [ `expr substr $1 1 1` = "-" ]; then
        if [ $1 = "--" ]; then
            shift
            break
        fi
        shift
    else
        break
    fi
done
if [ $# -gt 0 ]; then
    mv $* $TRASH/$DATE
fi

之后,只要把”alias rm=trash”放进bashrc就可以了。

iptables应用实例

本机端口转发

将本机80端口的请求转发到8080端口:

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080

Read the rest of this entry »

关于Unix静态库和动态库的分析

基本概念

库有动态与静态两种,动态通常用.so为后缀,静态用.a为后缀。 例如:libhello.so libhello.a

为了在同一系统中使用不同版本的库,可以在库文件名后加上版本号为后缀,例如: libhello.so.1.0,由于程序连接默认以.so为文件后缀名。所以为了使用这些库,通常使用建立符号连接的方式。

ln -s libhello.so.1.0 libhello.so.1
ln -s libhello.so.1 libhello.so

Read the rest of this entry »

tar: Removing leading `/’ from member names

首先应该明确:*nix系统中,使用tar对文件打包时,一般不建议使用绝对路径。

通常是在两台环境相似的机器上进行同步复制的时候,才有需要使用绝对路径进行打包。使用绝对路径打包时如果不指定相应的参数,tar会产生一句警告信息:”tar: Removing leading `/’ from member names”,并且实际产生的压缩包会将绝对路径转化为相对路径。 Read the rest of this entry »