<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>哇寶部落格</title>
	<atom:link href="http://blog.wabow.com/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.wabow.com</link>
	<description>Wabow Information Inc. Blog</description>
	<lastBuildDate>Fri, 21 May 2010 15:11:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Zend Framework Testing 入門 - 測試環境建置篇</title>
		<link>http://blog.wabow.com/archives/2345</link>
		<comments>http://blog.wabow.com/archives/2345#comments</comments>
		<pubDate>Fri, 21 May 2010 10:51:28 +0000</pubDate>
		<dc:creator>jaceju</dc:creator>
				<category><![CDATA[技術分享]]></category>

		<guid isPermaLink="false">http://blog.wabow.com/?p=2345</guid>
		<description><![CDATA[本文轉自：Zend Framework Testing 入門 - 測試環境建置篇 自 Zend Framework 1.6 之後就提供了 Zend_Test 這個套件，協助我們為 Zend Framework 的 MVC 做單元測試。然而當時也許是因為大家對 Zend Framework 的新架構還不熟悉，加上 Zend_Test 套件有許多小地方還不是很完善，因此就很少有人利用它來做測試。 而到了 Zend Framework 1.8 版之後， Zend_Test 便修正了許多缺點；而且也因為 Zend_Application 套件的引入，讓 Zend_Test 在 Controller 上的測試更加方便，也使得網路上許多高手開始為它編寫教學。 不過官方的文件並沒有特別告訴我們怎麼去建構 Zend Framework Testing 的環境，所以以下我以 Zend Framework 1.10 再加上 PHPUnit 3.4 為例，帶領大家進入 Zend Framework Testing 的世界。 準備 Zend Framework [...]]]></description>
			<content:encoded><![CDATA[<p>本文轉自：<a href="http://www.jaceju.net/blog/?p=1152">Zend Framework Testing 入門 - 測試環境建置篇</a></p>
<p>自 Zend Framework 1.6 之後就提供了 Zend_Test 這個套件，協助我們為 Zend Framework 的 MVC 做單元測試。然而當時也許是因為大家對 Zend Framework 的新架構還不熟悉，加上 Zend_Test 套件有許多小地方還不是很完善，因此就很少有人利用它來做測試。</p>
<p>而到了 Zend Framework 1.8 版之後， Zend_Test 便修正了許多缺點；而且也因為 Zend_Application 套件的引入，讓 Zend_Test 在 Controller 上的測試更加方便，也使得網路上許多高手開始為它編寫教學。</p>
<p>不過官方的文件並沒有特別告訴我們怎麼去建構 Zend Framework Testing 的環境，所以以下我以 Zend Framework 1.10 再加上 PHPUnit 3.4 為例，帶領大家進入 Zend Framework Testing 的世界。</p>
<p><span id="more-2345"></span></p>
<h2>準備 Zend Framework 專案</h2>
<p>要進行測試前，我們得先要有個 Zend Framework 專案。假設這個專案名稱叫 unittest ，原始檔位於 D:\WEB\zf\unittest 上，我們用 Zend Framework 提供的 Zend_Tool工具來建立它：</p>

<div class="wp_syntax"><div class="code"><pre class="dos" style="font-family:monospace;">zf create project unittest</pre></div></div>

<p>然後我們切換到該專案目錄下：</p>

<div class="wp_syntax"><div class="code"><pre class="dos" style="font-family:monospace;"><span style="color: #b1b100; font-weight: bold;">cd</span> unittest</pre></div></div>

<p class="note">註：雖然我是以 Win32 為主要環境，但 Linux 上的操作步驟也是雷同。</p>
<p>由於我個人偏好搬動整個目錄就可以移植專案的模式，因此我就不採用 Zend Framework 原本將 index.php 放在 public 目錄下的架構；以下動作的目的就是把 index.php 從 public 目錄移出來。</p>
<p>首先先把 D:\WEB\zf\unittest\public\index.php 和 D:\WEB\zf\unittest\public\.htaccess 複製到 D:\WEB\zf\unittest 下，然後修改 D:\WEB\zf\unittest\.zfproject.xml ，把上方紅框處的 index.php 和 .htaccess 的 XML tag 複製一份到下方的紅框處：</p>
<p class="image"><a href="http://www.jaceju.net/resources/zend_test_with_netbeans/zfproject_xml.png"><img src="http://www.jaceju.net/resources/zend_test_with_netbeans/zfproject_xml.png" alt="修改 .zfproject.xml" /></a></p>
<p>接下來要修改 D:\WEB\zf\unittest\index.php 中 application 目錄的相對位置；找到：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">||</span> <span style="color: #990000;">define</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'APPLICATION_PATH'</span><span style="color: #339933;">,</span> <span style="color: #990000;">realpath</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">dirname</span><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">__FILE__</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'/../application'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>改為：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">||</span> <span style="color: #990000;">define</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'APPLICATION_PATH'</span><span style="color: #339933;">,</span> <span style="color: #990000;">realpath</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">dirname</span><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">__FILE__</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'/application'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>然後我們要在 D:\WEB\zf\unittest\.htaccess 加入當前環境的常數，也就是在它的最上面一行加入：</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">SetEnv APPLICATION_ENV development</pre></div></div>

<p>原來的 D:\WEB\zf\unittest\public\index.php 則用來阻擋使用者瀏覽 public 目錄，所以我們把它改成：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #990000;">header</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'HTTP/1.1 403 Forbidden'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>而原來的 D:\WEB\zf\unittest\public\.htaccess 則是將 Rewrite Engine 關閉，讓外界可以直接存取：</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">RewriteEngine Off</pre></div></div>

<p>這樣就準備好我們的專案了。</p>
<h2>在 NetBeans 中加入專案</h2>
<p>NetBeans 近來對 PHP 的支援變得非常強大，讓我一用就愛上它。到  6.8 版為止， NetBeans 還沒有正式支援 Zend Framework ，不過這並不影響我們用它來開發以 Zend Framework 為架構的專案。</p>
<p> 而這裡會提到 NetBeans ，主要是因為它支援了 PHPUnit ！而且還有圖形化介面；這使得我們在對 PHP 專案進行單元測試時更加便利！</p>
<p>回到剛剛我們建立的 Zend Framework 專案，我們可以在 NetBeans 裡加入一個現成的 PHP 專案。在工具列中，選擇 File &gt; New Project... 後，會出現以下視窗：</p>
<p class="image"><a href="http://www.jaceju.net/resources/zend_test_with_netbeans/new_php_project.png"><img src="http://www.jaceju.net/resources/zend_test_with_netbeans/new_php_project.png" alt="建立 NetBeans 專案" /></a></p>
<p>然後要選擇現存專案的位置：</p>
<p class="image"><a href="http://www.jaceju.net/resources/zend_test_with_netbeans/location.png"><img src="http://www.jaceju.net/resources/zend_test_with_netbeans/location.png" alt="選擇專案位置" /></a></p>
<p>最後設定專案執行時的設置：</p>
<p class="image"><a href="http://www.jaceju.net/resources/zend_test_with_netbeans/final.png"><img src="http://www.jaceju.net/resources/zend_test_with_netbeans/final.png" alt="完成專案其它設定" /></a></p>
<p>這樣一來我們就可以在 NetBeans 裡開發 Zend Framework 的專案了。</p>
<h2>Zend_Test 基礎</h2>
<p>Zend_Test 主要是基於 PHPUnit 這個 PHP 界公認最完善的自動化測試套件所開發的，所以不論是在設置環境或是在撰寫測試上，其實都是以 PHPUnit 的架構去完成。</p>
<p>為了避免本文內容過於冗長，這裡我已經先行設定好 PHPUnit 的執行環境；因此在繼續以下的步驟前，請大家先確認自己是否可以正確執行 PHPUnit 。</p>
<p>在 Zend Framework 為我們們準備好的專案目錄架構中，已經事先建立了 tests 這個供我們放置測試的目錄，所以現在我們可以先試試看用 PHPUnit 來執行我們的測試。假設我們目前的工作路徑是 D:\WEB\zf\unittest\ ，我們要先切換到 tests 目錄下：</p>

<div class="wp_syntax"><div class="code"><pre class="dos" style="font-family:monospace;"><span style="color: #b1b100; font-weight: bold;">cd</span> tests</pre></div></div>

<p>然後用 PHPUnit 提供的 Command Line Interface (CLI) 工具 phpunit 來執行測試：</p>

<div class="wp_syntax"><div class="code"><pre class="dos" style="font-family:monospace;">phpunit .</pre></div></div>

<p>我們會發現執行的結果出現了以下錯誤：</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">PHPUnit_Framework_Exception: Could not load &quot;D:\WEB\zf\unittest\tests\phpunit.xml&quot;.</pre></div></div>

<p>原來， phpunit 這個工具在我們對一個目錄進行測試時，會自動去剖析該目錄下的 phpunit.xml 內容；而 phpunit.xml 在 Zend_Tool 產生之後，並沒有任何內容，所以就使得 PHPUnit 丟出了一個異常。</p>
<p>所以這裡我們先簡單將它變成一個正確的 XML 檔案，在 D:\WEB\zf\unittest\tests\phpunit.xml 中我們加入：</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;phpunit<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/phpunit<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>然後在 Command Line 環境下再跑一次測試，結果如下：</p>
<p class="image"><a href="http://www.jaceju.net/resources/zend_test_with_netbeans/phpunit_cli.png"><img src="http://www.jaceju.net/resources/zend_test_with_netbeans/phpunit_cli.png" alt="執行 phpunit" /></a></p>
<p>這表示 PHPUnit 認得我們的測試環境啦！</p>
<h2>建立測試</h2>
<p>其實上面也只是讓 phpunit 能在我們的專案上啟用而已，但我們的測試主角根本還沒出現，所以接下來我們要開始來建立測試了。</p>
<p>Zend_Tool 建立出來的專案架構，其實有個預設的前置名稱，叫做 Application ；這個 Application 之後都做為專案中 Model 的前置名稱。一般來說，我都會將它改為像是 MyApp 或是 Shop 等等諸如此類符合目前專案性質的名稱。 Zend_Tool 也提供我們修改這個前置名稱的機制：</p>

<div class="wp_syntax"><div class="code"><pre class="dos" style="font-family:monospace;">zf change application.class-name-prefix MyApp</pre></div></div>

<p>執行結果如下：</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">Note: the name provided &quot;MyApp&quot; was altered to &quot;MyApp_&quot; for correctness.
Note: All existing models will need to be altered to this new namespace by hand
application.ini updated with new appnamespace MyApp_
Updating project profile 'D:\WEB\zf\unittest/.zfproject.xml'</pre></div></div>

<p>要注意的是，如果在修改前就已經存在的 Model ，它們的前置名稱就要手動改成新的。</p>
<h3>建立第一個 Model</h3>
<p>接著我們建立第一個 Model Class ：</p>

<div class="wp_syntax"><div class="code"><pre class="dos" style="font-family:monospace;">zf create model MyClass1</pre></div></div>

<p>執行結果如下：</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">Creating a model at D:\WEB\zf\unittest/application/models/MyClass1.php
Updating project profile 'D:\WEB\zf\unittest/.zfproject.xml'</pre></div></div>

<p>在 D:\WEB\zf\unittest/application/models/MyClass1.php 中就是 MyClass1 的內容：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> MyApp_Model_MyClass1
<span style="color: #009900;">&#123;</span>
&nbsp;
&nbsp;
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>當然這個檔案目前只有簡單的類別定義而已，其他就是要靠我們自己手動完成。不過由於我們的重點是測試，所以這裡我們就不管 MyClass1 的內容。</p>
<h3>用 NetBeans 產生 Test Case</h3>
<p>前面提到 NetBeans 支援 PHPUnit ，因此這裡我們就直接試著用它來幫我們產生測試檔案。切換到專案目錄的「 Source Files/application/models 」下，在 MyClass1.php 上按下右鍵選擇「工具 / Create PHPUnit tests 」，我們就可以建立針對 MyClass1 類別的 Test Case ：</p>
<p class="image"><a href="http://www.jaceju.net/resources/zend_test_with_netbeans/create_phpunit_tests.png"><img src="http://www.jaceju.net/resources/zend_test_with_netbeans/create_phpunit_tests.png" alt="產生 Model Test Case" /></a></p>
<p>但因為 NetBeans 還不知道測試目錄的所在位置，因此它會提示我們輸入測試目錄；在這裡，我們當然就是選擇 D:\WEB\zf\unittest\tests ：</p>
<p class="image"><a href="http://www.jaceju.net/resources/zend_test_with_netbeans/select_test_dir.png"><img src="http://www.jaceju.net/resources/zend_test_with_netbeans/select_test_dir.png" alt="選擇測試目錄" /></a></p>
<p>在按下確定之後， NetBeans 就會自動打開產生好的 Test Case 檔案。在本例中，它的位置就是在 D:\WEB\zf\unittest\tests\application\models\MyApp_Model_MyClass1Test.php 。</p>
<p>另外 NetBeans 也會把 tests 從原來的 Source Files 中獨立成 Test Files 目錄結構，但別忘了它實際的位置還是在 D:\WEB\zf\unittest\ 下。</p>
<h3>目錄結構對應</h3>
<p>繼續下個步驟之前，我們先來整個專案的目錄結構：</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">unittest
 |--application
 |   |--models
 |       |--MyClass1.php
 |--library
 |--docs
 |--public
 |--tests
 |   |--application
 |       |--models
 |           |--MyApp_Model_MyClass1Test.php
 |   |--library
 |   |--phpunit.xml
 |--.zfproject.xml
 |--.htaccess
 |--index.php</pre></div></div>

<p>從上面的架構圖可以看到，在這個 tests 目錄下的 application 及 library ，就是對應著我們的專案目錄下的 application 及 library 。換句話說，我們在專案目錄下的 application/models 所建立的 Model Class ，它們的測試程式就可以放在 tests/application/models 下，其他以此類推。</p>
<h3>執行測試類別</h3>
<p>在我們建立好 MyApp_Model_MyClass1Test 這個測試類別後，就可以在上面撰寫測試案例了。這裡我們先簡單加入一個空的測試案例，即 testMethod1 方法：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// ... 略 ...</span>
<span style="color: #000000; font-weight: bold;">class</span> MyApp_Model_MyClass1Test <span style="color: #000000; font-weight: bold;">extends</span> PHPUnit_Framework_TestCase
<span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// ... 略 ...</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> testMethod1<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>接著就可以執行測試了。</p>
<p>這裡雖然我們可以用 phpunit 來執行測試，不過 NetBeans 也可以幫我們代勞。我們可以在 NetBeans 的 Project 視窗中，對 unittest 專案名稱按下滑鼠右鍵，執行 Test 指令 (或直接按下 Alt + F6 ) ，這樣就會開始執行測試了。</p>
<p class="image"><a href="http://www.jaceju.net/resources/zend_test_with_netbeans/run_project_test.png"><img src="http://www.jaceju.net/resources/zend_test_with_netbeans/run_project_test.png" alt="執行專案測試" /></a></p>
<p>完成測試後，就會出現下圖中的 Test Results 視窗。</p>
<p class="image"><a href="http://www.jaceju.net/resources/zend_test_with_netbeans/netbeans_test.png"><img src="http://www.jaceju.net/resources/zend_test_with_netbeans/netbeans_test.png" alt="完成測試的畫面" /></a></p>
<p>這看起來是不是比先前的 Command Line 輸出結果好多了呢？</p>
<h2>測試環境的自動載入</h2>
<p>在測試時，其實我希望要測試用的類別能被自動載入，而不需要加入一堆的 require_once 。以往我在舊專案的做法是在每個測試案例之前，引用一個 bootstrap.php 檔，內容如下：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #990000;">define</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'APP_PATH'</span><span style="color: #339933;">,</span> <span style="color: #990000;">realpath</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">dirname</span><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">__FILE__</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'/../app/'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #990000;">set_include_path</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">implode</span><span style="color: #009900;">&#40;</span>PATH_SEPARATOR<span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    <span style="color: #990000;">realpath</span><span style="color: #009900;">&#40;</span>APP_PATH <span style="color: #339933;">.</span> <span style="color: #0000ff;">'/lib'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #990000;">realpath</span><span style="color: #009900;">&#40;</span>APP_PATH <span style="color: #339933;">.</span> <span style="color: #0000ff;">'/base'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #990000;">realpath</span><span style="color: #009900;">&#40;</span>APP_PATH <span style="color: #339933;">.</span> <span style="color: #0000ff;">'/mod/common/models'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #990000;">get_include_path</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">function</span> autoload<span style="color: #009900;">&#40;</span><span style="color: #000088;">$className</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$className</span> <span style="color: #339933;">=</span> <span style="color: #990000;">str_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'_'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'/'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$className</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">require_once</span> <span style="color: #0000ff;">&quot;<span style="color: #006699; font-weight: bold;">$className</span>.php&quot;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #990000;">spl_autoload_register</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'autoload'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>而在新架構中， Zend_Tool 很貼心地為我們產生好了這個檔案，也就是 D:\WEB\zf\unittest\tests\application\bootstrap.php 。</p>
<p class="note">註：不過 D:\WEB\zf\unittest\tests\application\bootstrap.php 裡面的內容是空的，我們得自己把它加入。</p>
<p>但是每次都要在測試類別檔載入這個 bootstraop.php 也是相當麻煩，還好 PHPUnit 讓我們可以在 phpunit.xml 中去加入對 bootstraop.php 的自動引用。接下來請將 D:\WEB\zf\unittest\tests\phpunit.xml 的內容改為：</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;phpunit</span> <span style="color: #000066;">bootstrap</span>=<span style="color: #ff0000;">&quot;./application/bootstrap.php&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span></pre></div></div>

<p>這麼一來，當我們執行 phpunit 時，就會自動引入 bootstraop.php 了。而這裡要注意的是， ./application/bootstrap.php 這個路徑是相對於 phpunit.xml 的，其他非絕對路徑的設定也是。</p>
<p>不過上面的  bootstraop.php 寫法在新的 Zend Framework 架構中就不適用了，因為它的自動載入只能應付類別名稱為 Xxx_Yyy_Zzz 並對應到檔名為 Xxx/Yyy/Zzz.php 的模式；而新架構中的 Model 則是位於 application/models 之下，也就是說我們的 MyApp_Model_MyClass1 這個類別的實際位置是 D:\WEB\zf\unittest\application\models\MyApp_Model_MyClass1.php ，因此我們得想辦法讓 bootstrap.php 能自動載入新架構的 Model Class 。</p>
<p>還好 Zend_Loader 提供了 Zend_Loader_Autoloader_Resource 這個套件，來幫我們載入 Zend Framework MVC 架構下的 Model Class 。所以我們的 bootstrap.php 就可以改成：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #990000;">error_reporting</span><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">E_ALL</span> <span style="color: #339933;">|</span> <span style="color: #009900; font-weight: bold;">E_STRICT</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #990000;">date_default_timezone_set</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Asia/Taipei'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #990000;">define</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'APPLICATION_ENV'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'testing'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">define</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'APPLICATION_PATH'</span><span style="color: #339933;">,</span> <span style="color: #990000;">realpath</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">dirname</span><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">__FILE__</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'/../../application'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">define</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'APPLICATION_CONFIG'</span><span style="color: #339933;">,</span> APPLICATION_PATH <span style="color: #339933;">.</span> <span style="color: #0000ff;">'/configs/application.ini'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #990000;">set_include_path</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">implode</span><span style="color: #009900;">&#40;</span>PATH_SEPARATOR<span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    <span style="color: #990000;">realpath</span><span style="color: #009900;">&#40;</span>APPLICATION_PATH <span style="color: #339933;">.</span> <span style="color: #0000ff;">'/../library'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #990000;">realpath</span><span style="color: #009900;">&#40;</span>APPLICATION_PATH <span style="color: #339933;">.</span> <span style="color: #0000ff;">'/../tests'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #990000;">get_include_path</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">require_once</span> <span style="color: #0000ff;">'Zend/Loader/Autoloader.php'</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$autoloader</span> <span style="color: #339933;">=</span> Zend_Loader_Autoloader<span style="color: #339933;">::</span><span style="color: #004000;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$resourceLoader</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Zend_Loader_Autoloader_Resource<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    <span style="color: #0000ff;">'basePath'</span>      <span style="color: #339933;">=&gt;</span> APPLICATION_PATH<span style="color: #339933;">,</span>
    <span style="color: #0000ff;">'namespace'</span>     <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'MyApp'</span><span style="color: #339933;">,</span>
    <span style="color: #0000ff;">'resourceTypes'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'model'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
            <span style="color: #0000ff;">'path'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'models/'</span><span style="color: #339933;">,</span>
            <span style="color: #0000ff;">'namespace'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'Model'</span><span style="color: #339933;">,</span>
        <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$autoloader</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">pushAutoloader</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$resourceLoader</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p class="note">註： Zend_Loader_Autoloader_Resource 的詳細用法請參考官方手冊 <a href="http://zendframework.com/manual/en/zend.loader.autoloader-resource.html">Resource Autoloaders</a> 一節的說明。</p>
<p>現在我們可以試著把 MyApp_Model_MyClass1Test.php 中的 require_once 敘述移除，試試看 phpunit 會不會自動載入。</p>
<p>不過特別要注意的是， bootstrap.php 只會在 phpunit.xml 被載入時自動被引用，因此我們就一定要透過 phpunit . 這樣的方式來執行測試，不然就會發生找不到 Model Class 檔案的狀況。如果我們只想單獨執行某個測試類別時 (例如 MyApp_Model_MyClass1Test ) ，就必須改用以下的方式執行：  (假設當前工作目錄是在 D:\WEB\zf\unittest\tests ) </p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">phpunit application\models\MyApp_Model_MyClass1Test<span style="color: #339933;">.</span>php <span style="color: #339933;">--</span>configuration <span style="color: #339933;">./</span>phpunit<span style="color: #339933;">.</span>xml</pre></div></div>

<p>而在 NetBeans 中，我們可以在 Project 視窗的 Test Files 上按下滑鼠右鍵選擇 Properties ，就會出現以下視窗：</p>
<p class="image"><a href="http://www.jaceju.net/resources/zend_test_with_netbeans/phpunit_config.png"><img src="http://www.jaceju.net/resources/zend_test_with_netbeans/phpunit_config.png" alt="NetBeans 中的 PHPUnit 設定" /></a></p>
<p>然後我們再指定 phpunit.xml 的位置，這樣就算只對單一的 Model 進行測試， NetBeans 也會自動幫我們載入 phpunit.xml 了。</p>
<h2>加入更多測試</h2>
<p>一個專案裡要測試的 Model 當然不可能只有一個，接著我們再加入新的 Model 。在 D:\WEB\zf\unittest 之下，我們執行：</p>

<div class="wp_syntax"><div class="code"><pre class="dos" style="font-family:monospace;">zf create model MyClass2</pre></div></div>

<p>然後再透過 NetBeans 的 Create PHPUnit tests ，幫它建立一個測試類別 MyApp_Model_MyClass2Test 。當然也別忘了幫這個測試類別加入測試案例，以免執行測試時會出現沒有測試案例的警告。</p>
<p>不是只有 Model 可以被測試，在 Zend_Test 裡也提供了測試 Controller 的方法；方法很簡單，以預設的 IndexController 為例，我們一樣也是在 NetBeans 的 Project 視窗中，對 unittest/application/controllers/IndexController.php 執行 Create PHPUnit tests 就可以了。</p>
<p>但是這樣卻有可能出現以下的錯誤訊息，而無法成功建立 IndexController 的測試類別。</p>
<p class="image"><a href="http://www.jaceju.net/resources/zend_test_with_netbeans/create_test_error.png"><img src="http://www.jaceju.net/resources/zend_test_with_netbeans/create_test_error.png" alt="建立測試失敗" /></a></p>
<p>而查看輸出視窗 (Ctrl + 4) ，實際的錯誤訊息是：</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">Fatal error: Class 'Zend_Controller_Action' not found in D:\WEB\zf\unittest\application\controllers\IndexController.php on line 3</pre></div></div>

<p>這是因為 NetBeans 其實是透過 phpunit --skeleton-test 這個指令來幫助我們建立測試類別，而 --skeleton-test 會利用 PHP 5 的 Reflection 機制幫我們找出類別裡的方法；但 Reflection 也會需要相關引用到的類別的定義 (這裡就是 Zend_Controller_Action ) ，因此在沒有事先定義好的狀況下， phpunit 就會回報錯誤了。</p>
<p>解決的方法很簡單，我們只要在 IndexController 類別的上方加入：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">require_once</span> <span style="color: #0000ff;">'Zend/Controller/Action.php'</span><span style="color: #339933;">;</span></pre></div></div>

<p>就可以再執行 Create PHPUnit tests 指令了。</p>
<p>完成後， NetBeans 就會產生 D:\WEB\zf\unittest\tests\application\controllers\IndexControllerTest.php 這個檔案了。</p>
<h2>測試 Controller</h2>
<p>雖然前面我們產生了 IndexControllerTest 這個測試類別，但是它卻不能用來測試 IndexController 的流程。這是因為我們沒有去啟動 Zend_Application 及相關的 Resource ，所以這裡我們要借重 Zend_Test 提供的 Zend_Test_PHPUnit_ControllerTestCase 類別來幫我們進行測試。請將 D:\WEB\zf\unittest\tests\application\controllers\IndexControllerTest.php 的內容改為：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000000; font-weight: bold;">class</span> IndexControllerTest <span style="color: #000000; font-weight: bold;">extends</span> Zend_Test_PHPUnit_ControllerTestCase
<span style="color: #009900;">&#123;</span>
    protected <span style="color: #000000; font-weight: bold;">function</span> setUp<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">bootstrap</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'appBootstrap'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        parent<span style="color: #339933;">::</span><span style="color: #004000;">setUp</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> appBootstrap<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
	  	<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">application</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Zend_Application<span style="color: #009900;">&#40;</span>APPLICATION_ENV<span style="color: #339933;">,</span> APPLICATION_CONFIG<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	  	<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">application</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">bootstrap</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> testHome<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">dispatch</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">assertAction</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;index&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">assertController</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;index&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">assertResponseCode</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">200</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>在這裡我們要借重 Zend_Test_PHPUnit_ControllerTestCase 提供的 bootstrap 機制，幫我們處理有關應用程式設定與 Front Controller 等相關資源的啟動；然後我們就可以簡單地透過 Zend_Test_PHPUnit_ControllerTestCase 提供的方法 (例如 dispatch ) ，來幫我們測試 Controller 的流程。</p>
<p>上面的例子裡我們只很簡單地測試首頁，至於更進階的 Controller 測試，有機會我會再分享給大家。</p>
<h2>進階的 phpunit.xml 設定</h2>
<p>在 phpunit.xml 中可以設定的項目很多，可以參考<a href="http://www.phpunit.de/manual/current/en/appendixes.configuration.html" target="_blank">官方手冊的說明</a>，這邊我們簡單地探討幾個常用的項目。</p>
<h3>testsuite</h3>
<p>testsuite 標籤主要是幫我們透過 PHPUnit_Framework_TestSuite 去組織多個測試類別，例如以下範例：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">&lt;</span>phpunit bootstrap<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;./application/bootstrap.php&quot;</span><span style="color: #339933;">&gt;</span>
    <span style="color: #339933;">&lt;</span>testsuite name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;My App&quot;</span><span style="color: #339933;">&gt;</span>
        <span style="color: #339933;">&lt;</span>directory<span style="color: #339933;">&gt;./&lt;/</span>directory<span style="color: #339933;">&gt;</span>
    <span style="color: #339933;">&lt;/</span>testsuite<span style="color: #339933;">&gt;</span>
<span style="color: #339933;">&lt;/</span>phpunit<span style="color: #339933;">&gt;</span></pre></div></div>

<p>首先 testsuite 的 name 屬性是讓我們設定 Suite 的名稱，而 directory 標籤則是告訴 phpunit ，這個 Suite 包含了 D:\WEB\zf\unittest\tests 下所有檔名結尾為 Test.php 的測試檔案。</p>
<p>另外還要注意一點，在還沒加入 testsuite 之前，我們要在 D:\WEB\zf\unittest\tests 用 &quot;phpunit .&quot; 來指定目錄執行測試；而加入 testsuite 標籤後，我們就可以直接在 D:\WEB\zf\unittest\tests 執行 phpunit ，而不用再指定測試的路徑了。</p>
<h3>filter</h3>
<p>filter 標籤主要是幫我們過濾程式碼涵蓋範圍報告的項目，避免出現過多不相干類別的報告內容。 filter 分為白名單與黑名單兩種，以下我們以白名單為主：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">&lt;</span>phpunit bootstrap<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;./application/bootstrap.php&quot;</span><span style="color: #339933;">&gt;</span>
    <span style="color: #339933;">&lt;!--</span> 略 <span style="color: #339933;">--&gt;</span>
    <span style="color: #339933;">&lt;</span>filter<span style="color: #339933;">&gt;</span>
        <span style="color: #339933;">&lt;</span>whitelist<span style="color: #339933;">&gt;</span>
            <span style="color: #339933;">&lt;</span>directory suffix<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;.php&quot;</span><span style="color: #339933;">&gt;../</span>application<span style="color: #339933;">/&lt;/</span>directory<span style="color: #339933;">&gt;</span>
            <span style="color: #339933;">&lt;</span>exclude<span style="color: #339933;">&gt;</span>
            	<span style="color: #339933;">&lt;</span>file<span style="color: #339933;">&gt;../</span>application<span style="color: #339933;">/</span>Bootstrap<span style="color: #339933;">.</span>php<span style="color: #339933;">&lt;/</span>file<span style="color: #339933;">&gt;</span>
            	<span style="color: #339933;">&lt;</span>file<span style="color: #339933;">&gt;../</span>application<span style="color: #339933;">/</span>controllers<span style="color: #339933;">/</span>ErrorController<span style="color: #339933;">.</span>php<span style="color: #339933;">&lt;/</span>file<span style="color: #339933;">&gt;</span>
               <span style="color: #339933;">&lt;</span>directory suffix<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;.phtml&quot;</span><span style="color: #339933;">&gt;../</span>application<span style="color: #339933;">/&lt;/</span>directory<span style="color: #339933;">&gt;</span>
            <span style="color: #339933;">&lt;/</span>exclude<span style="color: #339933;">&gt;</span>
        <span style="color: #339933;">&lt;/</span>whitelist<span style="color: #339933;">&gt;</span>
    <span style="color: #339933;">&lt;/</span>filter<span style="color: #339933;">&gt;</span>
<span style="color: #339933;">&lt;/</span>phpunit<span style="color: #339933;">&gt;</span></pre></div></div>

<p>這裡主要是告訴 phpunit 只處理 D:\WEB\zf\unittest\application 下的類別 (注意！不是 tests\application ！) ，但排除掉 D:\WEB\zf\unittest\application\Bootstrap.php 、 D:\WEB\zf\unittest\application\controllers\ErrorController.php 以及 D:\WEB\zf\unittest\application\ 下所有的 .phtml 樣板檔。</p>
<p>不過 filter 通常會搭配稍後要說明的 logging 標籤一起使用。</p>
<h3>logging</h3>
<p>logging 標籤主要用來產生測試報告，它支援相當多的格式，以下我們以 HTML 格式為主：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">&lt;</span>phpunit bootstrap<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;./application/bootstrap.php&quot;</span><span style="color: #339933;">&gt;</span>
    <span style="color: #339933;">&lt;!--</span> 略 <span style="color: #339933;">--&gt;</span>
    <span style="color: #339933;">&lt;</span>logging<span style="color: #339933;">&gt;</span>
        <span style="color: #339933;">&lt;</span>log type<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;coverage-html&quot;</span> target<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;./log/report&quot;</span> charset<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;UTF-8&quot;</span>
            yui<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;true&quot;</span> highlight<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;true&quot;</span> lowUpperBound<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;50&quot;</span> highLowerBound<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;80&quot;</span><span style="color: #339933;">/&gt;</span>
        <span style="color: #339933;">&lt;</span>log type<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;testdox-html&quot;</span> target<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;./log/testdox.html&quot;</span> <span style="color: #339933;">/&gt;</span>
    <span style="color: #339933;">&lt;/</span>logging<span style="color: #339933;">&gt;</span>
<span style="color: #339933;">&lt;/</span>phpunit<span style="color: #339933;">&gt;</span></pre></div></div>

<p>在執行測試前，別忘了在 D:\WEB\zf\unittest\tests 下建立一個 log 目錄，避免 phpunit 回報錯誤。執行完測試後，就會在 D:\WEB\zf\unittest\tests\log 產生一個 testdox.html 檔案及一個 report 資料夾。</p>
<p>textdox.html 會以我們在測試類別裡寫的測試案例為名稱來做為驗證項目名稱，例如 testDoSomething 就會變成 Do something 。而用瀏覽器開啟 report/index.html 後，我們就能看到完整的程式碼覆蓋率報告。</p>
<h2>小結</h2>
<p>最後我們再整理一下重點：</p>
<ul>
<li>
<p>我們可以在專案中建立一個 tests 目錄，供我們放置測試類別。</p>
</li>
<li>
<p>PHPUnit 可以透過 phpunit.xml 及 bootstrap.php 來做自動化的測試環境。</p>
</li>
<li>
<p>phpunit.xml 主要是用來設定 phpunit 執行時的選項。</p>
</li>
<li>
<p>bootstrap.php 主要的工作是設定測試時會用到的環境常數、引入路徑以及類別自動載入機制等。</p>
</li>
<li>
<p>NetBeans 對 PHPUnit 有強大的支援，不論在建立測試及執行測試上，都非常直覺。</p>
</li>
<li>
<p>即便不使用 NetBeans ，我們還是可以透過 phpunit 這個 CLI 工具來完成自動化測試。</p>
</li>
</ul>
<p>雖然這裡我是以 Zend Framework 專案為主，但大家還是可以仿照這樣的機制，在自己的專案裡去建構自動化測試。</p>
<p>還猶豫什麼？快去試試吧！</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.wabow.com/archives/2345/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>關於測試這件事</title>
		<link>http://blog.wabow.com/archives/2342</link>
		<comments>http://blog.wabow.com/archives/2342#comments</comments>
		<pubDate>Fri, 14 May 2010 10:37:43 +0000</pubDate>
		<dc:creator>jaceju</dc:creator>
				<category><![CDATA[工作雜談]]></category>

		<guid isPermaLink="false">http://blog.wabow.com/?p=2342</guid>
		<description><![CDATA[轉自：關於測試這件事 為什麼要測試？ 因為我們沒辦法保證程式碼是萬無一失的，所以通常我們都會需要驗證我們的程式，而測試就是其中一種方法。很多工程師都在寫完程式之後，自己手動去做測試；如果執行結果是按照自己的想法出現後，那麼他們通常就認為程式沒錯了。 可是，其實這樣的程式碼通常就會躲進很多很多的 Bug 。所以我們要讓程式碼自己告訴我們它沒問題，而不是我們自己去想像它沒問題。 當然測試並不是萬靈丹，它只是去驗證我們所考慮到的狀況；但如果抱持著「既然我都有考慮到，而且也寫在程式碼裡，那這樣就不用測試了呀！」的態度，那其實也是災難的根源。因為如果我們沒有寫測試來驗證程式碼的話，那我們的防範措施根本就不值得信賴！ 所以不是手動測試過沒問題，下次就不會再發生了；而是要拿出保證來才值得相信，而測試就是我們的保證。 如何確保系統照著規格實作？ 符合客戶所要求的規格，就是我們實作系統的最終目標。有些規格是流程的控制，有些規格是資料的處理；但這些如果沒有一套好的檢驗機制來協助我們確認這些規格的話，我們就沒辦法有百分之百的信心告訴客戶說，我們的程式完成了你們的需求。 自動化測試就是一個方便的檢驗機制，而測試案例就是客戶的規格。當我們的程式按通過測試後，我們也就可以放心把這些程式碼用在實際的開發中；如果這時還發現執行的結果有問題的話，通常就就可以判斷是實際開發的程式碼中出現了錯誤。 當然有些工程師會認為：為什麼我要把同樣的程式碼在測試案例和實作運作的系統中各寫一遍？其實這是錯誤的觀念。 測試案例分成兩種：一種是在程式正常運作下的案例，它們能明確告訴我們程式的使用方式，也就是客戶要求的規格；一種是設想到可能會讓程式出現問題的案例，它們考驗著身為工程師應該去設想到的錯誤處理機制。 當客戶新增或修改了規格時，那麼我們的測試案例就要跟著調整。而沒有調整的部份，我們就能透過現有的測試案例來確保舊有程式按照舊的規格執行，確保我們的程式沒有因為新增或修改的功能而出現預料之外的錯誤。 怎麼寫出好測試？ 好的測試案例依賴著工程師的經驗，經驗越豐富的工程師，就能預想到各種可能發生的狀況，並寫出因應的測試案例。不過有經驗的工程師畢竟是少數，所以大多數時候我們還是要按步就班，從我們能做得到的部份做起。 一開始我們可以先對正常的流程編寫測試；而在程式通過正常測試之後，我們再針對有可能造成我們程式誤動作的狀況去加入異常的測試。有時候 Bug 可能是因為操作流程錯誤而產生，那麼就要在流程中的每個關卡做好程序的把關。 例如某些關卡要有防呆機制，某些關卡不能重覆執行，我們就必須去防止等等。測試之所以要強調自動化，就是讓我們不用把時間花在手動去模擬使用者操作的過程；而且我們可以透過對調測試案例裡的每個觸發條件的執行順序來產生不同的測試方式，以找出可能潛藏的流程問題。 有時候我們的系統可能會有多個使用者同時在操作，如何讓獨立性的資料不互相干擾，或是避免資料更新的先後順序問題 (例如商品庫存) ，這都是好的測試應該注意的重點。 重要的是，每個測試案例是要有意義的，我們在撰寫測試之前就要先分析它們的前因後果，才能擬定出正確的測試方向。如果覺得自己寫的流程測試可能有盲點時，那麼也可以請伙伴幫我們一起思考可能的狀況。 測試太花時間？ 在很多 Web 系統開發的過程中，其實很少有人會去考慮測試這件事情；主要是因為 Web 系統中大部份只是簡單的 CRUD 而已，加上時程的壓力，就會讓很多開發人員放棄撰寫自動化測試。 不過在一個較具規模的系統的規劃與設計過程中，就應該將自動化測試考慮進來；而且即便有時程壓力，也應該對核心功能撰寫測試案例。尤其當核心功能牽扯到有關金流等不容有錯的部份時，更是應該用測試來嚴格把關。 更好的方式是將撰寫測試的時間在一開始就放到時程規劃裡，其他的就讓專案經理去傷腦筋，即便是在維護階段時也是如此。因為如果多花半個小時寫自動化測試的話，那麼未來找 Bug 的時間就至少可以減掉半天。 既有的程式該如何測試？ 如果大部份已經在運作的程式沒有對應的自動化測試，而在它們發生問題就要花很多時間來除錯時，就應該考慮安排時間進行重構與撰寫測試。 首先在第一次重構時，可以先考慮把核心邏輯獨立出來；如果這個動作在執行上相當困難的話，那麼就先將資料或網路存取的部份獨立出來。這些外在因素我們可以透過 Dependency Injection 的方式來重構，然後在自動化測試時用 Stub 物件來代替它們。 當程式重構至無關外在變因，且手動測試通過後，就可以開始考慮撰寫自動化測試；這時還是要按照先測正常流程，再測異常流程的步驟來進行。而其中測試用的假資料可以從現有的資料中產生，這些資料因為已經透過客戶的驗證，更能確保測試的可靠性。 另外有些既有的錯誤是必須在長時間才能發現，這時候我們可能就要用推測的方式來撰寫測試案例。這樣一來有兩個好處，其一是我們就可以讓測試自動化去代替手動測試的部份，其二是如果未來還是發生同樣問題時，我們也能透過這些測試來排除掉先前推測出來的因素。 結論 其實我們也很難百分之百地保證通過測試的程式碼一定完全沒問題，但很重要的一點就是我們至少能保證通過測試的部份是會按照我們的想法來執行。 一個好的系統在交到客戶手上時，就應該要有一定的品質；而品質的保證來自我們的信心。至於我們的信心並不是建構在想像之上，而是應該用實際的測試數據來做為它的基礎。]]></description>
			<content:encoded><![CDATA[<p>轉自：<a href="http://www.jaceju.net/blog/?p=1142">關於測試這件事</a></p>
<h2>為什麼要測試？</h2>
<p>因為我們沒辦法保證程式碼是萬無一失的，所以通常我們都會需要驗證我們的程式，而測試就是其中一種方法。很多工程師都在寫完程式之後，自己手動去做測試；如果執行結果是按照自己的想法出現後，那麼他們通常就認為程式沒錯了。</p>
<p>可是，其實這樣的程式碼通常就會躲進很多很多的 Bug 。所以我們要<strong>讓程式碼自己告訴我們它沒問題，而不是我們自己去想像它沒問題</strong>。</p>
<p><span id="more-2342"></span></p>
<p>當然測試並不是萬靈丹，它只是去驗證我們所考慮到的狀況；但如果抱持著「既然我都有考慮到，而且也寫在程式碼裡，那這樣就不用測試了呀！」的態度，那其實也是災難的根源。<strong>因為如果我們沒有寫測試來驗證程式碼的話，那我們的防範措施根本就不值得信賴！</strong></p>
<p>所以不是手動測試過沒問題，下次就不會再發生了；而是要拿出保證來才值得相信，而測試就是我們的保證。</p>
<h2>如何確保系統照著規格實作？</h2>
<p>符合客戶所要求的規格，就是我們實作系統的最終目標。有些規格是流程的控制，有些規格是資料的處理；但這些如果沒有一套好的檢驗機制來協助我們確認這些規格的話，我們就沒辦法有百分之百的信心告訴客戶說，我們的程式完成了你們的需求。</p>
<p>自動化測試就是一個方便的檢驗機制，而測試案例就是客戶的規格。當我們的程式按通過測試後，我們也就可以放心把這些程式碼用在實際的開發中；如果這時還發現執行的結果有問題的話，通常就就可以判斷是實際開發的程式碼中出現了錯誤。</p>
<p>當然有些工程師會認為：為什麼我要把同樣的程式碼在測試案例和實作運作的系統中各寫一遍？其實這是錯誤的觀念。</p>
<p>測試案例分成兩種：一種是在程式正常運作下的案例，它們能明確告訴我們程式的使用方式，也就是客戶要求的規格；一種是設想到可能會讓程式出現問題的案例，它們考驗著身為工程師應該去設想到的錯誤處理機制。</p>
<p>當客戶新增或修改了規格時，那麼我們的測試案例就要跟著調整。<strong>而沒有調整的部份，我們就能透過現有的測試案例來確保舊有程式按照舊的規格執行，確保我們的程式沒有因為新增或修改的功能而出現預料之外的錯誤。</strong></p>
<h2>怎麼寫出好測試？</h2>
<p>好的測試案例依賴著工程師的經驗，經驗越豐富的工程師，就能預想到各種可能發生的狀況，並寫出因應的測試案例。不過有經驗的工程師畢竟是少數，所以大多數時候我們還是要按步就班，從我們能做得到的部份做起。</p>
<p>一開始我們可以先對正常的流程編寫測試；而在程式通過正常測試之後，我們再針對有可能造成我們程式誤動作的狀況去加入異常的測試。有時候 Bug 可能是因為操作流程錯誤而產生，那麼就要在流程中的每個關卡做好程序的把關。</p>
<p>例如某些關卡要有防呆機制，某些關卡不能重覆執行，我們就必須去防止等等。測試之所以要強調自動化，就是讓我們不用把時間花在手動去模擬使用者操作的過程；而且我們可以透過對調測試案例裡的每個觸發條件的執行順序來產生不同的測試方式，以找出可能潛藏的流程問題。</p>
<p>有時候我們的系統可能會有多個使用者同時在操作，如何讓獨立性的資料不互相干擾，或是避免資料更新的先後順序問題 (例如商品庫存) ，這都是好的測試應該注意的重點。</p>
<p>重要的是，每個測試案例是要有意義的，我們在撰寫測試之前就要先分析它們的前因後果，才能擬定出正確的測試方向。如果覺得自己寫的流程測試可能有盲點時，那麼也可以請伙伴幫我們一起思考可能的狀況。</p>
<h2>測試太花時間？</h2>
<p>在很多 Web 系統開發的過程中，其實很少有人會去考慮測試這件事情；主要是因為 Web 系統中大部份只是簡單的 CRUD 而已，加上時程的壓力，就會讓很多開發人員放棄撰寫自動化測試。</p>
<p>不過在一個較具規模的系統的規劃與設計過程中，就應該將自動化測試考慮進來；而且<strong>即便有時程壓力，也應該對核心功能撰寫測試案例。</strong>尤其當核心功能牽扯到有關金流等不容有錯的部份時，更是應該用測試來嚴格把關。</p>
<p>更好的方式是將撰寫測試的時間在一開始就放到時程規劃裡，其他的就讓專案經理去傷腦筋，即便是在維護階段時也是如此。<strong>因為如果多花半個小時寫自動化測試的話，那麼未來找 Bug 的時間就至少可以減掉半天。</strong></p>
<h2>既有的程式該如何測試？</h2>
<p>如果大部份已經在運作的程式沒有對應的自動化測試，而在它們發生問題就要花很多時間來除錯時，就應該考慮安排時間進行重構與撰寫測試。</p>
<p>首先在第一次重構時，可以先考慮把核心邏輯獨立出來；如果這個動作在執行上相當困難的話，那麼就先將資料或網路存取的部份獨立出來。這些外在因素我們可以透過 Dependency Injection 的方式來重構，然後在自動化測試時用 Stub 物件來代替它們。</p>
<p>當程式重構至無關外在變因，且手動測試通過後，就可以開始考慮撰寫自動化測試；這時還是要按照先測正常流程，再測異常流程的步驟來進行。而其中測試用的假資料可以從現有的資料中產生，這些資料因為已經透過客戶的驗證，更能確保測試的可靠性。</p>
<p>另外有些既有的錯誤是必須在長時間才能發現，這時候我們可能就要用推測的方式來撰寫測試案例。這樣一來有兩個好處，其一是我們就可以讓測試自動化去代替手動測試的部份，其二是如果未來還是發生同樣問題時，我們也能透過這些測試來排除掉先前推測出來的因素。</p>
<h2>結論</h2>
<p>其實我們也很難百分之百地保證通過測試的程式碼一定完全沒問題，但很重要的一點就是我們至少能<strong>保證</strong>通過測試的部份是會按照我們的想法來執行。</p>
<p>一個好的系統在交到客戶手上時，就應該要有一定的品質；而品質的保證來自我們的信心。至於我們的信心並不是建構在想像之上，而是應該用實際的測試數據來做為它的基礎。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.wabow.com/archives/2342/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>2010 亞太資安論壇心得筆記</title>
		<link>http://blog.wabow.com/archives/2339</link>
		<comments>http://blog.wabow.com/archives/2339#comments</comments>
		<pubDate>Fri, 23 Apr 2010 01:55:47 +0000</pubDate>
		<dc:creator>jaceju</dc:creator>
				<category><![CDATA[工作雜談]]></category>

		<guid isPermaLink="false">http://blog.wabow.com/?p=2339</guid>
		<description><![CDATA[轉自：2010 亞太資安論壇心得筆記 這次臨時去亞太資安論壇，主要是因為 Darkhero 的介紹，且主題剛好是我有興趣的網頁安全；所以就拜託了 Neo 老大讓我去聽課囉。 聽了一整天下來，很多都是廠商在介紹產品，觀念部份反而都是老調重彈 (但實作技術上都比以前進步很多) 。 不過阿碼科技的場次倒是讓我非常驚豔！主要是他們本身在這個業界就非常有名，而且這次分享的內容偏向技術面，讓我非常有認同感。 這次阿碼科技的分享主要內容是「網頁掛馬」，以下我就簡單分享這次的筆記與心得。 Malware 是什麼？ 其實就是用來控制被攻擊電腦的惡意軟體，像是不必經過使用者允許就能遠端連線的桌面控制工具。 而常看到的透過 Script 或 Iframe 標籤所連結的 JavaScript ，其實只是用來下載 Malware 的工具程式。 網頁掛馬的途徑 網頁掛馬的方式分成三種途徑： Web 一般常見的就是透過後端技術 (例如 ASP 、 PHP 、 JSP 等等) ，然後使用 SQL Injection 等常見的 Web 攻擊手法，把木馬掛到 Web 應用程式當中。 LAN 利用使用者操作上的疏忽，感染他們的電腦，再透過區域網路的 ARP 封包來對主機做掛馬的動作。常見的工具有 zxarps.exe ，它可以對區網內的使用者所訪問的所有網站插入惡意的 HTML 碼，例如 iframe 。 WAN 部份非知名品牌的網路設備 [...]]]></description>
			<content:encoded><![CDATA[<p>轉自：<a href="http://www.jaceju.net/blog/?p=1111">2010 亞太資安論壇心得筆記</a></p>
<p>這次臨時去亞太資安論壇，主要是因為 <a href="http://blog.darkhero.net/">Darkhero</a> 的介紹，且主題剛好是我有興趣的網頁安全；所以就拜託了 Neo 老大讓我去聽課囉。</p>
<p>聽了一整天下來，很多都是廠商在介紹產品，觀念部份反而都是老調重彈 (但實作技術上都比以前進步很多) 。</p>
<p class="image"><img src="http://farm3.static.flickr.com/2690/4542595099_28ca7de4a4.jpg" alt="阿碼科技創辦人" /></p>
<p>不過<a href="http://www.armorize.com/" target="_blank">阿碼科技</a>的場次倒是讓我非常驚豔！主要是他們本身在這個業界就非常有名，而且這次分享的內容偏向技術面，讓我非常有認同感。</p>
<p>這次阿碼科技的分享主要內容是「網頁掛馬」，以下我就簡單分享這次的筆記與心得。</p>
<p><span id="more-2339"></span></p>
<h2>Malware 是什麼？</h2>
<p>其實就是用來控制被攻擊電腦的惡意軟體，像是不必經過使用者允許就能遠端連線的桌面控制工具。</p>
<p>而常看到的透過 Script 或 Iframe 標籤所連結的 JavaScript ，其實只是用來下載 Malware 的工具程式。</p>
<h2>網頁掛馬的途徑</h2>
<p><a href="http://tw.trendmicro.com/tw/threats/home-user/common-threats/web-threat/" target="_blank">網頁掛馬</a>的方式分成三種途徑：</p>
<h3>Web</h3>
<p>一般常見的就是透過後端技術 (例如 ASP 、 PHP 、 JSP 等等) ，然後使用 SQL Injection 等常見的 Web 攻擊手法，把木馬掛到 Web 應用程式當中。</p>
<h3>LAN</h3>
<p>利用使用者操作上的疏忽，感染他們的電腦，再透過區域網路的 ARP 封包來對主機做掛馬的動作。常見的工具有 <a href="http://www.yanghengfei.com/show-162-1.html" target="_blank">zxarps.exe</a> ，它可以對區網內的使用者所訪問的所有網站插入惡意的 HTML 碼，例如 iframe 。</p>
<h3>WAN</h3>
<p>部份非知名品牌的網路設備 (例如 Layer 4 / Layer 7 switch) 存在著漏洞，駭客就利用它來讓連線的用戶被導向惡意的網站。</p>
<h2>Malzilla 解掛碼工具</h2>
<p>阿碼科技提供了以下測試用的掛碼網址：</p>
<ul>
<li>http://zcrack.org/a</li>
<li>http://zcrack.org/cookie</li>
</ul>
<p>然後透過 <a href="http://malzilla.sourceforge.net/" target="_blank">Malzilla</a> 來就可以攔截到 http://zcrack.org/a 的原始 HTML 碼：</p>

<div class="wp_syntax"><div class="code"><pre class="html4strict" style="font-family:monospace;"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">html</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">head</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">META</span> <span style="color: #000066;">NAME</span> <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;ROBOTS&quot;</span> <span style="color: #000066;">CONTENT</span> <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;NOARCHIVE&quot;</span> &gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">META</span> <span style="color: #000066;">NAME</span> <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;ROBOTS&quot;</span> <span style="color: #000066;">CONTENT</span> <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;NOINDEX&quot;</span> &gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">META</span> <span style="color: #000066;">NAME</span> <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;ROBOTS&quot;</span> <span style="color: #000066;">CONTENT</span> <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;NONE&quot;</span> &gt;</span>
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">head</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">body</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;imgs&quot;</span>&gt;</span> <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">script</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'go.jpg'</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;&lt;<span style="color: #000000; font-weight: bold;">script</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'2.jpg'</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;&lt;<span style="color: #000000; font-weight: bold;">script</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'3.jpg'</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;&lt;<span style="color: #000000; font-weight: bold;">script</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'4.jpg'</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;&lt;<span style="color: #000000; font-weight: bold;">script</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'5.jpg'</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;&lt;<span style="color: #000000; font-weight: bold;">script</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'5.1.jpg'</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;&lt;<span style="color: #000000; font-weight: bold;">script</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'6.jpg'</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;&lt;<span style="color: #000000; font-weight: bold;">script</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'7.jpg'</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;&lt;<span style="color: #000000; font-weight: bold;">script</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'8.jpg'</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">body</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">html</span>&gt;</span></pre></div></div>

<p>主要可以看到木馬透過多個 &lt;script&gt; 標籤去組合，這會讓 Sever 端的防毒很難偵測出它的存在。</p>
<p>而這些 JavaScript 就會動態組合出所謂的 Exploits (或稱為 Dropper 及 Downloader )，讓特定的瀏覽器執行後去下載真正的惡意程式 (Malware) 。</p>
<p>因為這些 Exploits 是動態組合，所以不容易被偵測出來，因此要借重一些工具來找出真正的 JavaScript 。</p>
<p><a href="http://portswigger.net/proxy/" target="_blank">Burp Suite</a> 可以幫我們攔截網頁 HTML ，然後進行適當的修改 (例如把 JavaScript 的 eval 改為 alert ) ，讓我們能看到真正會被執行的 JavaScript 長什麼樣子。</p>
<h2>圖解掛馬流程</h2>
<p>一般掛碼分為三個步驟：</p>
<p class="image"><img src="http://www.jaceju.net/resources/2010_secutech_armorize/01.png" alt="掛馬流程" /></p>
<ol>
<li>
<p> Cracker 想辦法攻擊某些網站的漏洞 (就是上面提到的三種途徑) ，並把 Url Generator 放到它們上面；通常流量較大的知名網站越容易成為被攻擊目標。</p>
</li>
<li>
<p>使用者去瀏覽這些被攻擊的網站的頁面時，就會被導向置有惡意 JavaScript Exploits 的網站。</p>
</li>
<li>
<p>當下載回來的 JavaScript Exploits 被特定瀏覽器執行時 (例如 IE6 ) ，就會再次連到另一個真正存放惡意軟體的網站將該惡意軟體下載回來執行。</p>
</li>
</ol>
<p>偵測的難度如下圖所示：</p>
<p class="image"><img src="http://www.jaceju.net/resources/2010_secutech_armorize/02.png" alt="偵測難度" /></p>
<p>因為 JavaScript 可以透過 JavaScript 來產生新的 JavaScript ，使得 Url Generator 及 Exploits 很容易變形，增加了偵測的難度。</p>
<h2>Exploits 難以偵測的原因</h2>
<ul>
<li>
<p>目前的 Exploites 都做了模組化，不同的瀏覽器有不同的掛馬方式。</p>
</li>
<li>
<p>如果 Exploites 透過 Browser Agent 的方式識別瀏覽器的話，很容易被資安廠商透過更改 Agent 的方式偵測到。所以目前的 Exploits 大多都是透過瀏覽器支援的特性來識別瀏覽器，這樣就更能精準確認使用者的瀏覽器，避免被資安廠商的自動檢測掛馬程式給偵測出來。</p>
</li>
<li>
<p>Exploites 也會先行利用偵測到的瀏覽器特性為 Key 來對自己的程式碼進行編碼，這樣就更能增加自動檢測掛馬程式的偵測難度。</p>
</li>
</ul>
<h2>Cracker 掛馬的難度</h2>
<ul>
<li>
<p>要讓被攻擊網站的安全檢測工具都檢查不出來。</p>
</li>
<li>
<p>在網路上的任何節點也不能被偵測到。</p>
</li>
<li>
<p>要隨時注意瀏覽器的漏洞。</p>
</li>
<li>
<p>必須知道資安廠商的 IP ，避免自己的網站被列入黑名單。</p>
</li>
</ul>
<h2>資安廠商因應的對策</h2>
<ul>
<li>
<p>Web Application Firewall</p>
</li>
<li>使用白名單網址，判斷 Script 的來源是否合法。</li>
</ul>
<h2>心得</h2>
<p>其實以前也研究過有關 IIS 與 ASP 的資安議題，也在實際上線的網站上被 Cracker 攻擊過，那時就覺得網站安全是一門很深的學問。</p>
<p>今天又在阿碼科技的 CTO 口中，瞭解了這些相當紮實且淺顯易懂的觀念，真是此行最大的收穫！</p>
<p>資安的世界真是複雜又有趣呀~</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.wabow.com/archives/2339/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>i&#039;m mark 進駐 MADE IN LUKA 手創館</title>
		<link>http://blog.wabow.com/archives/2324</link>
		<comments>http://blog.wabow.com/archives/2324#comments</comments>
		<pubDate>Sun, 04 Apr 2010 17:03:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[客戶紀事]]></category>

		<guid isPermaLink="false">http://blog.wabow.com/?p=2324</guid>
		<description><![CDATA[MADE IN LUKA 手創館自去年度就陸續協助本土設計師發展自己的創意品牌商品，這次超人氣職場部落客 i'm mark 也進駐賣起衣服跟馬克杯了。 現在買衣服還有送 i'm mark 紙喇叭喔。 雖然現在商品還不多，有興趣的話快到 MADE IN LUKA 的 i'm mark 專區看看吧: http://www.madeinluka.com.tw/category/313]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.madeinluka.com.tw/category/313" target="_blank"><img class="alignnone size-large wp-image-2325" title="immark1" src="http://blog.wabow.com/wp-content/uploads/2010/04/immark1-500x420.jpg" alt="" width="500" height="420" /></a></p>
<p><a href="http://www.madeinluka.com.tw/" target="_blank">MADE IN LUKA</a> 手創館自去年度就陸續協助本土設計師發展自己的創意品牌商品，這次超人氣職場部落客 <a href="http://www.wretch.cc/blog/markleeblog" target="_blank">i'm mark</a> 也進駐賣起衣服跟馬克杯了。</p>
<p><span id="more-2324"></span><a href="http://www.madeinluka.com.tw/product/6002" target="_blank"><img class="alignnone size-large wp-image-2326" title="immark6" src="http://blog.wabow.com/wp-content/uploads/2010/04/immark6-500x392.jpg" alt="" width="500" height="392" /></a></p>
<p>現在買衣服還有送 i'm mark 紙喇叭喔。<br />
<a href="http://blog.wabow.com/wp-content/uploads/2010/04/immark4.jpg"><img class="alignnone size-full wp-image-2329" title="immark4" src="http://blog.wabow.com/wp-content/uploads/2010/04/immark4.jpg" alt="" width="400" height="400" /></a></p>
<p>雖然現在商品還不多，有興趣的話快到 MADE IN LUKA 的 i'm mark 專區看看吧:<br />
<a href="http://www.madeinluka.com.tw/category/313" target="_blank">http://www.madeinluka.com.tw/category/313</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.wabow.com/archives/2324/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>宅男女神「豆花妹」現身天母嚴選</title>
		<link>http://blog.wabow.com/archives/2305</link>
		<comments>http://blog.wabow.com/archives/2305#comments</comments>
		<pubDate>Thu, 01 Apr 2010 12:04:19 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[客戶紀事]]></category>

		<guid isPermaLink="false">http://blog.wabow.com/?p=2305</guid>
		<description><![CDATA[宅男們心目中的女神現身在我們的客戶 天母嚴選 的 Gotobuy 網站中了，豆花妹親身示各種不同穿搭風格。 想跟豆花妹穿的一樣甜美可愛嗎? 到天母嚴選 Gotobuy 來看看吧: ^^ http://www.gotobuy.com.tw/templates/gotobuy/edm/100301-EDM/100301-EDM.html]]></description>
			<content:encoded><![CDATA[<p>宅男們心目中的女神現身在我們的客戶 天母嚴選 的 Gotobuy 網站中了，豆花妹親身示各種不同穿搭風格。</p>
<p><a href="http://blog.wabow.com/wp-content/uploads/2010/04/do2.jpg"><img class="alignnone size-full wp-image-2308" title="do2" src="http://blog.wabow.com/wp-content/uploads/2010/04/do2.jpg" alt="" width="550" height="400" /></a><span id="more-2305"></span></p>
<p><a href="http://blog.wabow.com/wp-content/uploads/2010/04/do3.jpg"><img class="alignnone size-full wp-image-2309" title="do3" src="http://blog.wabow.com/wp-content/uploads/2010/04/do3.jpg" alt="" width="550" height="400" /></a></p>
<p><a href="http://blog.wabow.com/wp-content/uploads/2010/04/do4.jpg"><img class="alignnone size-full wp-image-2309" title="do3" src="http://blog.wabow.com/wp-content/uploads/2010/04/do4.jpg" alt="" width="550" height="400" /></a></p>
<p><a href="http://blog.wabow.com/wp-content/uploads/2010/04/do5.jpg"><img class="alignnone size-full wp-image-2309" title="do3" src="http://blog.wabow.com/wp-content/uploads/2010/04/do5.jpg" alt="" width="550" height="400" /></a></p>
<p><a href="http://blog.wabow.com/wp-content/uploads/2010/04/do6.jpg"><img class="alignnone size-full wp-image-2309" title="do6" src="http://blog.wabow.com/wp-content/uploads/2010/04/do3.jpg" alt="" width="550" height="400" /></a></p>
<p><a href="http://blog.wabow.com/wp-content/uploads/2010/04/do7.jpg"></a></p>
<p>想跟豆花妹穿的一樣甜美可愛嗎? 到天母嚴選 Gotobuy 來看看吧: ^^<br />
<a href="http://www.gotobuy.com.tw/templates/gotobuy/edm/100301-EDM/100301-EDM.html">http://www.gotobuy.com.tw/templates/gotobuy/edm/100301-EDM/100301-EDM.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.wabow.com/archives/2305/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHPUnit 實務入門簡介</title>
		<link>http://blog.wabow.com/archives/2299</link>
		<comments>http://blog.wabow.com/archives/2299#comments</comments>
		<pubDate>Tue, 16 Mar 2010 13:28:53 +0000</pubDate>
		<dc:creator>jaceju</dc:creator>
				<category><![CDATA[技術分享]]></category>
		<category><![CDATA[軟體測試]]></category>

		<guid isPermaLink="false">http://blog.wabow.com/?p=2299</guid>
		<description><![CDATA[這幾天在寫折價券攤提到商品的數學演算法邏輯，搞得我七葷八素的...還好先前在製作購物車時，已經把單元測試放到架構裡，因此後面就只要專心應付演算法邏輯就好了。 雖然這樣的規劃聽起來不錯，但單元測試這件事說到底我的實務經驗還是太少，在這次的專案項目裡，才讓我真正有了較為深入的體會。 先對要測試的事情有一個概觀 其實測試一開始真的很難下手，主要是因為我們不知道我們要測些什麼東西。因此，我們需要對需要測試的東西有個概觀。 就以這次的例子來說吧，我要測試的東西就是「折價券攤提的演算法邏輯」，那它裡面重要的東西是什麼？ 在跟客戶討論，我們得知折價券面額要分攤到的商品上時有一定的規則；這時我們就要先在紙上作業，用簡單的例子跟客戶確認清楚規則。 確認了方向之後，因為我之前已經測試架構準備好了，所以接下來就只要針對要測試的部份撰寫程式碼即可。但如果一開始還沒有準備好測試架構的話，這裡給大家幾個建置環境的簡易流程： 在專案裡開個 tests 資料夾，這裡就是放置測試案例的地方。 準備一個 init.php ，目的是用來設置 include_path 及 autoload 機制。 按照 PHPUnit 官方的建議，建立一個 AllTests.php 的 Test Suite 。 註：這裡我就不列出程式碼了，讓大家自己試試看。 然後每次測試就用以下指令即可： &#62; phpunit AllTests.php 之後我會以「跑測試」來表示執行這個指令。 描繪程式的輪廓 接下來我們就要把整個系統的測試架構定義出來，不過這時候其實我們還沒開始寫程式，只是把流程和相關的方法先定義出來。 這裡的方法很簡單，就是先透過註解和方法介面來描述整個流程，而不是先寫細部的程式碼。 class Shop_Cart_Plugin_Coupon extends Shop_Cart_Plugin &#123; // ... 略 ... &#160; // 演算法計算後的結果 protected $_sharedCouponData = array&#40;&#41;; &#160; // 取得演算法計算後的結果，也可供測試來驗證 public functino [...]]]></description>
			<content:encoded><![CDATA[<p>這幾天在寫折價券攤提到商品的數學演算法邏輯，搞得我七葷八素的...還好先前在製作購物車時，已經把單元測試放到架構裡，因此後面就只要專心應付演算法邏輯就好了。</p>
<p>雖然這樣的規劃聽起來不錯，但單元測試這件事說到底我的實務經驗還是太少，在這次的專案項目裡，才讓我真正有了較為深入的體會。</p>
<p><span id="more-2299"></span></p>
<h2>先對要測試的事情有一個概觀</h2>
<p>其實測試一開始真的很難下手，主要是因為我們不知道我們要測些什麼東西。因此，我們需要對需要測試的東西有個概觀。</p>
<p>就以這次的例子來說吧，我要測試的東西就是「折價券攤提的演算法邏輯」，那它裡面重要的東西是什麼？</p>
<p>在跟客戶討論，我們得知折價券面額要分攤到的商品上時有一定的規則；這時我們就要先在紙上作業，用簡單的例子跟客戶確認清楚規則。</p>
<p class="image"><a href="http://www.jaceju.net/resources/phpunit/draft.jpg"><img src="http://www.jaceju.net/resources/phpunit/draft.jpg" alt="草圖" /></a></p>
<p>確認了方向之後，因為我之前已經測試架構準備好了，所以接下來就只要針對要測試的部份撰寫程式碼即可。但如果一開始還沒有準備好測試架構的話，這裡給大家幾個建置環境的簡易流程：</p>
<ol>
<li>
<p> 在專案裡開個 tests 資料夾，這裡就是放置測試案例的地方。</p>
</li>
<li>
<p> 準備一個 init.php ，目的是用來設置 include_path 及 autoload 機制。</p>
</li>
<li>
<p> 按照 PHPUnit 官方的建議，建立一個 AllTests.php 的 Test Suite 。</p>
</li>
</ol>
<p class="note">註：這裡我就不列出程式碼了，讓大家自己試試看。</p>
<p>然後每次測試就用以下指令即可：</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">&gt; phpunit AllTests.php</pre></div></div>

<p>之後我會以「跑測試」來表示執行這個指令。</p>
<h2>描繪程式的輪廓</h2>
<p>接下來我們就要把整個系統的測試架構定義出來，不過這時候其實我們還沒開始寫程式，只是把流程和相關的方法先定義出來。</p>
<p>這裡的方法很簡單，就是先透過註解和方法介面來描述整個流程，而不是先寫細部的程式碼。</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Shop_Cart_Plugin_Coupon <span style="color: #000000; font-weight: bold;">extends</span> Shop_Cart_Plugin
<span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// ... 略 ...</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// 演算法計算後的結果</span>
    protected <span style="color: #000088;">$_sharedCouponData</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// 取得演算法計算後的結果，也可供測試來驗證</span>
    <span style="color: #000000; font-weight: bold;">public</span> functino getSharedCouponData<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> 
    <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_sharedCouponData<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// 主要的執行方法</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> doCheckout<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_getCouponData<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// 取得</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_getProductData<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// 取得商品資料</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_initData<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// 初始化要攤提的資料</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_shareCouponToProduct<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// 開始攤提</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// ... 略 ...</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>當然這些都是大概的輪廓，因為可能在我們寫好測試執行時，會再額外加入新的方法及介面。</p>
<p>還有一個要先定義好的是測試用的比對數據格式，它對我們稍後要測試的程式寫法會有影響。</p>
<h2>寫第一個測試</h2>
<p>到這裡，我們就可以開始寫第一個測試，而接下來的程式碼，都是先以這個測試可以成功為目的。而這個測試要怎麼寫呢？就是把一開始我們在紙上作業的數字拿進來套用。</p>
<p>當然這裡我的 setUp 和 tearDown 也已經在之前準備測試架構時寫好了，它們會讓我們每次的測試數據都能夠獨立。我們關心的就是第一個測試案例：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000000; font-weight: bold;">class</span> Shop_Cart_Plugin_CouponTest <span style="color: #000000; font-weight: bold;">extends</span> PHPUnit_Framework_TestCase
<span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// ... 略 ...</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> setUp<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// ... 略 ...</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> tearDown<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// ... 略 ...</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> testDoCheckout<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_plugin<span style="color: #339933;">-&gt;</span><span style="color: #004000;">setValue</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
           <span style="color: #cc66cc;">1</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">// C1, ProductCoupon for P1, $100</span>
           <span style="color: #cc66cc;">2</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">2</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">// C2, ProductCoupon for P1, P2, $100</span>
        <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_cart<span style="color: #339933;">-&gt;</span><span style="color: #004000;">addItems</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
            <span style="color: #0000ff;">'P1'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">// $200</span>
            <span style="color: #0000ff;">'P2'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">// $300</span>
        <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">refresh</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">assertEquals</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">300</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_cart<span style="color: #339933;">-&gt;</span><span style="color: #004000;">getTotal</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_plugin<span style="color: #339933;">-&gt;</span><span style="color: #004000;">doCheckout</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$resultDataList</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_plugin<span style="color: #339933;">-&gt;</span><span style="color: #004000;">getSelectedOrderCouponDataList</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">assertEquals</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">-</span><span style="color: #cc66cc;">100</span><span style="color: #339933;">,</span> <span style="color: #000088;">$resultDataList</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'P1-C1'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'discountPrice'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">assertEquals</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">-</span><span style="color: #cc66cc;">25</span><span style="color: #339933;">,</span>  <span style="color: #000088;">$resultDataList</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'P1-C2'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'discountPrice'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">assertEquals</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">-</span><span style="color: #cc66cc;">75</span><span style="color: #339933;">,</span>  <span style="color: #000088;">$resultDataList</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'P2-C2'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'discountPrice'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>這裡因為我們在上一步就定義好比對用的數據，所以測試時就是用這個輸出的數據來與我們預期的數字相比較。</p>
<p>接下來就先跑跑測試，看看這個 TestCase 有沒有執行錯誤的地方 (例如物件沒有正確初始化或是變數名稱誤寫等等) ；當然如果沒有出現預期值是正常的，因為我們根本還沒有寫計算公式。</p>
<h2>繼續完成演算法</h2>
<p>現在回到 Shop_Cart_Plugin_Coupon ，我們就要把剛剛那些只有骨頭的方法開始添血添肉，這裡就請大家自行發擇。</p>
<p>接著只要你覺得程式差不多了，就先跑一下測試，看看是不是符合測試的預期結果。</p>
<p>當你完成第一個測試時，程式的就差不多完成百分之五十啦，到這裡別忘了先把程式 commit 到版本控制系統裡。</p>
<h2>加入新測試並修改程式</h2>
<p>完成第一個測試時，當然不是沒事了，我們要針對不同的狀況再加入其他的測試數據。</p>
<p>這裡我們就可以開始考慮把第一個測試以 PHPUnit 提供的 Data Provider 改寫，讓我們不必重複過多的程式碼。</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000000; font-weight: bold;">class</span> Shop_Cart_Plugin_CouponTest <span style="color: #000000; font-weight: bold;">extends</span> PHPUnit_Framework_TestCase
<span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// ... 略 ...</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> setUp<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// ... 略 ...</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> tearDown<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// ... 略 ...</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * @dataProvider provider
     */</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> testDoCheckout<span style="color: #009900;">&#40;</span><span style="color: #000088;">$selectedCouponIdList</span><span style="color: #339933;">,</span> <span style="color: #000088;">$productSkuNumberList</span><span style="color: #339933;">,</span> <span style="color: #000088;">$total</span><span style="color: #339933;">,</span> <span style="color: #000088;">$discountDataList</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_plugin<span style="color: #339933;">-&gt;</span><span style="color: #004000;">setValue</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$selectedCouponIdList</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_cart<span style="color: #339933;">-&gt;</span><span style="color: #004000;">addItems</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$productSkuNumberList</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">refresh</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">assertEquals</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$total</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_cart<span style="color: #339933;">-&gt;</span><span style="color: #004000;">getTotal</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_plugin<span style="color: #339933;">-&gt;</span><span style="color: #004000;">doCheckout</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$resultDataList</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_plugin<span style="color: #339933;">-&gt;</span><span style="color: #004000;">getSharedCouponData</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$discountDataList</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$key</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        	<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">assertEquals</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #339933;">,</span> <span style="color: #000088;">$resultDataList</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'discountPrice'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> provider<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span> <span style="color: #666666; font-style: italic;">// 第一個測試</span>
            <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
                <span style="color: #cc66cc;">1</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">// C1, ProductCoupon for P1, $100</span>
                <span style="color: #cc66cc;">2</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">2</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">// C2, ProductCoupon for P1, P2, $100</span>
            <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
                <span style="color: #0000ff;">'P1'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">// $200</span>
                <span style="color: #0000ff;">'P2'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">// $300</span>
            <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">300</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
                <span style="color: #0000ff;">'P1-C1'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #339933;">-</span><span style="color: #cc66cc;">100</span><span style="color: #339933;">,</span>
                <span style="color: #0000ff;">'P1-C2'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #339933;">-</span><span style="color: #cc66cc;">25</span><span style="color: #339933;">,</span>
                <span style="color: #0000ff;">'P2-C2'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #339933;">-</span><span style="color: #cc66cc;">75</span><span style="color: #339933;">,</span>
            <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
            <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span> <span style="color: #666666; font-style: italic;">// 第二個測試</span>
                <span style="color: #666666; font-style: italic;">// ... 略 ...</span>
            <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
            <span style="color: #666666; font-style: italic;">// ... 略 ...</span>
        <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>而加入新測試之後，就可以跑跑測試，看看我們剛寫好的演算法是否正確動作？通常這時候才真正是考驗的開始。因為這時候前面寫好的程式碼可能只對第一個測試正常，接下來的測試也許就會出錯了。</p>
<p>所以我們就會需要修改或重構程式碼，讓後面的測試也能正常執行。當然改過的程式也要讓第一個測試正常運作，才是正確的修改。</p>
<p>當然演算法寫好後，就要真正上到 Web 畫面去測試。至此，你會發現你花在寫測試上的心力都有了回報，因為通常如果你已經定義好介面，而這次的修改只是改寫一個小類別的話，那麼就會發現程式會非常順利地運作了。</p>
<h2>心得</h2>
<p>每次寫購物車時，最麻煩的就是測試時要開啟購物車網頁，把一個一個的商品加進來，再加入不同的折價券條件...</p>
<p>而有單元測試之後，我就可以省去一大堆開啟網頁，點選連結的功夫，專心地撰寫計算邏輯...只能說...單元測試真的個超級便利的工具呀。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.wabow.com/archives/2299/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>家的大小事　一輩子都是特力的事</title>
		<link>http://blog.wabow.com/archives/2277</link>
		<comments>http://blog.wabow.com/archives/2277#comments</comments>
		<pubDate>Thu, 25 Feb 2010 04:45:47 +0000</pubDate>
		<dc:creator>abu</dc:creator>
				<category><![CDATA[工作雜談]]></category>

		<guid isPermaLink="false">http://blog.wabow.com/?p=2277</guid>
		<description><![CDATA[Trihome 是個以靜態頁面為主的網站，需要管理介面的功能也是少之又少。 在和Neo討論之後，想試試看"內嵌前台"方式來製作這次的管理介面，一開始思索了一下，首先是"如何進入管理模式"，一般正常的方式，不外乎就是進到一個有帳號&#38;密碼欄位的畫面，輸入帳密之後，導向進管理後台，而這次想挑戰的內嵌式，當然要嚐試看看新鮮的寫法，相信有玩過魂斗羅的骨灰級玩家都知道，只要在一開始遊戲畫面中輸入上、上、下、下、左、右、左、右、B、A、B、A，，就可以得到30隻，對於想破關的朋友，莫不是一大福音，根據這樣的"取得隻數"的方式，"取得權限"亦可如法炮制，於是就出現了，魂斗羅內嵌Trihome的想法，在網站的任意位置，只要管理者突然有想進入管理介面的衝動，只要輸入密碼按下Enter，就可以神不知鬼不覺的偷偷進入管理介面，以下即為進入管理介面之後的畫面： 眼尖的朋友應該注意到了，在畫面上有隱約透露出神秘綠光的區塊，這部份是提示管理者，目前頁面上"即將被編輯的區域"，而點擊右上的綠勾，就可以進入真正的編輯區塊了，如下圖： 在編輯區塊內全部採取ajax即時更新資訊方式，讓管理者更能直覺的輸入修改資料。 在一開始構思的時候，本來預定是要真的在網頁上，即時編輯所有內容，不過第一頁就遇到問題了，在首頁的Banner，一次需要上多張Banner，系統判斷上下檔期後，要自動替換，那要可以即時編輯的話，難道要把全部已經上傳的圖都秀出來，版面應該會破的亂七八糟吧，所以才借助了blockUI，把需要編輯的部份通通丟在裡面，以不破壞原始版面為主；在這次撰寫過程，遇到很多問題需要解決，也連帶吸收了不少EXP，整個管理的方式進步空間還很大，不過算是處女作就....勉強算ok，未來有機會的話，可以再嚐試看看不同的方式，朝更人性、更直覺的設計介面前進吧~]]></description>
			<content:encoded><![CDATA[<p>Trihome 是個以靜態頁面為主的網站，需要管理介面的功能也是少之又少。</p>
<p><img class="alignnone size-full wp-image-2279" src="http://blog.wabow.com/wp-content/uploads/2010/02/tri1.png" alt="" width="500" height="319" /></p>
<p><span id="more-2277"></span></p>
<p>在和Neo討論之後，想試試看"內嵌前台"方式來製作這次的管理介面，一開始思索了一下，首先是"如何進入管理模式"，一般正常的方式，不外乎就是進到一個有帳號&amp;密碼欄位的畫面，輸入帳密之後，導向進管理後台，而這次想挑戰的內嵌式，當然要嚐試看看新鮮的寫法，相信有玩過魂斗羅的骨灰級玩家都知道，只要在一開始遊戲畫面中輸入上、上、下、下、左、右、左、右、B、A、B、A，，就可以得到30隻，對於想破關的朋友，莫不是一大福音，根據這樣的"取得隻數"的方式，"取得權限"亦可如法炮制，於是就出現了，魂斗羅內嵌Trihome的想法，在網站的任意位置，只要管理者突然有想進入管理介面的衝動，只要輸入密碼按下Enter，就可以神不知鬼不覺的偷偷進入管理介面，以下即為進入管理介面之後的畫面：<br />
<img src="http://blog.wabow.com/wp-content/uploads/2010/02/tri2.png" alt="" /><br />
<img src="http://blog.wabow.com/wp-content/uploads/2010/02/tri2_1.png" alt="" /></p>
<p>眼尖的朋友應該注意到了，在畫面上有隱約透露出神秘綠光的區塊，這部份是提示管理者，目前頁面上"即將被編輯的區域"，而點擊右上的綠勾，就可以進入真正的編輯區塊了，如下圖：<br />
<img src="http://blog.wabow.com/wp-content/uploads/2010/02/tri3.png" alt="" /></p>
<p>在編輯區塊內全部採取ajax即時更新資訊方式，讓管理者更能直覺的輸入修改資料。</p>
<p>在一開始構思的時候，本來預定是要真的在網頁上，即時編輯所有內容，不過第一頁就遇到問題了，在首頁的Banner，一次需要上多張Banner，系統判斷上下檔期後，要自動替換，那要可以即時編輯的話，難道要把全部已經上傳的圖都秀出來，版面應該會破的亂七八糟吧，所以才借助了blockUI，把需要編輯的部份通通丟在裡面，以不破壞原始版面為主；在這次撰寫過程，遇到很多問題需要解決，也連帶吸收了不少EXP，整個管理的方式進步空間還很大，不過算是處女作就....勉強算ok，未來有機會的話，可以再嚐試看看不同的方式，朝更人性、更直覺的設計介面前進吧~</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.wabow.com/archives/2277/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>哇寶 2010 尾牙宴 - 台北京華酒店三燔本家</title>
		<link>http://blog.wabow.com/archives/2270</link>
		<comments>http://blog.wabow.com/archives/2270#comments</comments>
		<pubDate>Sun, 14 Feb 2010 18:53:44 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[工作雜談]]></category>

		<guid isPermaLink="false">http://blog.wabow.com/?p=2270</guid>
		<description><![CDATA[公司這次的尾牙選在台北京華酒店的三燔本家，日期則是訂在1/20。 三燔本家在網路上許多吃過的人都極力推薦，甚至可以說是一生當中一定要吃一次的店。經過哇寶挑嘴團這次尾牙的實地品嚐，雖然價格較高，但的確非常值得親身前往一探究竟。 有多值得呢? 從第一道菜開始沒多久，身邊陸續傳來同事們此起彼落的聲音「好好吃喔~」「嗯~這個真好吃」「喔~太好吃了」...(每道新的菜上來，重覆的戲碼也不斷的上演 XD) (不只沙拉做的美味，連裝沙拉的碗都又脆又香，吃的不亦樂乎) (極度受好評的開胃菜) (生魚片好吃到大家都在用搶的) (這道牛肉的料理鮮嫩多汁，對牛肉最挑嘴的 Jace 都大力推薦) (龍蝦海鮮的美妙滋味實在讓人難以忘懷) (這隻魚一出現沒多久就只剩下骨頭了 XD) (燒烤的味道也不是蓋的) 這次的主角"和牛"更是不可少，甚至加點了一份頂級和牛來吃。 (用鍋底的蒸氣來吃，這真的是人間美味呀~) 最後的甜點水果一搬進來，真的就是異口同聲的「哇噢~~~」 (照片看起沒什麼，但現場看這個真的非常大一鍋) 雖然有遇到牛小排吃到飽的優惠，但同事有的不吃牛、不吃肉...點吃到飽的並不划算 (註)，所以這次以尾牙以三燔本家的套餐為主。以上的照片也只列出部份餐點，由於現場吃的種類很多，加上平常難得有機會吃到高級料理，只顧著吃都來不及了，能保持理性的人記得每樣菜的人已經不多了。XD 註:使用吃到飽的優惠，包廂全場的每個人都要加一份牛小排吃到飽的價格。 (最後每個人幾乎飽到走不太動了，飽到不行的合照) 今年大家也要一起好好努力，明年繼續吃大餐。^^ //]]></description>
			<content:encoded><![CDATA[<p>公司這次的尾牙選在台北京華酒店的三燔本家，日期則是訂在1/20。</p>
<p><img src="http://farm3.static.flickr.com/2694/4290936974_1f8c9a9327.jpg" alt="" /></p>
<p><span id="more-2270"></span>三燔本家在網路上許多吃過的人都極力推薦，甚至可以說是一生當中一定要吃一次的店。經過哇寶挑嘴團這次尾牙的實地品嚐，雖然價格較高，但的確非常值得親身前往一探究竟。</p>
<p>有多值得呢? 從第一道菜開始沒多久，身邊陸續傳來同事們此起彼落的聲音「好好吃喔~」「嗯~這個真好吃」「喔~太好吃了」...(每道新的菜上來，重覆的戲碼也不斷的上演 XD)</p>
<p><img src="http://farm3.static.flickr.com/2745/4290197289_8754e88cdd.jpg" alt="" />(不只沙拉做的美味，連裝沙拉的碗都又脆又香，吃的不亦樂乎)</p>
<p><img src="http://farm3.static.flickr.com/2735/4290197427_5f7c7215e1.jpg" alt="" />(極度受好評的開胃菜)</p>
<p><img src="http://farm3.static.flickr.com/2711/4290197679_23f20a3af1.jpg" alt="" />(生魚片好吃到大家都在用搶的)</p>
<p><img src="http://farm5.static.flickr.com/4025/4290199727_b7dba19bf6.jpg" alt="" />(這道牛肉的料理鮮嫩多汁，對牛肉最挑嘴的 Jace 都大力推薦)</p>
<p><img src="http://farm5.static.flickr.com/4056/4290943170_e2e2849e44.jpg" alt="" />(龍蝦海鮮的美妙滋味實在讓人難以忘懷)</p>
<p><img src="http://farm5.static.flickr.com/4039/4290942708_eb4588439f.jpg" alt="" />(這隻魚一出現沒多久就只剩下骨頭了 XD)<br />
<img src="http://farm5.static.flickr.com/4001/4290942938_3d047d7726.jpg" alt="" /></p>
<p>(燒烤的味道也不是蓋的)</p>
<p>這次的主角"和牛"更是不可少，甚至加點了一份頂級和牛來吃。</p>
<p><img src="http://farm5.static.flickr.com/4012/4290943382_fd702a16c3.jpg" alt="" /></p>
<p>(用鍋底的蒸氣來吃，這真的是人間美味呀~)</p>
<p>最後的甜點水果一搬進來，真的就是異口同聲的「哇噢~~~」</p>
<p><img src="http://farm5.static.flickr.com/4051/4290204809_7283a5f1e5.jpg" alt="" /></p>
<p>(照片看起沒什麼，但現場看這個真的非常大一鍋)</p>
<p>雖然有遇到牛小排吃到飽的優惠，但同事有的不吃牛、不吃肉...點吃到飽的並不划算 (註)，所以這次以尾牙以三燔本家的套餐為主。以上的照片也只列出部份餐點，由於現場吃的種類很多，加上平常難得有機會吃到高級料理，只顧著吃都來不及了，能保持理性的人記得每樣菜的人已經不多了。XD</p>
<p>註:使用吃到飽的優惠，包廂全場的每個人都要加一份牛小排吃到飽的價格。</p>
<p><a href="http://blog.wabow.com/wp-content/uploads/2010/02/CIMG0093.jpg"><img class="alignnone size-large wp-image-2271" title="CIMG0093" src="http://blog.wabow.com/wp-content/uploads/2010/02/CIMG0093-500x375.jpg" alt="" width="500" height="375" /></a></p>
<p>(最後每個人幾乎飽到走不太動了，飽到不行的合照)</p>
<p>今年大家也要一起好好努力，明年繼續吃大餐。^^</p>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">
<div id="photo_notes" class="photo_notes" style="visibility: visible;">
<div id="notes_text_div" style="z-index: 1000; display: none; position: relative; width: 220px; margin-top: -5px; padding-top: 5px;">
<div id="notes_text_table">
<div class="td_note_yeller  td_note_yeller_container"><span id="notes_text_span"> </span></p>
<form id="notes_text_form">
<input name="magic_cookie" type="hidden" value="c966c9f1b441bcdc11bd05e0739d139b" /><textarea id="notes_text_area" style="height: 58px;" onkeydown="_limit_textarea(this, 300);  _ge('photo_notes').check_note_for_prop()" onkeyup="place_notes_text_div(); adjust_textarea_height(this);  _limit_textarea(this, 300); _ge('photo_notes').check_note_for_prop()" rows="1"></textarea></form>
</div>
</div>
<form id="notes_text_buttons_form">
<input class="Butt" onclick="_ge('photo_notes').save_editing(); this.blur();" type="button" value="儲存" />
<input class="CancelButt" onclick="_ge('photo_notes').cancel_editing(); this.blur();" type="button" value="取消" />
<input id="delete_note_button" class="DeleteButt" onclick="_ge('photo_notes').delete_note();  this.blur();" type="button" value="刪除！" /></form>
</div>
<p><script type="text/javascript">// <![CDATA[
var page_note_ratio = 1;
// ]]&gt;</script><script type="text/javascript"></script></p>
</div>
<div id="comm_div" style="z-index: 1002; display: none;">
<table id="comm_table" style="width: 200px; background: none repeat scroll 0% 0% #ffffff; padding: 3px;" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="td_white"></td>
<td class="td_white" style="padding: 3px 0px 0px;" width="1" valign="top"><img id="comm_pulser_img" src="http://l.yimg.com/g/images/pulser2.gif" border="0" alt="" width="32" height="15" /></td>
<td id="comm_td" class="td_white" style="padding: 3px; font-size: 12px;"></td>
<td class="td_white"></td>
</tr>
<tr id="comm_button_tr">
<td class="td_white"></td>
<td class="td_white"></td>
<td class="td_white" style="padding: 3px;">
<form>
<input id="comm_button_ok" class="Butt" style="margin: 5px 5px 0pt 0pt;" onclick="this.onclick_func();" type="button" value="OK" />
<input id="comm_button_cancel" class="CancelButt" style="margin: 5px 5px 0pt 0pt;" onclick="this.onclick_func();" type="button" value="取消" /></form>
</td>
<td class="td_white"></td>
</tr>
</tbody>
</table>
</div>
<div id="rotate_div" style="z-index: 1003; display: none;">
<div id="rotate_table" style="width: 218px; background: none repeat scroll 0% 0% #ffffff; padding: 1px;">
<div class="td_note_white" style="padding: 0px; text-align: center; margin-top: 3px;"><span id="rotate_span" style="font-family: arial; font-size: 12px;"> </span></div>
</div>
</div>
<div id="shadow_div" style="z-index: 999; display: none;">
<table class="shadow_table" style="padding: 0px;" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="11"><img class="shadow_sprite shadow_tl" src="http://l.yimg.com/g/images/spaceout.gif" alt="" width="11" height="11" /></td>
<td id="shadow_width_controller"><img class="shadow_sprite  shadow_t" src="http://l.yimg.com/g/images/spaceout.gif" alt="" width="100%" height="11" /></td>
<td width="11"><img class="shadow_sprite  shadow_tr" src="http://l.yimg.com/g/images/spaceout.gif" alt="" width="11" height="11" /></td>
</tr>
<tr>
<td id="shadow_height_controller" height="30"><img class="shadow_sprite  shadow_l" src="http://l.yimg.com/g/images/spaceout.gif" alt="" width="11" height="100%" /></td>
<td></td>
<td><img class="shadow_sprite  shadow_r" src="http://l.yimg.com/g/images/spaceout.gif" alt="" width="11" height="100%" /></td>
</tr>
<tr>
<td><img class="shadow_sprite  shadow_bl" src="http://l.yimg.com/g/images/spaceout.gif" alt="" width="11" height="11" /></td>
<td><img id="shadow_width_controller2" class="shadow_sprite  shadow_b" src="http://l.yimg.com/g/images/spaceout.gif" alt="" width="100%" height="11" /></td>
<td><img class="shadow_sprite  shadow_br" src="http://l.yimg.com/g/images/spaceout.gif" alt="" width="11" height="11" /></td>
</tr>
</tbody>
</table>
</div>
<p><img class="reflect" src="http://farm3.static.flickr.com/2694/4290936974_1f8c9a9327.jpg" alt="jaceju 拍攝的 P1020432。" width="500" height="333" /></p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.wabow.com/archives/2270/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>HOLA 的網站改版會議</title>
		<link>http://blog.wabow.com/archives/2212</link>
		<comments>http://blog.wabow.com/archives/2212#comments</comments>
		<pubDate>Sat, 09 Jan 2010 09:15:36 +0000</pubDate>
		<dc:creator>Neo</dc:creator>
				<category><![CDATA[工作雜談]]></category>

		<guid isPermaLink="false">http://blog.wabow.com/?p=2212</guid>
		<description><![CDATA[回顧去年的時候，特力集團的電子商務團隊負責人跑來我們公司。 會議開始後，從投影機之中映出了一網站，問我們能不能做到這樣的效果? (這個網站是 Pixazza 。發音 Pix-a-zza 音似: "皮克斯阿殺") Pixazza 在去年成立時就引發國外媒體關注，這個連 Google 也名列股東之一的公司，做的事看起來明白易懂:「即使是新聞圖片也可以購物」。 雖然很多人笑稱這只是 Flickr + EDM 的變形，國外早年已有類似的應用在型錄上，但實際應用於購物網站在台灣還沒見到。 特力的團隊同時也帶來了 IKEA 的網站做為參考: 看完之後，我請另一位同事先放下手邊的工作，從電腦拿出個東西給他們看，我們其實很早就開發出雛形來了。 (這個雛形不只有"點"，甚至可以延伸到"面"。上圖是 Email 給特力團隊時改為廚房情境照) 接著跟特力的團隊討論完技術層面，並且參考 HOLA 的實體型錄內容之後，特力團隊的負責人認為還有一件事要解決，以圖片為購物主軸來結合購物網站並不容易，在國內外都沒有這樣的案例可以參考，也希望我們能提供一些意見。 這次就輪到我來做展示了，其實在討論的過程中就已經想到我們的客戶 BlingCandy 的網站首頁非常適合呈現這樣的購物模式: 首頁上方遠大於一般購物網站的圖片尺寸，可以左右切換不同的圖片來進行購物。 這樣情境圖片便能成為網站購物的主體，網頁下方再規畫為展示及促銷訊息區塊。 就這樣，客戶帶著滿意的微笑離去， HOLA 的新版計畫也就從這裡開始了。]]></description>
			<content:encoded><![CDATA[<p>回顧去年的時候，特力集團的電子商務團隊負責人跑來我們公司。</p>
<p>會議開始後，從投影機之中映出了一網站，問我們能不能做到這樣的效果?</p>
<p><a href="http://blog.wabow.com/wp-content/uploads/2010/01/pixazza3.jpg"><img class="alignnone size-large wp-image-2219" title="pixazza3" src="http://blog.wabow.com/wp-content/uploads/2010/01/pixazza3-500x465.jpg" alt="" width="500" height="465" /></a></p>
<p>(這個網站是 <span style="font-size: x-small;"><a href="http://www.pixazza.com/" target="_blank">Pixazza</a> 。發音 </span>Pix-a-zza 音似: "皮克斯阿殺"<span style="font-size: x-small;">)<br />
</span></p>
<p><span style="font-size: x-small;"><a href="http://www.pixazza.com/" target="_blank"><span id="more-2212"></span>Pixazza</a> 在去年成立時就引發國外<a href="http://news.cnet.com/8301-1023_3-10203588-93.html" target="_blank">媒體關注</a>，</span>這個連 Google 也名列股東之一的公司，做的事看起來明白易懂:「即使是新聞圖片也可以購物」。</p>
<p>雖然很多人笑稱這只是 <a href="http://www.flickr.com" target="_blank">Flickr</a> + EDM 的變形，國外早年已有類似的應用在型錄上，但實際應用於購物網站在台灣還沒見到。</p>
<p>特力的團隊同時也帶來了 <a href="http://www.ikea.com/ca/en/" target="_blank">IKEA </a>的網站做為參考:</p>
<p><a href="http://blog.wabow.com/wp-content/uploads/2010/01/ikea1.png"><img class="alignnone size-large wp-image-2215" title="ikea1" src="http://blog.wabow.com/wp-content/uploads/2010/01/ikea1-500x288.png" alt="" width="500" height="288" /></a></p>
<p><a href="http://blog.wabow.com/wp-content/uploads/2010/01/ikea2.jpg"><img class="alignnone size-medium wp-image-2216" title="ikea2" src="http://blog.wabow.com/wp-content/uploads/2010/01/ikea2-300x225.jpg" alt="" width="300" height="225" /></a> <a href="http://blog.wabow.com/wp-content/uploads/2010/01/ikea3.jpg"><img class="alignnone size-medium wp-image-2217" title="ikea3" src="http://blog.wabow.com/wp-content/uploads/2010/01/ikea3-300x226.jpg" alt="" width="300" height="226" /></a></p>
<p>看完之後，我請另一位同事先放下手邊的工作，從電腦拿出個東西給他們看，我們其實很早就開發出雛形來了。</p>
<p><a href="http://blog.wabow.com/wp-content/uploads/2010/01/washow.jpg"><img class="alignnone size-full wp-image-2220" title="washow" src="http://blog.wabow.com/wp-content/uploads/2010/01/washow.jpg" alt="" width="470" height="388" /></a></p>
<p>(這個雛形不只有"點"，甚至可以延伸到"面"。上圖是 Email 給特力團隊時改為廚房情境照)</p>
<p>接著跟特力的團隊討論完技術層面，並且參考 HOLA 的實體型錄內容之後，特力團隊的負責人認為還有一件事要解決，以圖片為購物主軸來結合購物網站並不容易，在國內外都沒有這樣的案例可以參考，也希望我們能提供一些意見。</p>
<p>這次就輪到我來做展示了，其實在討論的過程中就已經想到我們的客戶 <a href="http://www.blingcandy.com.tw/" target="_blank">BlingCandy</a> 的網站首頁非常適合呈現這樣的購物模式:</p>
<p><a href="http://blog.wabow.com/wp-content/uploads/2009/06/new-2009-4-29-e4b88be58d88-12-28-28.jpg"><img class="alignnone size-large wp-image-1297" title="new-2009-4-29-e4b88be58d88-12-28-28" src="http://blog.wabow.com/wp-content/uploads/2009/06/new-2009-4-29-e4b88be58d88-12-28-28-500x411.jpg" alt="" width="500" height="411" /></a></p>
<p>首頁上方遠大於一般購物網站的圖片尺寸，可以左右切換不同的圖片來進行購物。<br />
這樣情境圖片便能成為網站購物的主體，網頁下方再規畫為展示及促銷訊息區塊。</p>
<p>就這樣，客戶帶著滿意的微笑離去， HOLA 的新版計畫也就從這裡開始了。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.wabow.com/archives/2212/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Yahoo! 2009 網路爆紅品牌之最</title>
		<link>http://blog.wabow.com/archives/2191</link>
		<comments>http://blog.wabow.com/archives/2191#comments</comments>
		<pubDate>Sun, 03 Jan 2010 16:01:58 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[客戶紀事]]></category>
		<category><![CDATA[最新消息]]></category>

		<guid isPermaLink="false">http://blog.wabow.com/?p=2191</guid>
		<description><![CDATA[回顧 2009 年，Yahoo! 做了一系列的網路活動調查，網路爆紅品牌之最 TOP 10 也是其中之一: (第1名"天母嚴選"及第10名"御家族"正好都是我們的客戶) 我們非常了解網路市場的經營不易，因此對能入榜 Yahoo! TOP10 的商家都深感佩服。 在這邊也同時祝福台灣所有的電子商務網站在 2010 年能有更好的成績。TAIWAN UP! 相關網頁: Yahoo! 奇摩2009之最]]></description>
			<content:encoded><![CDATA[<p>回顧 2009 年，Yahoo! 做了一系列的網路活動調查，<a href="http://yahoo.atlaspost.com/Tw.promotions.yahoo.com/YIR2009/top10.php?cid=31" target="_blank">網路爆紅品牌之最 TOP 10</a> 也是其中之一:</p>
<p style="text-align: center;"><a href="http://blog.wabow.com/wp-content/uploads/2010/01/yahoo2009bestbrand.png" target="_blank"><img class="alignnone size-large wp-image-2192" title="yahoo2009bestbrand" src="http://blog.wabow.com/wp-content/uploads/2010/01/yahoo2009bestbrand-322x500.png" alt="" width="322" height="500" /></a></p>
<p style="text-align: center;">(第1名"<a href="http://www.gotobuy.com.tw/" target="_blank">天母嚴選</a>"及第10名"<a href="http://www.ace-88.com/" target="_blank">御家族</a>"正好都是我們的客戶)</p>
<p><span id="more-2191"></span>我們非常了解網路市場的經營不易，因此對能入榜 Yahoo! TOP10 的商家都深感佩服。</p>
<p>在這邊也同時祝福台灣所有的電子商務網站在 2010 年能有更好的成績。TAIWAN UP!</p>
<p>相關網頁:<br />
<a href="http://yahoo.atlaspost.com/Tw.promotions.yahoo.com/YIR2009/index.php?PAGE_TAG_ID=64" target="_blank">Yahoo! 奇摩2009之最</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.wabow.com/archives/2191/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>御家族網站上線，喚醒體內的零食基因</title>
		<link>http://blog.wabow.com/archives/2149</link>
		<comments>http://blog.wabow.com/archives/2149#comments</comments>
		<pubDate>Sat, 02 Jan 2010 08:28:15 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[客戶紀事]]></category>
		<category><![CDATA[最新消息]]></category>

		<guid isPermaLink="false">http://blog.wabow.com/?p=2149</guid>
		<description><![CDATA[上線日期: 2009/11/30 沒吃過御海苔，等於這輩子沒吃過海苔。 御海苔有多好吃? Google 搜尋 "御海苔" 所出現的一大串團購、勸敗文: 小華兒愛瞎拼_【團購】御家族的御海苔~忍不住想吃咧 喵喵の簡單生活 ::【團購】御家族的味付海苔&#38;手工達人之黃金蛋捲 [團購]板橋市。寬泓御海苔@ 佳莉。心情:: 痞客邦PIXNET :: yumi的隨意札記: 【零食】味付御海苔- yam天空部落 御家族除了海苔很有名之外，陸續推出了許多不同種類的零食。 這次很高興能有機會跟御家族的團隊合作，他們真的很在乎每一位網友的反應，對於自家購物網站也要求一定要做到最好、最方便訂購。 御家族網站在2009 年尾很順利的上線了，但偷偷告訴大家，這個網站的重頭戲還沒來，2010 年初將提供一般購物網站難得一見的新功能，敬請期待。 御家族官方購物網站: http://www.ace-88.com/]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><a href="upload.php"><img class="alignnone size-large wp-image-2157" title="ace88-wabow" src="http://blog.wabow.com/wp-content/uploads/2010/01/ace88-wabow-306x499.png" alt="" width="306" height="499" /><br />
</a></p>
<p style="text-align: center;">上線日期: 2009/11/30</p>
<h2><span id="more-2149"></span>沒吃過御海苔，等於這輩子沒吃過海苔。</h2>
<p>御海苔有多好吃? Google 搜尋 "御海苔" 所出現的一大串團購、勸敗文:</p>
<h3><a onmousedown="return rwt(this,'','','res','6','AFQjCNFh-muqBAlFWkzVC_kcli6dhzNUCw','&amp;sig2=Ht5gwvz4c6ThHUayhKTLvQ','0CB8QFjAF')" href="http://www.calldoor.com.tw/myblog/nimi57/articles/17523" target="_blank">小華兒愛瞎拼_【團購】<em>御家族</em>的御<em>海苔</em>~忍不住想吃咧<br />
</a></h3>
<h3><a onmousedown="return rwt(this,'','','res','1','AFQjCNH7wUHWX9jjLKuv2dpSLz8YatpOMQ','&amp;sig2=HbVkLjDdLmogY1RdMsEBNA','0CAcQFjAA')" href="http://nicole0726.pixnet.net/blog/post/24458083" target="_blank">喵喵の簡單生活 ::【<em>團購</em>】御家族的味付海苔&amp;手工達人之黃金蛋捲<br />
</a></h3>
<h3><a onmousedown="return rwt(this,'','','res','13','AFQjCNGDyWDZ1JrOClPR-u-gRYxthlmlQw','&amp;sig2=0XLo6DfWddfAAZMKb2DT6Q','0CBAQFjACOAo')" href="http://www.google.com.tw/url?sa=t&amp;source=web&amp;ct=res&amp;cd=13&amp;ved=0CBAQFjACOAo&amp;url=http%3A%2F%2Fchialy.pixnet.net%2Fblog%2Fpost%2F23714440&amp;ei=8vw-S__XI8GHkQWQ-vGDCQ&amp;usg=AFQjCNGDyWDZ1JrOClPR-u-gRYxthlmlQw&amp;sig2=0XLo6DfWddfAAZMKb2DT6Q" target="_blank">[團購]板橋市。寬泓<em>御海苔</em>@ 佳莉。心情:: 痞客邦PIXNET ::</a></h3>
<h3><a onmousedown="return rwt(this,'','','res','8','AFQjCNGqKZgpaeil5bftV03kdGuLNjtksQ','&amp;sig2=PfFD3fsPtOguxidvsbd46g','0CCgQFjAH')" href="http://www.google.com.tw/url?sa=t&amp;source=web&amp;ct=res&amp;cd=8&amp;ved=0CCgQFjAH&amp;url=http%3A%2F%2Fblog.yam.com%2Fyumi721%2Farticle%2F3329132&amp;ei=dPw-S4n6GM6LkAWtkPT3CA&amp;usg=AFQjCNGqKZgpaeil5bftV03kdGuLNjtksQ&amp;sig2=PfFD3fsPtOguxidvsbd46g" target="_blank">yumi的隨意札記: 【零食】味付<em>御海苔</em>- yam天空部落</a></h3>
<p>御家族除了海苔很有名之外，陸續推出了許多不同種類的零食。</p>
<p>這次很高興能有機會跟御家族的團隊合作，他們真的很在乎每一位網友的反應，對於自家購物網站也要求一定要做到最好、最方便訂購。</p>
<p>御家族網站在2009 年尾很順利的上線了，但偷偷告訴大家，這個網站的重頭戲還沒來，2010 年初將提供一般購物網站難得一見的新功能，敬請期待。<a href="http://www.ace-88.com/" target="_blank"></p>
<p></a></p>
<p>御家族官方購物網站: <a href="http://www.ace-88.com/" target="_blank"><br />

http://www.ace-88.com/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.wabow.com/archives/2149/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>美麗華 IMAX 3D 體驗阿凡達的真實世界</title>
		<link>http://blog.wabow.com/archives/2141</link>
		<comments>http://blog.wabow.com/archives/2141#comments</comments>
		<pubDate>Fri, 01 Jan 2010 06:22:43 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[工作雜談]]></category>

		<guid isPermaLink="false">http://blog.wabow.com/?p=2141</guid>
		<description><![CDATA[阿凡達 AVATAR 這部劃時代的電影上映，許多企業紛紛包場體恤辛苦的工作同仁們。 哇寶當然不能錯過這個新時代 3D 電影的響宴，阿凡達在台正式上映前便已預訂在台灣螢幕最大的美麗華 IMAX 影廳，讓全體同仁體驗身歷其境的 IMAX 3D 的潘朵拉星球之旅。 (哇寶夥伴們在阿凡達立牌前合影) 阿凡達這部電影成功的寫下影史的新頁，相信台灣未來也能做出更多舉世刮目相看的革命性產品。 TAIWAN UP!]]></description>
			<content:encoded><![CDATA[<p>阿凡達 AVATAR 這部劃時代的電影上映，許多企業紛紛包場體恤辛苦的工作同仁們。</p>
<p><a href="http://www.atmovies.com.tw/movie/film.asp?action=now&amp;film_id=faen00499549" target="_blank"><img class="alignnone size-full wp-image-2142" title="3170" src="http://blog.wabow.com/wp-content/uploads/2010/01/3170.jpg" alt="" width="383" height="572" /></a></p>
<p><span id="more-2141"></span>哇寶當然不能錯過這個新時代 3D 電影的響宴，阿凡達在台正式上映前便已預訂在台灣螢幕最大的美麗華 IMAX 影廳，讓全體同仁體驗身歷其境的 IMAX 3D 的潘朵拉星球之旅。</p>
<p><img class="alignnone size-large wp-image-2143" title="CIMG9542" src="http://blog.wabow.com/wp-content/uploads/2010/01/CIMG9542-500x375.jpg" alt="" width="500" height="375" /></p>
<p>(哇寶夥伴們在阿凡達立牌前合影)</p>
<p>阿凡達這部電影成功的寫下影史的新頁，相信台灣未來也能做出更多舉世刮目相看的革命性產品。</p>
<p>TAIWAN UP!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.wabow.com/archives/2141/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>噗浪備份工具 BKPlurk Beta 上線</title>
		<link>http://blog.wabow.com/archives/2124</link>
		<comments>http://blog.wabow.com/archives/2124#comments</comments>
		<pubDate>Sat, 12 Dec 2009 11:51:30 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[最新消息]]></category>

		<guid isPermaLink="false">http://blog.wabow.com/?p=2124</guid>
		<description><![CDATA[Plurk 的官方API 出來之後，第一件事當然就是要用來好好的備份噗浪啦。 噗浪備份工具 BKPlurk Beta 測試上線網址: http://www.wabow.com/bkplurk/ 在噗浪官方 API 發布前，備份工具大多只能備份自己的噗，因此這次在做 BKPlurk 時就把備份"回噗"列為重點。 為了觀看方便，所以備份檔案採用 HMTL 格式，點一下就可以看到回噗了。 (至於 CSV 的格式目前還在規畫中) 使用上有任何問題或意見也歡迎大家提出來一起討論。^^ 更新記錄: 12/15: 感謝 Jace 做的新畫面 (點此回顧初版的畫面)]]></description>
			<content:encoded><![CDATA[<p>Plurk 的<a href="http://www.plurk.com/API" target="_blank">官方API</a> 出來之後，第一件事當然就是要用來好好的備份噗浪啦。</p>
<p><a title="http://www.wabow.com/bkplurk/" href="http://www.wabow.com/bkplurk/" target="_blank"><img class="alignnone size-large wp-image-2131" title="bkplurk2" src="http://blog.wabow.com/wp-content/uploads/2009/12/bkplurk2-460x500.png" alt="bkplurk2" width="460" height="500" /></a></p>
<p><span id="more-2124"></span></p>
<p>噗浪備份工具 BKPlurk Beta 測試上線網址:<br />
<a href="http://www.wabow.com/bkplurk/" target="_blank">http://www.wabow.com/bkplurk/</a></p>
<p>在噗浪官方 API 發布前，備份工具大多只能備份自己的噗，因此這次在做 BKPlurk 時就把備份"回噗"列為重點。</p>
<p>為了觀看方便，所以備份檔案採用 HMTL 格式，點一下就可以看到回噗了。<br />
(至於 CSV 的格式目前還在規畫中)</p>
<p>使用上有任何問題或意見也歡迎大家提出來一起討論。^^</p>
<p><span style="color: #ff0000;">更新記錄</span>:<br />
12/15: 感謝 Jace 做的新畫面 (<a href="http://blog.wabow.com/wp-content/uploads/2009/12/bkplurk.png" target="_blank">點此</a>回顧初版的畫面)</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.wabow.com/archives/2124/feed</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>天母嚴選 Gotobuy 網站上線</title>
		<link>http://blog.wabow.com/archives/2116</link>
		<comments>http://blog.wabow.com/archives/2116#comments</comments>
		<pubDate>Wed, 18 Nov 2009 11:57:11 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[客戶紀事]]></category>
		<category><![CDATA[最新消息]]></category>

		<guid isPermaLink="false">http://blog.wabow.com/?p=2116</guid>
		<description><![CDATA[Yahoo! 購物中心最大的女裝品牌「天母嚴選」購物網站在 11/15 正式上線了。 不就是個服裝購物網站嘛? 如果這麼想可就大大的錯囉。 只要在 Yahoo! 購物中心 或 Gotobuy 網站消費，都可以累積紅利積點兌換好康商品喔。接下來即將登場的優惠折扣機制，讓網友即使在實體通路也能享受到天母嚴選異業合作的大優惠，真的是賺翻啦。 在建置的過程當中，最複雜的地方在於庫存的調撥機制，為了讓天母嚴選在不同的通路都能有正確的數量，花了很多時間跟天母嚴選的團隊一起討論、修正、討論、再修正，過程當中天母嚴選的倉管、物流、客服人員也很用心的提出作業的流程建議參考，在雙方不斷的努力下，最後終於讓網站順利的完成上線了。 上線後才驚覺天母嚴選的團隊更是臥虎藏龍，有人在家隨手就畫出了這張 Gotobuy 的 7-11 取貨圖。 別再等啦~ 想親身體驗各種不同風格的時尚穿搭，來 Gotobuy 就對了! ^^ 天母嚴選 Gotobuy 網址: http://www.gotobuy.com.tw/ 同場加映，網站開發中畫面:]]></description>
			<content:encoded><![CDATA[<p style="text-align: left;">Yahoo! 購物中心最大的女裝品牌「<a href="http://buy.yahoo.com.tw/?sub=231" target="_blank">天母嚴選</a>」購物網站在 11/15 正式上線了。</p>
<p style="text-align: left;"><a href="http://www.gotobuy.com.tw" target="_blank"><img class="size-large wp-image-2115 aligncenter" title="gotobuy" src="http://blog.wabow.com/wp-content/uploads/2009/11/gotobuy-278x499.png" alt="gotobuy" width="278" height="499" /></a><br />
<span id="more-2116"></span>不就是個服裝購物網站嘛?</p>
<p style="text-align: left;">如果這麼想可就大大的錯囉。</p>
<p style="text-align: left;">只要在 Yahoo! 購物中心 或 Gotobuy 網站消費，都可以累積紅利積點兌換好康商品喔。接下來即將登場的優惠折扣機制，讓網友即使在實體通路也能享受到天母嚴選異業合作的大優惠，真的是賺翻啦。</p>
<p>在建置的過程當中，最複雜的地方在於庫存的調撥機制，為了讓天母嚴選在不同的通路都能有正確的數量，花了很多時間跟天母嚴選的團隊一起討論、修正、討論、再修正，過程當中天母嚴選的倉管、物流、客服人員也很用心的提出作業的流程建議參考，在雙方不斷的努力下，最後終於讓網站順利的完成上線了。</p>
<p>上線後才驚覺天母嚴選的團隊更是臥虎藏龍，有人在家隨手就畫出了這張 Gotobuy 的 7-11 取貨圖。</p>
<p><a href="http://blog.wabow.com/wp-content/uploads/2009/11/gotobuy7-11.jpg"><img class="alignnone size-large wp-image-2117" title="gotobuy7-11" src="http://blog.wabow.com/wp-content/uploads/2009/11/gotobuy7-11-500x222.jpg" alt="gotobuy7-11" width="500" height="222" /></a></p>
<p>別再等啦~ <strong>想親身體驗各種不同風格的時尚穿搭，來 <a href="http://www.gotobuy.com.tw/" target="_blank">Gotobuy</a> 就對了!</strong> ^^</p>
<p>天母嚴選 Gotobuy 網址:<br />
<a href="http://www.gotobuy.com.tw/" target="_blank">http://www.gotobuy.com.tw/</a></p>
<p><strong><span style="color: #ff6600;">同場加映，網站開發中畫面</span></strong>:<br />
<a href="http://blog.wabow.com/wp-content/uploads/2009/11/gotobuy-develop.png"><img class="alignnone size-thumbnail wp-image-2121" title="gotobuy-develop" src="http://blog.wabow.com/wp-content/uploads/2009/11/gotobuy-develop-150x150.png" alt="gotobuy-develop" width="150" height="150" /></a><a href="http://blog.wabow.com/wp-content/uploads/2009/11/gotobuy-develop2.png"><img class="alignnone size-thumbnail wp-image-2120" title="gotobuy-develop2" src="http://blog.wabow.com/wp-content/uploads/2009/11/gotobuy-develop2-150x150.png" alt="gotobuy-develop2" width="150" height="150" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.wabow.com/archives/2116/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>[轉載][SVN] 為 Subversion 的 post-commit mail 加入專案名稱</title>
		<link>http://blog.wabow.com/archives/2112</link>
		<comments>http://blog.wabow.com/archives/2112#comments</comments>
		<pubDate>Fri, 02 Oct 2009 12:21:06 +0000</pubDate>
		<dc:creator>jaceju</dc:creator>
				<category><![CDATA[技術分享]]></category>

		<guid isPermaLink="false">http://blog.wabow.com/?p=2112</guid>
		<description><![CDATA[本文轉載自：[SVN] 為 Subversion 的 post-commit mail 加入專案名稱 問題 目前我們公司是用 Subversion 做為版本控管系統，在 commit 時都會需要把版本更新訊息寄送給相關人員，當然這就會用到 post-commit 這個 hook 指令；而在 post-commit 中，我們可以利用 bash 語法去呼叫寄信程式。 不過預設建立好的 Repository 下的 hooks 目錄並沒有這個檔案，我們可以把預設的 post-commit.tmpl 複製成 post-commit ： # cp /path-to-svn-repository/project_name/hooks/post-commit.tmpl /path-to-svn-repository/project_name/hooks/post-commit 至於寄信程式的部份，在 Subversion 的 Source code 裡就提供了一個很有用的 mailer.py ，它可以協助我們寄送 commit 後的訊息。 原來的 post-commit 內容如下： #!/bin/sh &#160; # POST-COMMIT HOOK # (略) &#160; [...]]]></description>
			<content:encoded><![CDATA[<p>本文轉載自：<a href="http://www.jaceju.net/blog/?p=733">[SVN] 為 Subversion 的 post-commit mail 加入專案名稱</a></p>
<h2>問題</h2>
<p>目前我們公司是用 Subversion 做為版本控管系統，在 commit 時都會需要把版本更新訊息寄送給相關人員，當然這就會用到 post-commit 這個 hook 指令；而在 post-commit 中，我們可以利用 bash 語法去呼叫寄信程式。</p>
<p><span id="more-2112"></span></p>
<p>不過預設建立好的 Repository 下的 hooks 目錄並沒有這個檔案，我們可以把預設的 post-commit.tmpl 複製成 post-commit ：</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;"># cp /path-to-svn-repository/project_name/hooks/post-commit.tmpl /path-to-svn-repository/project_name/hooks/post-commit</pre></div></div>

<p>至於寄信程式的部份，在 Subversion 的 Source code 裡就提供了一個很有用的 mailer.py ，它可以協助我們寄送 commit 後的訊息。</p>
<p>原來的 post-commit 內容如下：</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/sh</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># POST-COMMIT HOOK</span>
<span style="color: #666666; font-style: italic;"># (略)</span>
&nbsp;
<span style="color: #007800;">REPOS</span>=<span style="color: #ff0000;">&quot;$1&quot;</span>
<span style="color: #007800;">REV</span>=<span style="color: #ff0000;">&quot;$2&quot;</span>
&nbsp;
commit-email.pl <span style="color: #ff0000;">&quot;<span style="color: #007800;">$REPOS</span>&quot;</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$REV</span>&quot;</span> commit-watchers<span style="color: #000000; font-weight: bold;">@</span>example.org
log-commit.py <span style="color: #660033;">--repository</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$REPOS</span>&quot;</span> <span style="color: #660033;">--revision</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$REV</span>&quot;</span></pre></div></div>

<p>將它修改為：</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/sh    </span>
&nbsp;
<span style="color: #666666; font-style: italic;"># POST-COMMIT HOOK </span>
<span style="color: #666666; font-style: italic;"># (略) </span>
&nbsp;
<span style="color: #007800;">REPOS</span>=<span style="color: #ff0000;">&quot;$1&quot;</span>
<span style="color: #007800;">REV</span>=<span style="color: #ff0000;">&quot;$2&quot;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">/</span>path-to-subversion-source<span style="color: #000000; font-weight: bold;">/</span>tools<span style="color: #000000; font-weight: bold;">/</span>hook-scripts<span style="color: #000000; font-weight: bold;">/</span>mailer<span style="color: #000000; font-weight: bold;">/</span>mailer.py commit <span style="color: #ff0000;">&quot;<span style="color: #007800;">$REPOS</span>&quot;</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$REV</span>&quot;</span>
<span style="color: #666666; font-style: italic;"># log-commit.py --repository &quot;$REPOS&quot; --revision &quot;$REV&quot;</span></pre></div></div>

<p>不過用原始的 mailer.py 有個缺點，主要是它寄送的訊息主旨範例如下：</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">r3214 - branches/2.0</pre></div></div>

<p>這樣在多個專案時，我們就不容易識別這次的更新是哪個專案。</p>
<p>所以我就想透過修改 mailer.py ，讓它產生如下的主旨：</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">[project_name] r3214 - branches/2.0</pre></div></div>

<h2>修改方式</h2>
<p>改法很簡單，有兩個地方要改： (針對 Subversion 版本 1.4.4 原始檔)</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">if</span> commondir:
  <span style="color: #008000;">self</span>.<span style="color: black;">output</span>.<span style="color: black;">subject</span> = <span style="color: #483d8b;">'r%d - in %s: %s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>repos.<span style="color: black;">rev</span>, commondir, dirlist<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">else</span>:
  <span style="color: #008000;">self</span>.<span style="color: black;">output</span>.<span style="color: black;">subject</span> = <span style="color: #483d8b;">'r%d - %s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>repos.<span style="color: black;">rev</span>, dirlist<span style="color: black;">&#41;</span></pre></div></div>

<p>改成：</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">if</span> commondir:
  <span style="color: #008000;">self</span>.<span style="color: black;">output</span>.<span style="color: black;">subject</span> = <span style="color: #483d8b;">'[%s] r%d - in %s: %s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>repos.<span style="color: black;">project_name</span>, repos.<span style="color: black;">rev</span>, commondir, dirlist<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">else</span>:
  <span style="color: #008000;">self</span>.<span style="color: black;">output</span>.<span style="color: black;">subject</span> = <span style="color: #483d8b;">'[%s] r%d - %s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>repos.<span style="color: black;">project_name</span>, repos.<span style="color: black;">rev</span>, dirlist<span style="color: black;">&#41;</span></pre></div></div>

<p>也就是這裡我多加了一個 repos.project_name ，讓信件主旨可以多一個專案名稱。不過 projects_name 並不是 repos 的屬性，所以我們還要再修改一個地方。</p>
<p>往下找到：</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #008000;">self</span>.<span style="color: black;">author</span> = <span style="color: #008000;">self</span>.<span style="color: black;">get_rev_prop</span><span style="color: black;">&#40;</span>svn.<span style="color: black;">core</span>.<span style="color: black;">SVN_PROP_REVISION_AUTHOR</span><span style="color: black;">&#41;</span></pre></div></div>

<p>然後在底下加入一行：</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #008000;">self</span>.<span style="color: black;">project_name</span> = repos_dir<span style="color: black;">&#91;</span><span style="color: #ff4500;">10</span>:<span style="color: black;">&#93;</span></pre></div></div>

<p>其中 10 這個數字是指 /path-to-svn-repository/ 的長度，因為 repos_dir 的內容會是 /path-to-svn-repository/project-name ，而字串是由 0 開始算起，那麼 project_name 的起始位置就會剛好是 /path-to-svn-repository/ 的長度。 (所以請自行計算並更改之)</p>
<p>至於為什麼我會知道 repos_dir 的內容，這是因為我在一開始就用了以下的程式去印出它：</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">f = <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;mailer.log&quot;</span>, <span style="color: #483d8b;">'w'</span><span style="color: black;">&#41;</span>
f.<span style="color: black;">write</span><span style="color: black;">&#40;</span>repos_dir<span style="color: black;">&#41;</span>
f.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>當然這邊要注意縮排。</p>
<h2>結論</h2>
<p>Python 對我來說，其實是一個不熟悉的語言。不過它的語法也不是那麼難以理解，以我這種三流能力，竟然還能看懂並修改它。</p>
<p>而 mailer.py 也大量使用了物件導向的寫法，所以未來有機會在開發 Python 程式時，在物件導向的基礎也是不可或缺的。</p>
<p>就這樣啦~謝謝收看~再會~</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.wabow.com/archives/2112/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[PHP]免費的檔案瀏覽工具 fileNice</title>
		<link>http://blog.wabow.com/archives/2106</link>
		<comments>http://blog.wabow.com/archives/2106#comments</comments>
		<pubDate>Thu, 27 Aug 2009 07:34:03 +0000</pubDate>
		<dc:creator>andrew</dc:creator>
				<category><![CDATA[技術分享]]></category>
		<category><![CDATA[軟體測試]]></category>

		<guid isPermaLink="false">http://blog.wabow.com/?p=2106</guid>
		<description><![CDATA[官方網站 http://filenice.com/ 展示網頁 http://filenice.com/demo/ 介紹 filenice是一套用php編寫的檔案瀏覽工具，作用在你本身如果有架設網站並有某個資料夾提供上傳檔案，當你想要查看這個資料夾中有哪些檔案時，filenice提供使用瀏覽器就可以查看的功能。 安裝 到官網下載檔案(http://filenice.com/demo/fileNice.zip)，下載完畢將解壓縮後的檔案放到網站伺服器上你想要瀏覽檔案的資料夾下即可。 優點 官方的說明是filenice是使用php+javascript也就是所謂的Ajax技術編寫的，因此速度比較快，而且當應用程式忙碌時可以返回而不會整個畫面當掉。此外使用filenice不需要安裝任何資料庫。 感想 filenice提供了無須安裝其他軟體，僅需使用瀏覽器就可觀看主機上提供upload的資料夾下的內容，也可自訂瀏覽檔案的一些排列等細節，另外也提供搜尋的功能。不過個人比較覺得可惜的是，因為無須登入帳密即可觀看，在安全性上稍顯不足，不過或是也因此除了觀看以外，並沒有額外提供刪除或是上傳的功能吧!?介紹給大家用看看!]]></description>
			<content:encoded><![CDATA[<p><img src="http://blog.wabow.com/wp-content/uploads/2009/08/sample10-500x260.gif" alt="sample10" width="500" height="260" class="aligncenter size-large wp-image-2107" /></p>
<p>官方網站  <a href="http://filenice.com/">http://filenice.com/</a><br />
展示網頁  <a href="http://filenice.com/demo/">http://filenice.com/demo/</a><span id="more-2106"></span></p>
<h3>介紹</h3>
<p>filenice是一套用php編寫的檔案瀏覽工具，作用在你本身如果有架設網站並有某個資料夾提供上傳檔案，當你想要查看這個資料夾中有哪些檔案時，filenice提供使用瀏覽器就可以查看的功能。</p>
<h3>安裝</h3>
<p>到官網下載檔案(http://filenice.com/demo/fileNice.zip)，下載完畢將解壓縮後的檔案放到網站伺服器上你想要瀏覽檔案的資料夾下即可。</p>
<h3>優點</h3>
<p>官方的說明是filenice是使用php+javascript也就是所謂的Ajax技術編寫的，因此速度比較快，而且當應用程式忙碌時可以返回而不會整個畫面當掉。此外使用filenice不需要安裝任何資料庫。</p>
<h3>感想</h3>
<p>filenice提供了無須安裝其他軟體，僅需使用瀏覽器就可觀看主機上提供upload的資料夾下的內容，也可自訂瀏覽檔案的一些排列等細節，另外也提供搜尋的功能。不過個人比較覺得可惜的是，因為無須登入帳密即可觀看，在安全性上稍顯不足，不過或是也因此除了觀看以外，並沒有額外提供刪除或是上傳的功能吧!?介紹給大家用看看!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.wabow.com/archives/2106/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>[PHP] PHP 密技： include 與 require</title>
		<link>http://blog.wabow.com/archives/2104</link>
		<comments>http://blog.wabow.com/archives/2104#comments</comments>
		<pubDate>Thu, 27 Aug 2009 07:25:54 +0000</pubDate>
		<dc:creator>jaceju</dc:creator>
				<category><![CDATA[技術分享]]></category>

		<guid isPermaLink="false">http://blog.wabow.com/?p=2104</guid>
		<description><![CDATA[轉載自：[PHP] PHP 密技： include 與 require 可以接受回傳資料？ 先調查一下，知道 include 或 require 可以取得回傳資料的請舉手... (眺望) 呃...不知道的朋友也不用煩惱，我來解釋一下。 如何回傳資料呢？假設現在有個 php 檔叫做 config.php ，內容如下： &#60;?php return array&#40;'123', '456'&#41;; 咦？那邊有人說 return 放錯地方了？不不不， PHP 能接受這樣的寫法。 好，現在我們來證明 include 或 require 能取得 config.php 所 return 回來的資料。請建立一支 test.php ，其內容是： $config = require 'config.php'; var_dump&#40;$config&#41;; 執行看看，是不是可以跑呀？ 所以我們可以在某支 PHP 程式中 return 一個資料 (任何型態) ，然後在另一支 PHP 程式中用 include [...]]]></description>
			<content:encoded><![CDATA[<p>轉載自：<a href="http://www.jaceju.net/blog/?p=316">[PHP] PHP 密技： include 與 require</a></p>
<h2>可以接受回傳資料？</h2>
<p>先調查一下，知道 include 或 require 可以取得回傳資料的請舉手... (眺望)</p>
<p>呃...不知道的朋友也不用煩惱，我來解釋一下。</p>
<p><span id="more-2104"></span></p>
<p>如何回傳資料呢？假設現在有個 php 檔叫做 config.php ，內容如下：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #b1b100;">return</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'123'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'456'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>咦？那邊有人說 return 放錯地方了？不不不， PHP 能接受這樣的寫法。</p>
<p>好，現在我們來證明 include 或 require 能取得 config.php 所 return 回來的資料。請建立一支 test.php ，其內容是：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$config</span> <span style="color: #339933;">=</span> <span style="color: #b1b100;">require</span> <span style="color: #0000ff;">'config.php'</span><span style="color: #339933;">;</span>
<span style="color: #990000;">var_dump</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$config</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>執行看看，是不是可以跑呀？</p>
<p>所以我們可以在某支 PHP 程式中 return 一個資料 (任何型態) ，然後在另一支 PHP 程式中用 include 或 require 來取得這個資料。 </p>
<h2>把 require 放在參數裡 </h2>
<p>什麼？這不是密技？不不不，密技在底下：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> test<span style="color: #009900;">&#40;</span><span style="color: #000088;">$config</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #990000;">var_dump</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$config</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
test<span style="color: #009900;">&#40;</span><span style="color: #b1b100;">require</span> <span style="color: #0000ff;">'config.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>對！你沒看錯！直接把 require 放在函式的參數裡！</p>
<p>還沒完呢，再看：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Test
<span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span><span style="color: #000088;">$config</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #990000;">var_dump</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$config</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000088;">$a</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Test<span style="color: #009900;">&#40;</span><span style="color: #b1b100;">require</span> <span style="color: #0000ff;">'config.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>連 new 建構子的參數都可以接受 require ！</p>
<p>所以只要能放變數的地方，都可以放 include 或 require ，例如：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #b1b100;">require</span> <span style="color: #0000ff;">'config.php'</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #990000;">var_dump</span><span style="color: #009900;">&#40;</span><span style="color: #b1b100;">require</span> <span style="color: #0000ff;">'config.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$config</span> <span style="color: #339933;">=</span> <span style="color: #b1b100;">require</span> <span style="color: #0000ff;">'config.php'</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #990000;">var_dump</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$config</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>而且不僅是 include 及 require ，連 include_once 和 require_once 都可以這麼做。</p>
<p>我在<a href="http://blog.astrumfutura.com/archives/340-The-Zend-Framework,-Dependency-Injection-and-Zend_Di.html">某篇文章</a>發現這個密技以後，分享給辦公室裡的同事們；沒想到玩了 PHP 這麼多年的他們也沒看過這個方法，看來大家對 PHP 的瞭解需要更深入一點囉！</p>
<h2>Scope 的問題 </h2>
<p>接著我同事問了我一個問題：如果在參數使用 require 敘述，而且被 require 的 PHP 程式裡如果有定義全域變數的話，那麼這個變數在執行的 PHP 程式裡，它的 scope 在哪裡呢？</p>
<p>答案是：它還是全域。</p>
<p>怎麼說呢？現在我們在剛剛的 config.php 的 return 敘述前加上一行程式，如下：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000088;">$data</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'789'</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// 加上這行</span>
<span style="color: #b1b100;">return</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'123'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'456'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>然後在 test.php 裡的 Global 部份 (也就是不在函式或類別定義裡) 的任意處加入：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #990000;">var_dump</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>是不是也可以正確顯示 config.php 中 $data 變數所指定的內容呢？這就表示在參數中使用 require 不會影響全域變數的 scope 。</p>
<p>還有其他 include 或 require 的密技嗎？歡迎大家一起討論囉~</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.wabow.com/archives/2104/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>用 PHP 查 DOMAIN 的 CNAME 紀錄</title>
		<link>http://blog.wabow.com/archives/2066</link>
		<comments>http://blog.wabow.com/archives/2066#comments</comments>
		<pubDate>Thu, 27 Aug 2009 06:44:34 +0000</pubDate>
		<dc:creator>suzy</dc:creator>
				<category><![CDATA[軟體測試]]></category>
		<category><![CDATA[cname]]></category>

		<guid isPermaLink="false">http://blog.wabow.com/?p=2066</guid>
		<description><![CDATA[接獲一項來自 Neo 的任務, "用PHP 實作由 CNAME 去判定新加入服務的 DOMAIN 為申請人所有" (證明他不是來亂的). For Example: Google Apps 就是用這個方式去作驗證 CNAME 是 DOMAIN or SUB DOMAIN 指向另一個 DOMAIN 的方式. (跟 alias 一樣) 那麼如果要用 PHP 實作呢? 有兩種方式 : 1. PHP5 內建的 dns_get_record() (Windows &#38; BSD &#38; Mac 不適用) 2. PEAR NET_DNS NET_DNS 原理是用 fsockopen("你的 DNS SERVER IP", 53), 但是要先自己組合出 "封包的header data" [...]]]></description>
			<content:encoded><![CDATA[<p>接獲一項來自 Neo 的任務, "用PHP 實作由 CNAME 去判定新加入服務的 DOMAIN 為申請人所有" (證明他不是來亂的).</p>
<p>For Example:<br />
<a href="http://www.google.com/support/a/bin/answer.py?hl=b5&amp;answer=92354">Google Apps 就是用這個方式去作驗證</a><br />
<span id="more-2066"></span></p>
<p><a href="http://www.google.com.tw/search?hl=zh-TW&amp;q=CNAME">CNAME</a> 是 DOMAIN or SUB DOMAIN 指向另一個 DOMAIN 的方式. (跟 alias 一樣)</p>
<p>那麼如果要用 PHP 實作呢? 有兩種方式 :<br />
1. PHP5 內建的 dns_get_record() (Windows &amp; BSD &amp; Mac 不適用)<br />
2. PEAR <a href="http://pear.php.net/package/Net_DNS">NET_DNS</a></p>
<p>NET_DNS 原理是用 fsockopen("你的 DNS SERVER IP", 53),<br />
但是要先自己組合出 "封包的header data" 再丟過去, DNS Server 才會理你唷.<br />
這些複雜的部份 NET_DNS 已經都幫我們做好了.</p>
<p>我們只要:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">require_once</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Net/DNS.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$ndr</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Net_DNS_Resolver<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$answer</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$ndr</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">search</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;www.OOO.com&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;CNAME&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;pre&gt;&quot;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">print_r</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$answer</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// 獲得的結果</span>
<span style="color: #990000;">Array</span>
<span style="color: #009900;">&#40;</span>
    <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> Net_DNS_RR_CNAME Object
        <span style="color: #009900;">&#40;</span>
            <span style="color: #009900;">&#91;</span>name<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> www<span style="color: #339933;">.</span>OOO<span style="color: #339933;">.</span>co<span style="color: #339933;">.</span>nz
            <span style="color: #009900;">&#91;</span>type<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> CNAME
            <span style="color: #009900;">&#91;</span><span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> IN
            <span style="color: #009900;">&#91;</span>ttl<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">86400</span>
            <span style="color: #009900;">&#91;</span>rdlength<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">18</span>
            <span style="color: #009900;">&#91;</span>rdata<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> store	XXX�<span style="color: #cc66cc;">3</span>
            <span style="color: #009900;">&#91;</span>cname<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> store<span style="color: #339933;">.</span>XXX<span style="color: #339933;">.</span>com
        <span style="color: #009900;">&#41;</span>
&nbsp;
<span style="color: #009900;">&#41;</span></pre></div></div>

<p>PS, 在 Windows 環境, 請修改 PEAR/NET/DNS/Resolver.php 裡的</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">var</span> <span style="color: #000088;">$resolv_conf</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'/etc/resolv.conf'</span><span style="color: #339933;">;</span></pre></div></div>

<p>改成</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">var</span> <span style="color: #000088;">$resolv_conf</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'D:\Appserv\resolv.conf'</span><span style="color: #339933;">;</span></pre></div></div>

<p>resolv.conf 要加入你的 DNS Server (請用 ipconfig /all 查詢)</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">nameserver 168<span style="color: #339933;">.</span>95<span style="color: #339933;">.</span>192<span style="color: #339933;">.</span>1</pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://blog.wabow.com/archives/2066/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[Subversion] Setup In Windows</title>
		<link>http://blog.wabow.com/archives/2067</link>
		<comments>http://blog.wabow.com/archives/2067#comments</comments>
		<pubDate>Thu, 27 Aug 2009 06:41:19 +0000</pubDate>
		<dc:creator>abu</dc:creator>
				<category><![CDATA[技術分享]]></category>

		<guid isPermaLink="false">http://blog.wabow.com/?p=2067</guid>
		<description><![CDATA[版本控管是個相當方便的程式開發好幫手，不管檔案被改到多爛，甚至不小心誤殺，都能輕鬆救回。 平常使用的安裝在哇寶主機上的subversion，這次想嘗試看看將subversion架設在windows平台上，於是開始了尋找資料之旅。 基本上，這裡有很詳細的說明，只要按照個人系統，修改部份設定，以下就紀錄一下我自己的步驟： (因為已經寫的超白話了，所以就不另外附圖) 安裝apache，我是用懶人包xampp直接裝好apache、php、mysql，apache版本2.2.9。  (  範例懶人包安裝的路徑是在c:\xampp\ )     點我下載xampp (版本 1.7.2 ) 下載subversion windows版本，點我下載  (版本 1.6.5 ) ， 安裝很容易，狂點next就對了。 打開C:\xampp\apache\conf\httpd.conf ，隨便找個地方 加入 &#60;Location /svn/repository&#62; DAV svn SVNPath D:\svn\repository &#60;/Location&#62; 其中 /svn/repository 是你想對應到的網址，像是 http://localhost/svn/repository， 而D:\svn\repository 則是實際svn專案檔案放置的位置。 最後，請到windows提供的"命令提示字元"模式下，輸入 svnadmin create d:/svn/repository ，完成建立專案，到這裡算是完成建立整個專案。 打開瀏覽器，輸入http://localhost:8080/svn/repository/ ，可以看到 『 repository - Revision 0: / 』，代表該專案目前版號為0 (還沒開始動工，當然是0) 測試一下，先隨便找個地方，例如 D:\wwwroot\ ，滑鼠右鍵選擇『 SVN 取出 [...]]]></description>
			<content:encoded><![CDATA[<p>版本控管是個相當方便的程式開發好幫手，不管檔案被改到多爛，甚至不小心誤殺，都能輕鬆救回。<span id="more-2067"></span></p>
<p>平常使用的安裝在哇寶主機上的subversion，這次想嘗試看看將subversion架設在windows平台上，於是開始了尋找資料之旅。<br />
基本上，<a href="http://liangkuo.blogspot.com/2007/03/svn-subversion-tortoisesvn.html">這裡</a>有很詳細的說明，只要按照個人系統，修改部份設定，以下就紀錄一下我自己的步驟：</p>
<p>(因為已經寫的超白話了，所以就不另外附圖)  </p>
<ul>
<li> 安裝apache，我是用懶人包xampp直接裝好apache、php、mysql，apache版本2.2.9。  (  範例懶人包安裝的路徑是在c:\xampp\ )     <a href="http://www.apachefriends.org/download.php?xampp-win32-1.7.2.exe">點我下載xampp</a> (版本 1.7.2 )</li>
<li>下載subversion windows版本，<a href="http://subversion.tigris.org/files/documents/15/46531/Setup-Subversion-1.6.5.msi">點我下載</a>  (版本 1.6.5 ) ， 安裝很容易，狂點next就對了。</li>
<li>打開C:\xampp\apache\conf\httpd.conf ，隨便找個地方 加入
<pre lang="html4strict" escaped="ture">
  &lt;Location /svn/repository&gt;
    DAV svn
    SVNPath D:\svn\repository
  &lt;/Location&gt;
</pre>
<p>其中 /svn/repository 是你想對應到的網址，像是 http://localhost/svn/repository， 而D:\svn\repository 則是實際svn專案檔案放置的位置。</li>
<li>最後，請到windows提供的"命令提示字元"模式下，輸入 svnadmin create d:/svn/repository ，完成建立專案，到這裡算是完成建立整個專案。</li>
<li>打開瀏覽器，輸入http://localhost:8080/svn/repository/ ，可以看到 『 repository - Revision 0: / 』，代表該專案目前版號為0 (還沒開始動工，當然是0)</li>
<li>測試一下，先隨便找個地方，例如 D:\wwwroot\ ，滑鼠右鍵選擇『 SVN 取出 』，檔案庫URL 請輸入 『 http://localhost:8080/svn/repository 』，取出目錄按照預設即可，按下確定。</li>
<li>到D:\wwwroot\repository，測試建立一個文字檔， aaa.txt ，同樣路徑下按滑鼠右鍵『 SVN 送交 』，將更新的檔案傳送至SVN檔案庫，完成測試SVN上傳。</li>
<li>同樣來到 http://localhost:8080/svn/repository/ ，會看到『 repository - Revision 1: / 』，版號以由0變成1，代表剛上傳的svn紀錄已完成。</li>
<p>以上就是依照個人設定，完成subversion安裝在windows的過程，看到專案是使用自己架設的subversion，檔案成功被建立、刪除修改後更新，感覺還不錯～</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.wabow.com/archives/2067/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>[分享] 垃圾留言判斷，隱藏驗證碼的 NoSpamNX class PART2</title>
		<link>http://blog.wabow.com/archives/2072</link>
		<comments>http://blog.wabow.com/archives/2072#comments</comments>
		<pubDate>Thu, 27 Aug 2009 06:32:14 +0000</pubDate>
		<dc:creator>daniel</dc:creator>
				<category><![CDATA[技術分享]]></category>
		<category><![CDATA[NoSpamNX]]></category>
		<category><![CDATA[垃圾留言]]></category>

		<guid isPermaLink="false">http://blog.wabow.com/?p=2072</guid>
		<description><![CDATA[感謝上一篇文章中前輩們的熱心回覆；垃圾留言果然是大家心中的痛啊（噗）～雖然 CAPTCHA 可以透過各式各樣的 OCR 破解（最新版的 JDownloader 也已經能忽略大部分免費空間所用的圖像辨識...扯遠了），不過它仍是目前阻擋機器人最直接也最簡單的解決方案；當然更複雜的 CAPTCHA 還是能夠達到阻擋的目的，但是使用 CAPTCHA 的方式對使用者來說就已經是不友善了。 後來在討論中 Jace 提到，其實 SESSION 是有可能被機器人知道的；所以我後來綜合了 fillano 提供的演算法概念，稍微改良了一下之前的 NoSpamNX class。利用隨機產生的隱藏欄位順序，用不同的演算法再對隱藏欄位的數值作編碼；讓 SESSION 內存的未編碼的值，與 POST 過來的已編碼的值不一樣。最後再將 SESSION 內存的值編碼，與 POST 的已編碼的值作比較，判斷留言的使用者是不是機器人。 SESSION 紀錄的值是未編碼的值，但在產生隱藏欄位時，input 的值是已經編碼過後的值 /** &#xa0;* 建立隱藏欄位 HTML；利用隱藏欄位先後順序不同，使用 md5 or sha1 編碼 &#xa0;* &#xa0;*/ public function addHiddenFields() { &#xa0;&#xa0;&#xa0;&#xa0;$nospamnx = $_SESSION[$this-&#62;_sessionName]; &#xa0;&#xa0;&#xa0;&#xa0;if (1 === rand(1,2)) { &#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;return '&#60;input [...]]]></description>
			<content:encoded><![CDATA[<p>感謝<a href="http://blog.wabow.com/archives/1974" target="_blank">上一篇文章</a>中前輩們的熱心回覆；垃圾留言果然是大家心中的痛啊（噗）～雖然 <a href="http://zh.wikipedia.org/w/index.php?title=CAPTCHA&amp;variant=zh-tw" target="_blank">CAPTCHA</a> 可以透過各式各樣的 <a href="http://zh.wikipedia.org/zh-tw/%E5%85%89%E5%AD%A6%E5%AD%97%E7%AC%A6%E8%AF%86%E5%88%AB" target="_blank">OCR</a> 破解（最新版的 <a href="http://jdownloader.org/home/index" target="_blank">JDownloader</a> 也已經能忽略大部分免費空間所用的圖像辨識...扯遠了），不過它仍是目前阻擋機器人最直接也最簡單的解決方案；當然更複雜的 CAPTCHA 還是能夠達到阻擋的目的，但是使用 CAPTCHA 的方式對使用者來說就已經是不友善了。</p>
<p>後來在討論中 Jace 提到，其實 SESSION 是有可能被機器人知道的；所以我後來綜合了 fillano 提供的演算法概念，稍微改良了一下之前的 NoSpamNX class。利用隨機產生的隱藏欄位順序，用不同的演算法再對隱藏欄位的數值作編碼；讓 SESSION 內存的未編碼的值，與 POST 過來的已編碼的值不一樣。最後再將 SESSION 內存的值編碼，與 POST 的已編碼的值作比較，判斷留言的使用者是不是機器人。</p>
<p><span id="more-2072"></span>SESSION 紀錄的值是未編碼的值，但在產生隱藏欄位時，input 的值是已經編碼過後的值</p>
<pre style='color:#000020;background:#cceeee;overflow:auto;border:1px solid silver'>
<span style='color:#595979;background:#cceeee'>/**</span>
<span style='color:#595979;background:#cceeee'>&#xa0;* 建立隱藏欄位 HTML；利用隱藏欄位先後順序不同，使用 md5 or sha1 編碼</span>
<span style='color:#595979;background:#cceeee'>&#xa0;* </span>
<span style='color:#595979;background:#cceeee'>&#xa0;*/</span>
<span style='color:#200080;background:#cceeee;font-weight:bold'>public</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#200080;background:#cceeee;font-weight:bold'>function</span><span style='color:#000000;background:#cceeee'> addHiddenFields</span><span style='color:#308080;background:#cceeee'>(</span><span style='color:#308080;background:#cceeee'>)</span><span style='color:#000000;background:#cceeee'></span>
<span style='color:#406080;background:#cceeee'>{</span><span style='color:#000000;background:#cceeee'></span>
<span style='color:#000000;background:#cceeee'>&#xa0;&#xa0;&#xa0;&#xa0;</span><span style='color:#007d45;background:#cceeee'>$nospamnx</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#308080;background:#cceeee'>=</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#007d45;background:#cceeee'>$_SESSION</span><span style='color:#308080;background:#cceeee'>[</span><span style='color:#007d45;background:#cceeee'>$</span><span style='color:#200080;background:#cceeee;font-weight:bold'>this</span><span style='color:#308080;background:#cceeee'>-&gt;</span><span style='color:#007d45;background:#cceeee'>_sessionName</span><span style='color:#308080;background:#cceeee'>]</span><span style='color:#406080;background:#cceeee'>;</span><span style='color:#000000;background:#cceeee'></span>
<span style='color:#000000;background:#cceeee'></span>
<span style='color:#000000;background:#cceeee'>&#xa0;&#xa0;&#xa0;&#xa0;</span><span style='color:#200080;background:#cceeee;font-weight:bold'>if</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#308080;background:#cceeee'>(</span><span style='color:#008c00;background:#cceeee'>1</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#308080;background:#cceeee'>=</span><span style='color:#308080;background:#cceeee'>=</span><span style='color:#308080;background:#cceeee'>=</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#400000;background:#cceeee'>rand</span><span style='color:#308080;background:#cceeee'>(</span><span style='color:#008c00;background:#cceeee'>1</span><span style='color:#308080;background:#cceeee'>,</span><span style='color:#008c00;background:#cceeee'>2</span><span style='color:#308080;background:#cceeee'>)</span><span style='color:#308080;background:#cceeee'>)</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#406080;background:#cceeee'>{</span><span style='color:#000000;background:#cceeee'></span>
<span style='color:#000000;background:#cceeee'>&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;</span><span style='color:#200080;background:#cceeee;font-weight:bold'>return</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#1060b6;background:#cceeee'>'&lt;input type="text" name="nospamnx['</span><span style='color:#308080;background:#cceeee'>.</span><span style='color:#007d45;background:#cceeee'>$nospamnx</span><span style='color:#308080;background:#cceeee'>[</span><span style='color:#1060b6;background:#cceeee'>'nospamnx-1'</span><span style='color:#308080;background:#cceeee'>]</span><span style='color:#308080;background:#cceeee'>.</span><span style='color:#1060b6;background:#cceeee'>']" value="" class="locktross" /&gt;&lt;input type="text" name="nospamnx['</span><span style='color:#308080;background:#cceeee'>.</span><span style='color:#007d45;background:#cceeee'>$nospamnx</span><span style='color:#308080;background:#cceeee'>[</span><span style='color:#1060b6;background:#cceeee'>'nospamnx-2'</span><span style='color:#308080;background:#cceeee'>]</span><span style='color:#308080;background:#cceeee'>.</span><span style='color:#1060b6;background:#cceeee'>']" value="'</span><span style='color:#308080;background:#cceeee'>.</span><span style='color:#400000;background:#cceeee'>md5</span><span style='color:#308080;background:#cceeee'>(</span><span style='color:#007d45;background:#cceeee'>$nospamnx</span><span style='color:#308080;background:#cceeee'>[</span><span style='color:#1060b6;background:#cceeee'>'nospamnx-2-value'</span><span style='color:#308080;background:#cceeee'>]</span><span style='color:#308080;background:#cceeee'>)</span><span style='color:#308080;background:#cceeee'>.</span><span style='color:#1060b6;background:#cceeee'>'" class="locktross" /&gt;'</span><span style='color:#406080;background:#cceeee'>;</span><span style='color:#000000;background:#cceeee'></span>
<span style='color:#000000;background:#cceeee'>&#xa0;&#xa0;&#xa0;&#xa0;</span><span style='color:#406080;background:#cceeee'>}</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#200080;background:#cceeee;font-weight:bold'>else</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#406080;background:#cceeee'>{</span><span style='color:#000000;background:#cceeee'></span>
<span style='color:#000000;background:#cceeee'>&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;</span><span style='color:#200080;background:#cceeee;font-weight:bold'>return</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#1060b6;background:#cceeee'>'&lt;input type="text" name="nospamnx['</span><span style='color:#308080;background:#cceeee'>.</span><span style='color:#007d45;background:#cceeee'>$nospamnx</span><span style='color:#308080;background:#cceeee'>[</span><span style='color:#1060b6;background:#cceeee'>'nospamnx-2'</span><span style='color:#308080;background:#cceeee'>]</span><span style='color:#308080;background:#cceeee'>.</span><span style='color:#1060b6;background:#cceeee'>']" value="'</span><span style='color:#308080;background:#cceeee'>.</span><span style='color:#400000;background:#cceeee'>sha1</span><span style='color:#308080;background:#cceeee'>(</span><span style='color:#007d45;background:#cceeee'>$nospamnx</span><span style='color:#308080;background:#cceeee'>[</span><span style='color:#1060b6;background:#cceeee'>'nospamnx-2-value'</span><span style='color:#308080;background:#cceeee'>]</span><span style='color:#308080;background:#cceeee'>)</span><span style='color:#308080;background:#cceeee'>.</span><span style='color:#1060b6;background:#cceeee'>'" class="locktross" /&gt;&lt;input type="text" name="nospamnx['</span><span style='color:#308080;background:#cceeee'>.</span><span style='color:#007d45;background:#cceeee'>$nospamnx</span><span style='color:#308080;background:#cceeee'>[</span><span style='color:#1060b6;background:#cceeee'>'nospamnx-1'</span><span style='color:#308080;background:#cceeee'>]</span><span style='color:#308080;background:#cceeee'>.</span><span style='color:#1060b6;background:#cceeee'>']" value="" class="locktross" /&gt;'</span><span style='color:#406080;background:#cceeee'>;</span><span style='color:#000000;background:#cceeee'></span>
<span style='color:#000000;background:#cceeee'>&#xa0;&#xa0;&#xa0;&#xa0;</span><span style='color:#406080;background:#cceeee'>}</span><span style='color:#000000;background:#cceeee'></span>
<span style='color:#406080;background:#cceeee'>}</span><span style='color:#000000;background:#cceeee'></span>
</pre>
<p>驗證時根據 POST 過來的 nospamnx 順序不同，以不同的演算法編碼後再做比較</p>
<pre style='color:#000020;background:#cceeee;overflow:auto;border:1px solid silver'>
<span style='color:#595979;background:#cceeee'>// 根據 POST 過來的值順序不同，以 md5 or sha1 判斷</span><span style='color:#000000;background:#cceeee'></span>
<span style='color:#200080;background:#cceeee;font-weight:bold'>if</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#308080;background:#cceeee'>(</span><span style='color:#007d45;background:#cceeee'>$nospamnx</span><span style='color:#308080;background:#cceeee'>[</span><span style='color:#1060b6;background:#cceeee'>'nospamnx-1'</span><span style='color:#308080;background:#cceeee'>]</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#308080;background:#cceeee'>=</span><span style='color:#308080;background:#cceeee'>=</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#400000;background:#cceeee'>current</span><span style='color:#308080;background:#cceeee'>(</span><span style='color:#400000;background:#cceeee'>array_keys</span><span style='color:#308080;background:#cceeee'>(</span><span style='color:#007d45;background:#cceeee'>$postData</span><span style='color:#308080;background:#cceeee'>)</span><span style='color:#308080;background:#cceeee'>)</span><span style='color:#308080;background:#cceeee'>)</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#406080;background:#cceeee'>{</span><span style='color:#000000;background:#cceeee'></span>
<span style='color:#000000;background:#cceeee'>&#xa0;&#xa0;&#xa0;&#xa0;</span><span style='color:#007d45;background:#cceeee'>$encode_value</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#308080;background:#cceeee'>=</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#400000;background:#cceeee'>md5</span><span style='color:#308080;background:#cceeee'>(</span><span style='color:#007d45;background:#cceeee'>$nospamnx</span><span style='color:#308080;background:#cceeee'>[</span><span style='color:#1060b6;background:#cceeee'>'nospamnx-2-value'</span><span style='color:#308080;background:#cceeee'>]</span><span style='color:#308080;background:#cceeee'>)</span><span style='color:#406080;background:#cceeee'>;</span><span style='color:#000000;background:#cceeee'></span>
<span style='color:#406080;background:#cceeee'>}</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#200080;background:#cceeee;font-weight:bold'>else</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#406080;background:#cceeee'>{</span><span style='color:#000000;background:#cceeee'></span>
<span style='color:#000000;background:#cceeee'>&#xa0;&#xa0;&#xa0;&#xa0;</span><span style='color:#007d45;background:#cceeee'>$encode_value</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#308080;background:#cceeee'>=</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#400000;background:#cceeee'>sha1</span><span style='color:#308080;background:#cceeee'>(</span><span style='color:#007d45;background:#cceeee'>$nospamnx</span><span style='color:#308080;background:#cceeee'>[</span><span style='color:#1060b6;background:#cceeee'>'nospamnx-2-value'</span><span style='color:#308080;background:#cceeee'>]</span><span style='color:#308080;background:#cceeee'>)</span><span style='color:#406080;background:#cceeee'>;</span><span style='color:#000000;background:#cceeee'></span>
<span style='color:#406080;background:#cceeee'>}</span><span style='color:#000000;background:#cceeee'></span>
<span style='color:#200080;background:#cceeee;font-weight:bold'>if</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#308080;background:#cceeee'>(</span><span style='color:#007d45;background:#cceeee'>$postData</span><span style='color:#308080;background:#cceeee'>[</span><span style='color:#007d45;background:#cceeee'>$nospamnx</span><span style='color:#308080;background:#cceeee'>[</span><span style='color:#1060b6;background:#cceeee'>'nospamnx-2'</span><span style='color:#308080;background:#cceeee'>]</span><span style='color:#308080;background:#cceeee'>]</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#308080;background:#cceeee'>!</span><span style='color:#308080;background:#cceeee'>=</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#007d45;background:#cceeee'>$encode_value</span><span style='color:#308080;background:#cceeee'>)</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#406080;background:#cceeee'>{</span><span style='color:#000000;background:#cceeee'></span>
<span style='color:#000000;background:#cceeee'>&#xa0;&#xa0;&#xa0;&#xa0;</span><span style='color:#200080;background:#cceeee;font-weight:bold'>return</span><span style='color:#000000;background:#cceeee'> </span><span style='color:#200080;background:#cceeee;font-weight:bold'>false</span><span style='color:#406080;background:#cceeee'>;</span><span style='color:#000000;background:#cceeee'></span>
<span style='color:#406080;background:#cceeee'>}</span><span style='color:#000000;background:#cceeee'></span>
</pre>
<p>最後提供<a href="http://blog.wabow.com/wp-content/uploads/2009/08/nospamnx_090827.zip">範例程式下載</a>，分為一般 POST 與 AJAX 二種方式。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.wabow.com/archives/2072/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
