2011年12月27日 星期二

[PHP] 如何使用 Onion 建置 PEAR 套件

以往要建置 PEAR 套件,得先研究 package.xml 的規格,然後使用一個超過 200 多行的樣板一行一行修改,若是檔案一多,更是麻煩。
因此 Onion https://github.com/c9s/Onion 是為了解決 PEAR 套件建置所提供的方案。
首先請確認你的程式碼目錄結構
  • src/ 類別目錄
  • doc/ 文件目錄
  • tests/ 單元測試目錄
你的類別名稱與名稱空間需要遵守 PSR-0 的規範,例如以下的類別:
<?php
namespace Foo;
class Bar {
}
應該被放置在 src/Foo/Bar.php 檔案中。
測試相關的檔案可放置於 tests/,一般來說都是使用 PHPUnit 作為測試框架,你也可以使用 PHPUnit_TestMore 來幫助你簡化測試程式碼。
接著即可建立 package.ini 來建置 PEAR 套件。
於套件目錄下,編輯 package.ini 檔案
[package]
name = PacakgeName
version = 0.0.1
desc = description here
summary = summary here
author = Author Name <your_email@email.com>
如果你的套件相依其他 PEAR 模組,可接著定義:
[require]
pear.twig-project.org/Twig = 1.0.1
格式為:
{PEAR Channel Host}/{Package Name} = {Version Expression}
接著,將 Onion.phar 抓取下來裝置於你的系統中:
$ wget https://github.com/c9s/Onion/raw/master/onion.phar
$ chmod +x onion.phar
$ ./onion.phar -d build
即可建置 PEAR 套件檔案。 PackageName-0.0.1.tgz 就會被產生出來。
你也可以透過 PEAR Installer 直接安裝該套件:
$ sudo pear install -f package.xml
若你希望將相依性安裝至該套件目錄,且不需要 root 權限,你可以執行:
$ ./onion.phar -d bundle 
相依套件就會被安裝至 vendor/pear 內。
Onion on GitHub: https://github.com/c9s/Onion

2011年12月25日 星期日

[PHP] Onion For PEAR: 發佈 Onion 0.0.10 bundle 功能


我們目前釋出了 Onion 0.0.10-alpha 的版本,這個版本包含了 bundle 的功能,可以將 PEAR 的相依套件安裝至目前目錄的 vendor 目錄底下,且不需要相依 PEAR Installer 或是 Pyrus。

你可以在 package.ini 內定義好 PEAR 套件的所有相依性,然後執行 onion.phar -d bundle 的命令,Onion 會將所有套件安裝至本地目錄下,且不需要 Root 權限就可以做到。

目前,Onion 是利用 bundle 指令,將 Onion 自己的相依套件全部安裝至 vendor/pear ,然後使用 Onion 自己的 compile 命令,將本身程式碼、相依程式碼、自動類別載入器打包成 phar 的執行檔。

你也可以使用 Onion 來編譯你自己的 phar 函式庫或是執行檔。你可以參考原始碼內的 scripts/compile.sh 命令。

因為 Pyrus 沒有把 Package.xml 剖析器類別、PEAR 頻道探索器等文件寫好,也因為他不是獨立的元件,所以我為 Onion 寫了一個內建的 PEAR 頻道探索器 (PEAR Channel) 以及簡單的 package.xml 剖析器,來處理 PEAR 套件的安裝程序。 這些東西運作的相當快,不過 Channel 的資訊還未被快取起來,只要快取的部份處理好後,速度會比現在更快。

我已經測試了一些 Symfony, PHPUnit, PHPSpec, PEAR 套件,大多數都運作的挺順利,但是可能還有一些 Bug ,如果你遇到了,請發送一個 Issue 給我,Onion 專案是建置在 GitHub 上頭。

Patches, Feature requests are welcomed.


Here is the screenshot:




Related Tweets:

https://twitter.com/#!/yuya_takeyama/status/150642017003778050
https://twitter.com/#!/yuya_takeyama/status/150627664917577728
https://twitter.com/#!/yuya_takeyama/status/150619889244180481

Onion For PHP: Announcing Onion 0.0.10 bundle feature

We currently released Onion 0.0.10-alpha, this version introduced a bundle feature, which can install PEAR package dependencies into a vendor directory.

You can define your PEAR package dependencies in package.ini, and run onion.phar -d bundle, onion will install dependencies locally, and root permission is not needed.

Currently, Onion is using bundle command to install Onion's dependencies, and run onion compile command to compile src/, vendor/pear/ and a SPLClassLoader into a phar file.

You can also use Onion to compile your library into a plain library phar file or executable phar file, you can check the script "scripts/compile.sh".

Since Pyrus didn't document much of its PackageXml parser and Channel Discover, and it's not independent component, I wrote a built-in PEAR channel discover and a simple package.xml parser for this, which is pretty fast already. but the channel information is not cached yet. Once the cache stuff is done, this could be more faster than current one.

I've tested many PEAR packages from Symfony, PHPUnit, PHPSpec, most of them works fine, but may have some bugs still, If you encountered, please send an issue on GitHub/Onion repository.

Onion project is hosted on GitHub, patches and feature request are welcomed.

Here is the screenshot:




Related Tweets:

https://twitter.com/#!/yuya_takeyama/status/150642017003778050
https://twitter.com/#!/yuya_takeyama/status/150627664917577728
https://twitter.com/#!/yuya_takeyama/status/150619889244180481

2011年12月24日 星期六

Access 97, ODBC, unixODBC, iODBC, mdbtools 問題處理記錄

今天處理 Microsoft Access Database 的問題就花上了一整天 ...

簡單介紹一下該死的 MS Access Database (*.mdb) 是微軟發展的資料庫引擎,從 Access 97 使用 Jet 3.5 版本,從 Access 2000 時則採用 Jet 4.0 版本。

可以在 DSN 時指定 Provider 參數 Provider=Microsoft.Jet.OLEDB.4.0 指定 Jet OLEDB 的版本。


而在 Unix 系統上大致上有多款 Jet Database Engine 的實作 (應該是反向工程而來的) ,譬如:


首先 mdbtools 是由 C 寫成,可讀取 Access 97 版本以上的 mdb 檔案,不過在編碼的部份有點問題,若 Access 97 內使用 Big5 ,似乎沒辦法順利透過 mdbtools 提供的 charset 環境變數來指定,程式碼中使用到 iconv 的環境變數有:

MDBICONV=UTF-8
MDB_JET3_CHARSET=Big-5

該 JET3_CHARSET 為資料庫編碼,MDBICONV 為內部編碼,但這個解法無效,頂多只能讀出 Table 以及各 Table 資料內的比數,但由於 Access DB 的開發人員相當蠢,直接用 Big5 編碼的字元當做 Table Name ,所以無效。

後來也嘗試使用 mdbtools 將讀取出的 Table Name 利用 mbstring convert encoding 試著從 Big5 轉為 UTF-8 ,但這條路也不通,但讀出的字元是 ASCII 沒錯 (should be Big-5),這部份不知道是否有長輩有解答 ?

但我想只要該 DB 內資料若使用 ASCII 或是 ISO8859-1 的話應該是可以運作順利。

Jackcess 主要由 Java 所寫成,目前看起來可靠度最高,但是不支援 Access 97 以下版本,除此之外其他的 Jet Database 都支援,程式碼內也有 junit 所寫成的單元測試,測試各種格式的資料庫版本,不過因為不支援 Access 97 ,所以沒有繼續嘗試,否則應該是很好的跨平台解決方案。



資料庫介面的部份可以透過 ODBC 或是 iODBC 或是 Windows 上的 COM 元件來建立 ADODB 連線來讀取 Access Database 的資料庫,也可透過 ActiveXObject 建立 ADODB 連線。

不幸的地方在於,Unix 上的 mdbtools 既然無法運作正確,再接著用 ODBC 指定 Driver 為 mdbtools 也無用了。 否則應該是可以透過下列方式連結:

// With DSN
$connection = odbc_connect("access_db",'','');

// For Windows, DSN-less
$connection = odbc_connect("Driver={Microsoft Access Driver (*.mdb)};Dbq=$mdbFilename", $user, $password);

不過 ODBC 的部份光是指定 mdbtools 連連線都有問題。


接著嘗試使用 Windows 7 64bit 建立連至 Access 97 mdb 檔案的 ODBC 連線,發現 Jet Database Engine 並不支援 64bit Windows 7 ,有看到大概的解法,但我嘗試過也不行:

C:\Windows\SysWow64\odbcad.exe

所以只好轉而裝個 Virutalbox Windows XP 建立 ODBC 連線,連線沒問題,但同樣也卡在編碼。

整個 Google 都快翻過來的沒看到任何可以對 Access *.mdb 指定 CodePage 或是 Charset 的方法,或是嘗試了完全無效。

總之嘗試了以下大概幾種:

* Windows PHP 內的 COM 元件建立 ADODB.Connection
* JScript 使用 ActiveXObject 建立 ADODB.Connection
* PHP odbc_connect 連線

這三種途徑在 Windows XP 32bit 上都可順利連線,取得資料表清單,但仍是有編碼問題。

也就是說,就算是用微軟自己的 JScript (CScript) 都沒辦法正確讀出字元

推測大概還有幾種解決方法:

- 使用 Access 2010 把 Access 97 轉為較新版本的 mdb。
- 使用 MySQL Migration Toolkit 轉匯入至 MySQL (不過在新版的 MySQL 內卻找不到 Migration Toolkit 了,是否有分割出來 ? )

但我想編碼的方式應該還是有辦法解決,只是時間上的問題罷了。XD






2011年12月19日 星期一

Predis is using Onion to build PEAR package.

Predis is using Onion

I'm glad to see this, nrk uses Onion to build their PEAR package.

predis commit: https://github.com/nrk/predis/commit/104cd1eae7f3fb2bff3ccd3193c3e31b8502af56

Use Onion to build PEAR packages of Predis.
Since Pearhub is currently broken (unfortunately the project does not seem to
be actively mantained anymore) but we still want to have PEAR packages for our
library, we need to automate the creation of a package.xml definition file to
build the actual packages that will be uploaded on a self-hosted PEAR channel.

Onion, while still in its alpha stage right now, works perfectly fine for our
needs and its own package.ini file looks simple enough to edit and maintain.

See http://c9s.github.com/Onion for more details about Onion and thank @c9s
for making it available.

2011年12月18日 星期日

PHPUnit_TestMore

PHPUnit_TestMore

PHPUnit is a great unit testing framework for PHP http://www.phpunit.de/manual/current/en/.

This helper library PHPUnit_TestMore https://github.com/c9s/PHPUnit_TestMore is for PHPUnit Test Framework, which brings the good things from the Test::More http://search.cpan.org/~mschwern/Test-Simple-0.98/lib/Test/More.pm library of Perl into PHP platform.

The original PHPUnit TestCase is trivial, for example:

function test() {
    $this->assertTrue( true );
    $this->assertArrayHasKey('foo', array('bar' => 'baz'));
    $this->assertClassHasAttribute('foo', 'stdClass');
    $this->assertContains(4, array(1, 2, 3));
}

If you write Perl, you must be familiar with this:

#!/usr/bin/env perl
use Test::More tests => 10;
$val = 1;
ok( $val );
is( 1, 1 );

Which is much simpler and easy, let you not to hate writing unit tests.

Then here is the PHP version's Test::More:

class FooTest extends PHPUnit_Framework_TestCase 
{
    function test() 
  {
        ok(1);
        ok(true);
        ok('string');
        not_ok(false);
  }
}

Setup phpunit.xml configuration

Create a file named phpunit.xml, and set the attribute printerClass to PHPUnit_Util_Log_TAP:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="tests/bootstrap.php"
        backupGlobals="false"
        verbose="true"
        syntaxCheck="true"
        convertErrorsToExceptions="true"
        convertNoticesToExceptions="true"
        convertWarningsToExceptions="true"
        printerClass="PHPUnit_Util_Log_TAP">
<testsuites>
    <testsuite name="PHPUnit">
    <directory suffix="Test.php">tests</directory>
    </testsuite>
</testsuites>
</phpunit>

In your bootstrap.php, require the TestMore helper.

require 'tests/PHPUnit_TestMore.php';

How it works

To reduce unit testing code, there is a function called debug_backtrace, which returns a call stack of current function call.

Here is some ideal PHP code synopsis for testing:

function test()
{
    ok( 1 );
    is( 1, 1);
}

To let the ok function get the caller object, we use debug_backtrace to call the original assertNotEmpty method:

function ok( $v , $msg = null )
{
    $stacks = debug_backtrace( DEBUG_BACKTRACE_PROVIDE_OBJECT );                      $testobj = $stacks[1]['object'];
    $testobj->assertTrue( $v ? true : false , $msg );
}

2011年12月1日 星期四

PHP - Current Onion PHP Package builder

Current Onion PHP Package builder (building #PEAR package) #PHP https://github.com/c9s/Onion



It works perfectly.

package.ini

The package config file is pretty simple, here:

And we used to write trivial xml format config by hands like this:

The package.xml 2.0


https://gist.github.com/1415004