May 27, 2011

PHP Manual in VIM

Updated at May 29:
我把產生出來的php manaul tags分享出來 phpdoc-20110526.tar.gz,需要又懶得自已動手的人歡迎下載回去用。

網路上提供的tags都太舊了,所以就自已動手產生吧!我今天在FreeBSD上做了一遍,現在用Mac寫文章,所以這邊就以Mac的環境說一下流程,我不太清楚Mac OS X Server和XCode預設裝了哪些東西,所以我把環境列上來提供參考:

操作環境
Mac OS X Server v10.6.7
XCode 4.0.2
PHP 5.3.4

一、安裝PEAR

Mac OS X Server出廠就有LAMP stack的環境了,但PHP沒編--with-pear,所以要自已裝,基本上是照著pear官網的文件,但我沒有加-d detect_unicode=0。
$ curl http://pear.php.net/go-pear.phar > go-pear.phar
$ sudo php -q go-pear.phar

Below is a suggested file layout for your new PEAR installation.  To
change individual locations, type the number in front of the
directory.  Type 'all' to change all of them or simply press Enter to
accept these locations.

 1. Installation base ($prefix)                   : /usr/local
 2. Temporary directory for processing            : /tmp/pear/install
 3. Temporary directory for downloads             : /tmp/pear/install
 4. Binaries directory                            : /usr/local/bin
 5. PHP code directory ($php_dir)                 : /usr/local/share/pear
 6. Documentation directory                       : /usr/local/docs
 7. Data directory                                : /usr/local/data
 8. User-modifiable configuration files directory : /usr/local/cfg
 9. Public Web Files directory                    : /usr/local/www
10. Tests directory                               : /usr/local/tests
11. Name of configuration file                    : /Users/gasol/.pearrc

1-11, 'all' or Enter to continue:
預設會裝在個人的home目錄,這邊我把prefix改成/usr/local,如果是裝在別的地方,注意一下PATH要找的到pear,最後會詢問是否要在php.ini把pear的路徑加在include_path。
裝完再用pear裝待會兒會用到的PhD和XML_Parser
$ sudo pear install doc.php.net/phd_php
Did not download optional dependencies: phpdocs/PhD_PEAR, phpdocs/PhD_IDE, use --alldeps to download automatically
phpdocs/PhD_PHP can optionally use PHP extension "haru"
phpdocs/PhD can optionally use package "phpdocs/PhD_PEAR"
phpdocs/PhD can optionally use package "phpdocs/PhD_IDE"
phpdocs/PhD can optionally use PHP extension "haru"
phpdocs/PhD_Generic can optionally use PHP extension "haru"
downloading PhD_PHP-1.1.0.tgz ...
Starting to download PhD_PHP-1.1.0.tgz (24,067 bytes)
........done: 24,067 bytes
downloading PhD-1.1.0.tgz ...
Starting to download PhD-1.1.0.tgz (42,303 bytes)
...done: 42,303 bytes
downloading PhD_Generic-1.1.0.tgz ...
Starting to download PhD_Generic-1.1.0.tgz (28,104 bytes)
...done: 28,104 bytes
install ok: channel://doc.php.net/PhD_Generic-1.1.0
install ok: channel://doc.php.net/PhD-1.1.0
install ok: channel://doc.php.net/PhD_PHP-1.1.0

$ sudo pear install XML_Parser
downloading XML_Parser-1.3.4.tgz ...
Starting to download XML_Parser-1.3.4.tgz (16,040 bytes)
......done: 16,040 bytes
install ok: channel://pear.php.net/XML_Parser-1.3.4
詳細安裝方式可以參考 https://wiki.php.net/doc/phd/install

二、從SVN Repository產生PHP Documentation.

svn co http://svn.php.net/repository/phpdoc/modules/doc-en phpdoc
                ... ignore ...
A    phpdoc/en/features/figures/simple-array.png
A    phpdoc/en/features/figures/simple-array2.png
A    phpdoc/en/features/figures/leak-array.png
A    phpdoc/en/features/commandline.xml
A    phpdoc/en/features/sessions.xml
A    phpdoc/en/features/gc.xml
A    phpdoc/en/features/remote-files.xml
A    phpdoc/en/features/cookies.xml
A    phpdoc/en/features/http-auth.xml
A    phpdoc/en/features/xforms.xml
 U   phpdoc/en
Checked out external at revision 311445.

Checked out revision 311445.
會clone一堆xml下來,接著執行./build.sh
$ cd phpdoc
phpdoc/ $ ./build.sh
configure.php: $Id: configure.php 310808 2011-05-06 16:11:39Z bjori $
PHP version: 5.3.4

LibXML 2.7.4+ added a 'feature' to break things, typically namespace related, and unfortunately we must require it.
For a few related details, see: http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg777646.html
Please recompile PHP with a LibXML version 2.7.4 or greater. Version detected: 2.7.3
Or, pass in --disable-libxml-check if doing so feels safe.

Checking for source directory... /Users/gasol/tmp/phpdoc/doc-base
Checking for output filename... /Users/gasol/tmp/phpdoc/doc-base/.manual.xml
Checking whether to include CHM... no
Checking for PHP executable... /usr/bin/php
Checking for language to build... en
Checking whether the language is supported... yes
Checking for partial build... no
Checking whether to enable detailed XML error messages... yes
Checking libxml version... 2.7.3
Checking whether to enable detailed error reporting (may segfault)... yes
Checking whether to optimize out the DTD (performance gain, but segfaults)... yes
Generating /Users/gasol/tmp/phpdoc/doc-base/manual.xml... done
Generating /Users/gasol/tmp/phpdoc/doc-base/install-unix.xml... done
Generating /Users/gasol/tmp/phpdoc/doc-base/install-win.xml... done
Generating /Users/gasol/tmp/phpdoc/doc-base/developer.template.xml... done
Generating /Users/gasol/tmp/phpdoc/doc-base/entities/version.ent... done
Generating /Users/gasol/tmp/phpdoc/doc-base/scripts/file-entities.php... done
Iterating over extension specific version files... OK
Saving it... OK
Creating file /Users/gasol/tmp/phpdoc/doc-base/entities/file-entities.ent... done
Checking for if we should generate a simplified file... no
Checking whether to save an invalid .manual.xml... no
Loading and parsing manual.xml... done.
Validating manual.xml... done.

All good. Saving .manual.xml... done.
All you have to do now is run 'phd -d /Users/gasol/tmp/phpdoc/doc-base/.manual.xml'
If the script hangs here, you can abort with ^C.
 (Run `nice php configure.php` next time!)


PHP will segfault now :) - Don't worry though, the .manual.xml has been saved :D
[23:42:04 - Heads up              ] Creating output directory..
[23:42:04 - Indexing              ] Indexing...
[23:44:02 - Indexing              ] Indexing done
[23:44:02 - Rendering Style       ] Running full build
[23:44:03 - Rendering Format      ] Starting PHP-Chunked-XHTML rendering
[23:46:30 - Rendering Format      ] Writing search indexes..
[23:46:30 - Rendering Format      ] Index written
[23:46:30 - Rendering Format      ] Finished rendering
結束後就可以看到日期是今天最新的PHP Documentation.


三、把HTML轉換成VIM helptags

作者的網頁下載Parser,這隻script年代有點久遠,所以我加了
點料
patch讓它可以順利執行

在phpdoc的上一層目錄執行parser2.php
$ curl http://blog.planetxml.de/uploads/source/php/phpdoc/parser2.php.txt > parser2.php
$ patch -p1 < parser2.diff
patching file parser2.php
Hunk #1 succeeded at 344 with fuzz 1.
$ mkdir out
$ php parser2.php

recursing into phpdoc/en/reference/mcrypt/functions/.svn/tmp/props
recursing into phpdoc/en/reference/mcrypt/functions/.svn/tmp/text-base
recursing into phpdoc/en/reference/mcrypt/functions/.svn/tmp
recursing into phpdoc/en/reference/mcrypt/functions/.svn
processing phpdoc/en/reference/mcrypt/functions/mcrypt-cbc.xml
processing phpdoc/en/reference/mcrypt/functions/mcrypt-cfb.xml
processing phpdoc/en/reference/mcrypt/functions/mcrypt-create-iv.xml
processing phpdoc/en/reference/mcrypt/functions/mcrypt-decrypt.xml
processing phpdoc/en/reference/mcrypt/functions/mcrypt-ecb.xml
processing phpdoc/en/reference/mcrypt/functions/mcrypt-enc-get-algorithms-name.xml
processing phpdoc/en/reference/mcrypt/functions/mcrypt-enc-get-block-size.xml
processing phpdoc/en/reference/mcrypt/functions/mcrypt-enc-get-iv-size.xml
processing phpdoc/en/reference/mcrypt/functions/mcrypt-enc-get-key-size.xml
processing phpdoc/en/reference/mcrypt/functions/mcrypt-enc-get-modes-name.xml
processing phpdoc/en/reference/mcrypt/functions/mcrypt-enc-get-supported-key-sizes.xml
processing phpdoc/en/reference/mcrypt/functions/mcrypt-enc-is-block-algorithm-mode.xml
processing phpdoc/en/reference/mcrypt/functions/mcrypt-enc-is-block-algorithm.xml
processing phpdoc/en/reference/mcrypt/functions/mcrypt-enc-is-block-mode.xml
processing phpdoc/en/reference/mcrypt/functions/mcrypt-enc-self-test.xml
processing phpdoc/en/reference/mcrypt/functions/mcrypt-encrypt.xml
processing phpdoc/en/reference/mcrypt/functions/mcrypt-generic-deinit.xml
processing phpdoc/en/reference/mcrypt/functions/mcrypt-generic-end.xml
processing phpdoc/en/reference/zlib/functions/gzwrite.xml
processing phpdoc/en/reference/zlib/functions/readgzfile.xml
processing phpdoc/en/reference/zlib/functions/zlib-get-coding-type.xml
recursing into phpdoc/en/reference/zlib/functions
recursing into phpdoc/en/reference/zlib
sorting tags
這邊時間要久一點,

四、設定VIM

把上一步在out目錄產生的所有檔案搬到$HOME/.vim/doc,有用pathogen的話要把pathogen#helptags()拿掉,它會自動執行helptags把tags檔覆蓋過去,我個人是用pathogen擺在$HOME/.vim/bundle/phpdoc/doc底下,接著在.vimrc加上一行autocmd BufNewFile,BufRead *.php set keywordprg="help"就大功告成了!

最後,開一個php檔到處在funciton按K測試看看吧,在沒有雙瑩幕的環境,用這方法看manual可以結省不少切換視窗的時間,helptags的應用可以參考李果正 - 大家來學VIM 12.5.2節

May 24, 2011

Using Reflection to get private property value in PHP

說在前頭,此方法破壞了OO封裝的原則,多數的狀況下是不適用的!用這方法前請確定你了解,而且需要它!不然結果會很恐怖的。

PHP 5的Property Visibility提供public, protected, private三個keyword來封裝資料,property一旦宣告了private,就代表它與世隔絕,要存取它可以另外透過getter accessor,然後magic就在此黑盒子裡面發生了!

今天碰到一個狀況,在Thrift的PHP Library裡,我必需存取一個宣告為private但沒有getter的property,@ronnywang告訴了我有PHP Reflection,我就在這裡找到答案了,透過ReflectionProperty的setAccessible就可以輕鬆的達到這個需求。


May 19, 2011

替主機上第二道鎖 - Google Authenticator

今天 @jnlin 跟我提到了Google Authenticator,我才知道原來它是open source的專案,因為我一直有在用它的Android App,Google從去年下半年就開始從Google Apps推2-step authentication,直到Google Accounts全面開放,我一直都有使用,雖然某些狀況下不方便,例如Android、Picasa、Google Talk、AppEngine (deploy)等都需要產生application-specific password才能使用,但在帳號安全的考量下魚與熊掌沒辦法兼顧,某些程度必須要讓步,這就是trade-off!

很久之前我就一直很想在自已的機器上加上第二道認證的機制,如同OTP Token一樣,但是自已用總不能像公司一樣去買個商用的solution吧?這太粗本了!幸運的是今天讓我知道google-authenticator!馬上就跑去hg clone,還為了它裝了mercurial,安裝很容易,只需要補上libpam0g-dev就可以了,但是設定上,還是需要動一些手腳,裝完後先執行google-authenticator,它會在$HOME下產生.google_authenticator的檔案,裡面存了secret key, emergency code和一些設定,這邊特別要注意的是!這是明碼存放的,所以記得檢查一下權限是不是正確的,接著只要想辦法把secret key輸入到手機裡面就好了,用barcode scan或手動輸入都可以。

接下來到補上設定後記得保留login的session,另開terminal來測試成功!不然進不去又沒留後門的話我也不知道該怎麼解決...XD,最後感謝一下open source....


May 6, 2011

Ubuntu 11.04 Gnome Terminal預設的瀏覽器


Gnome Terminal遇到Link時可以在右鍵menu選擇以browser打開,這個動作可以用更快速的方法Ctrl+左鍵來代替,雖然是個小小的功能卻很方便,省去copy & paste的繁索動作,Ubuntu 11.04 (Natty Narwhal) 在4月28日正式推出時的那個週末,就把身邊的機器都升級完成,從此惡夢就來了!這個Open Link的動作預設都給我開Firefox,即使我在裝好Chrome第一次開啟時已經選擇讓它成為我的預設瀏覽器,Gnome Terminal還是給我開Firefox,佔住我那寶貴的memory空間!這一切在Natty之前都是不必操心的事啊!!

Google大神告訴我,在地球的某個地方也有像我一樣的人,Launchpad上的Bug #759990 gnome-terminal ignores default browser!我觀察了幾天,一直忍到今天還是沒什麼動靜,所以我決定自已下來看看是否自已可以修復,用apt-get source抓package下來grep相關的關鍵字,找到了gtk_show_uri的function,合理判斷責任就不在gnome-terminal這邊了,線索指向libgtk2.0!最後在debian的bug report #487862 gnome-terminal doesn't call x-www-browser給我了靈感!

gnome-terminal不吃/etc/alternatives link的設定,所以x-www-browser和gnome-www-browser都指到/usr/bin/google-chrome也沒用,解決的方法到是出奇的容易...


到Unity的Home Button搜Preferred Applications,把Web Browser換成Google Chrome就Okay了,說起來不算是什麼bug,而是Unity Dash讓人誤以為Gnome default browser已經是chrome,實際上是兩個不同的設定,Unity Dash的設定單獨在~/.local/share/applications/defaults.list。

Apr 22, 2011

以Thrift為例 - 單一source打包多個Debian Package

前言

大神長輩最近在用Perl跟Cassandra構通做一些應用程式,而client要跟Cassandra構通需透過Thrift這個RPC framework,一開始的階段編source出來就可以進行下一步了,不過之後系統上線還是需要包成package管理會比較完善,而我自已工作上也有機會要用到Thrift,語言包括工作上的PHP,有興趣的Java、Python等,所以我就撿了這張票來練習包看看,對自已也會有幫助。

之前自已就會包一些Debian Package,不過都是輕量級tarball或是dummy package,這一次包Thrift,過程中碰到蠻多問題的,不過也從中學到不少知識,這次要講的就是怎麼在一包source裡產生出多個Debian Package(dpkg)。

Single or Multiple?

第一個問題就是打包成一個套件還是多個套件比較好?如果像我一樣是業餘的玩家包給自已用的話就以方便快速為原則就好,透過apt套件管理系統來安裝和移除的好處是比較有一致性,管理也方便!安裝了什麼檔案在系統裡也很輕楚(dpkg -L),移除也不會遺留一些垃圾在檔案系統裡。

但在某些狀況下,打包成多個套件是比較好的,例如Java Library通常都會帶有自身的javadoc文件,但通常是只需要jar檔import進來使用,javadoc api通常習慣是在網路上查,如果打包成一個套件,你就留了你遠永不會看的javadoc在你的硬碟裡佔住你的空間,所以發行版套件都會拆開來打包,libcommons-lang-java, libcommons-lang-java-doc就是個例子。

另一個例子就是有大量plugin或module時,就應該拆出來打包,而不是全部都塞成撒尿牛丸包成一個套件,這樣就失去模組化的意義,例如apache2有一堆libapache2-mod-*可以裝,而Thrift就屬於這一種類的,如果你只需要Thrift compiler來compilen定義好的Thrift IDL file,那你就不需要一堆的language binding如perl,java,php,c#,c++,python,ruby等等,如果只需要透過單一語言的binding做事的話,那就裝該語言的套件就好!就不必裝了一堆你跟本用不到的東西在系統上,原本我打算輕鬆又快速的包成一個套件,後來發現不對,我不想裝一些用不到的東西在我系統上啊!!所以就去網路上找看看方法來包成多個套件,發現並沒有一篇整理的比較好的教學,所以就寫一篇來紀錄一下。

Single to Multiple

我自已習慣在自已的home目錄建一個debs的目錄,然後每個package再建一個目錄分開放,避免產生出來的deb file都放在一堆,就不會有command completion互相甘擾的問題,還要多key幾個字元...XD
mkdir -p ~/debs/thrift && cd ~/deb/thrift
wget http://foo.com/thrift-0.6.0.tar.gz
tar zxvf thrift-0.6.0.tar.gz
cd thrift-0.6.0
dh_make -f ../thrift-0.6.0.tar.gz
先照著Debian New Maintainer's Guide把source debianize,生出debian目錄後,重點就在debian/control和debian/rules這兩個檔案而已,先看以下例子:
Source: thrift                         
Section: devel                         
Priority: extra                        
Maintainer: Gasol Wu 
Build-Depends: debhelper (>= 7), autotools-dev, build-essential, ant, 
    pkg-config, libtool, bison, flex, libboost-dev (>= 1.38), openjdk-6-jdk,
    libboost-test1.40-dev, libevent-dev
Standards-Version: 3.8.3               
Homepage: http://thrift.apache.org     
                                       
Package: thrift                        
Architecture: any                      
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: thrift compiler for Thrift definition files.
 Thrift is a software framework for scalable 
 cross-language services development. It  
 combines a software stack with a code generation 
 engine to build services that work efficiently 
 and seamlessly between C++, Java, Python, PHP, 
 Ruby, Erlang, Perl, Haskell, C#, Cocoa, 
 JavaScript, Node.js, Smalltalk, and OCaml.

基本上準備好debian/control檔案,在debian/rules中的install target把檔案通通裝在debian/tmp下包起來就okay了,像下面這樣:
$(MAKE) PREFIX=$(PWD)/debian/tmp/usr install
or
$(MAKE) DESTDIR=$(PWD)/debian/tmp install
現在我們要多包二個套件,分別叫做libthrift-java和libthrift-java-doc,只要在debian/control裡面加上兩個Package的描述,其他的資訊把它補完:
Package: libthrift-java        
Architecture: all
Section: java
Depends: java1-runtime, java2-runtime, ${misc:Depends}
Description: thrift java libraray


Package: libthrift-java-doc
Architecture: all
Section: java
Depends: ${misc:Depends}
Description: thrift java libraray documentation

接著在debian/rules上面做個手腳,原本把檔案裝在debian/tmp目錄下,現在要改成debian/${package}的目錄下,現在我們在debian/control有三個Package的描述,所以要有debian/thrift、debian/libthrift-java、debian/libthrift-java-doc的目錄,接著分別在Makefile debian/rules中想辦法把各套件相關的檔案分別安裝至對應的目錄即可,dh_builddeb就會幫你做打包的動作,如果Makefile不是不符合GNU的規範的話就累人了,有的傷腦筋了!碰到比較奇怪的Makefile要有做點修改貼一堆補丁的心理準備,按Debian Policy是不對upstream source做任何修改的,要修改source的話一律是用patch的形式,所以就有quilt和dpatch可以用,這兩隻tool實在是方便又強大,一試成主顧啊!!下回再來介紹。

另外一提THRIFT-71有patch可以參考,不過它沒有包Perl和PHP,我包PHP最累,搞到aclocal、autoconf、automake都用上了...

Apr 8, 2011

利用PHP處理Solr DateField的時間格式

今天遇到一個case,確定文章進Solr的索引了,但卻搜不出來!通常遇到這種問題,我的解法就是把原本的raw query抓出來,然後一個一個把條件拔掉測試,不過最後發現不是條件的問題,而是資料的問題。

測試了一下,發現是DateField Range Query的條件不過關,長的像fq=created_at:[* TO NOW/HOUR],拔掉後面的/HOUR後確定不是cache的問題,因為用到Distributed Search,一度懷疑是Distributed Search的問題,把shards的參數拔掉也不見效,接下來轉而懷疑是Server的時間不準,發現其中兩台Server時間不準,用NTP校時後本來以為問題解了,但是問題依然存在,待誌不是憨人想的那麼簡單!於是我就trial&error,用盡各種辦法,最後終於發現是當初餵進去的資料就有錯誤,所以條件看起來沒問題,但還是搜不出來。

DateField上說的很清楚,它是用ISO 8601的格式,它長的像下面這樣:
  1. 2002-10-10T12:00:00-05:00
  2. 2002-10-10T17:00:00Z
以上兩個的時間是相等的,Solr要求的是第二種格式,也就是尾巴要接著Z的格式!最初看到這種格式沒有考慮到TimeZone,就寫出了...

date('Y-m-d\TH:i:s\Z', $timestamp)

這樣子的code,於是杯具就這樣產生了...

在了解原因後查了一下date function,format character 'c',就是ISO 8601的格式了,但是它輸出的是上列第一種的格式,並不是Solr所要的,自已做切割字串的動作加上簡單的數學運算看起來是個解法,但直覺想到一堆時間曆法的問題要解決,在沒有完整的testing coverage之下,交給system function會是比較安全的選擇,接下來第二個問題來了,怎麼解比較漂亮?

我用下面的code達成我想要的目的:

function solrDate($timestamp) {
        $dateTime = DateTime::createFromFormat('U', $timestamp, new DateTimeZone('UTC'));
        $iso8601 = $dateTime->format(DateTime::ISO8601);
        $iso8601_with_trailing_z = strstr($iso8601, '+', true) . 'Z';
        return $iso8601_with_trailing_z;
}

Jan 28, 2011

First look at Android 3.0 Honeycomb Preview SDK



Google之前在CES 2011 announce Honeycomb時就很期待Android Tablet的到來,今天Google把Android 3.0 preview SDK端出來了,而且連同ADT也更新至9.0,除了User和Developer關心的Feature之外,這下不得了了,連帶出場的是預編好的emulator的image啊!可以實際跑emulator來玩玩Honeycomb,第一時間下載下來玩,發現爆慢,其實emulator在之前就不快了,隨著resolution從HVGA(480x320)提升到WVGA(800x480)時,就可以明顯感覺頓頓的,這次更提昇到WXGA(1280x768)就爆炸了,想在上面寫程式的我看還是要買機器來測會來的有效率,這筆錢省不了啊...

這種狀態Google自已不會不知道,在Android 3.0 Preview SDK裡的About emulator performance有提到了,原因是emulator必需模擬ARM的指令集,在解析度過大的狀態很明顯應付不來,在未來正式推出時會有所改善,不過我不抱很大的期望,如果你是靠Android溫飽,直接用device來測應該是首選。

Google急著把preview的SDK推上來自有它的道理,因為硬體已經箭在玄上了,必須要趕在上市前讓developer有充足的時間測試他們的App,這次更新除了針對平台UI Widget的更新之外,還有一個很重要的就是向前支援舊版的App,不過並沒有詳細的交代哪些版本,我猜測是2.1以上,我自已也把最近一個寫的App裝上去跑跑看,除了慢到爆炸外到是沒有什麼問題,另外測試了新的Holographic theme,我把android:targetSdkVersion和android:minSdkVersion都改為Honeycomb,但是跑起來沒什麼改變,測不出來...

console會有warning





修改useSdk前

修改useSdk之後,看不出差別...


UI的改變和有的沒的Improve我就不提了,另外還有幾點比較容易忽略,不過值得一提的更新:
  1. 可能Honeycomb太容易crash了(誤),這次還加上了snapshot的功能,emulator會在關閉前保留狀態,開始時restore先前的data來加快開啟的速度...
  2. vm size增加到48m了 (App可以再肥一點了...)

最後重點來了,網頁上的Dev Guide和Reference還沒有更新,但是Android Repository有Documentation for Android Honeycomb Preview SDK, rev 1可以下載,裡面有API和Dev Guide的一篇文章叫Fragments,地位同等於之前的四大金鋼Activity、Service、Broadcast、ContentProvider,簡單的講,一個Activity可以有多個fragment,它有自已的生命週期來跟其他人互動,達成multi-pane的連動效果,還有drag & drop的操作。



先看到這樣,現在lag的程度沒辦法用新的API寫測試程式啊!!!...