2008年12月31日 星期三

明年第一季Android Market將正式開放付費性商品

以下節錄自Google寄送的Mail:

Additionally, I would like to confirm that Android Market will support priced applications starting early Q1 2009, as we'd originally stated last fall. Given the country-by-country work required to set up payment support for developers in different countries, we will enable priced app support in Q1 for developers operating in these countries in the following order: (1) United States and UK; (2) Germany, Austria and Netherlands; (3) France, Italy and Spain. By the end of Q1 2009, we will announce support for developers operating in additional countries. Developers operating in the above listed countries should begin finalizing their priced applications, including determining the appropriate pricing strategy.

從明年第一季開始Android Market會開始實施去年秋天就原本要執行的付費軟體計畫, 由於國家間交易需要支援設定付款方式, 我們將先開放以下國家(1) United States and UK; (2) Germany, Austria and Netherlands; (3)France, Italy and Spain, 等到第一季尾聲則會再宣布開放更多的國家加入。

2008年12月30日 星期二

RIA 設計小技巧 (使用自訂事件)

如果你目前在寫一些ActionScript3.0 based RIA的程式, 但是你卻是寫在影格上或是視窗間要溝通時設計成互相知道對方的話, 你應該要學起來下面的做法, 基本上這已經是標準動作了。

首先創建ModelLocator, 它的作用等於所有事件的轉運站, 所以內部採用Singleton模式, 外部調用時使用static方法getInstance(), 尚未創建則創建並返回, 若已經存在則返回該物件。

package {
    import flash.events.EventDispatcher;

    public class ModelLocator extends EventDispatcher {

        private static var _instance:ModelLocator;

        public function ModelLocator() {
        }

        public static function getInstance():ModelLocator {
            if (! _instance) {
                _instance = new ModelLocator();
            }
            return _instance;
        }
    }
}

再來是自訂事件CustomEvent, 它繼承Event使用type字串作為旗標, 第二個參數為varargs, 可以定義符合自己需求的data.

package {
    import flash.events.Event;

    public class CustomEvent extends Event {

        public var data:* ="default data";// default data  
        public var msg:* ="default msg";// default message  
        
        // EventType, data, message  
        public function CustomEvent(type:String, ... args) {
            super(type, true, true);
            if (args) {
                if (args[0]!=undefined) {
                    this.data=args[0];
                }// if( args[1] != undefined ) this.msg = args[1];  
                // 以此類推  
            }
        }
    }
}

使用方式為:

發送:

model.dispatchEvent( new CustomEvent("RECEIVE_OK", "you've send a message") );

接收:

var model:ModelLocator = ModelLocator.getInstance();  
model.addEventListener("RECEIVE_OK", onReceiveOK);  
function onReceiveOK(evt:CustomEvent):void  
{  
    trace(evt.data);  
}

用完一樣要適時的removeEventListener, 否則會造成資源浪費。

2008年12月29日 星期一

Android上的中文輸入

睡覺前玩了一下手機發現科科輸入法有人改進了變成"嫩科科"輸入法, 有完整的注音鍵盤, 蠻不錯用的, 只有滑蓋後沒有變成橫向螢幕這個小缺點。
使用的時候按著注音鍵滑上下左右選注音與輕重音。按menu複製出去。

長期在電腦前工作請注意!

做我們這行的最常看到就是眼壓過高,而且週邊的同事或長官只要是長期在電腦前工作的小孩子生出來都是女生居多。女生是很好啦, 但是生不出男生可能會有人覺得不太好^^ 所以請大家要注意一下:

電腦對人類健康的隱患,從輻射類型來看,主要包括電腦在工作時產生和發出的電磁輻射(各種電磁射線和電磁波等)、聲(噪音)、光(紫外線、紅外線輻射以及可見光等)等多種輻射「污染」。

從輻射根源來看,它們包括CRT顯示器輻射源、機箱輻射源以及音箱、打印機、複印機等周邊設備輻射源。其中CRT(陰極射線管)顯示器的成像原理,決定了它在使用過程中難以完全消除有害輻射。因為它在工作時,其內部的高頻電子槍、偏轉線圈、高壓包以及周邊電路,會產生諸如電離輻射(低能X射線)、非電離輻射(低頻、高頻輻射)、靜電電場、光輻射(包括紫外線、紅外線輻射和可見光等)等多種射線及電磁波。

而液晶顯示器則是利用液晶的物理特性,其工作原理與CRT顯示器完全不同,天生就是無輻射(可忽略不計)、環保的「健康」型顯示器;機箱內部的各種部件,包括高頻率、功耗大的CPU,帶有內部集成大量晶體管的主芯片的各個板卡,帶有高速直流伺服電機的光驅、軟驅和硬盤,若干個散熱風扇以及電源內部的變壓器等等,工作時則會發出低頻電磁波等輻射和噪音干擾。另外,外置音箱、複印機等周邊設備輻射源也是一個不容忽視的「源頭」。

從危害程度來看,無疑以電磁輻射的危害最大。國內外醫學專家的研究表明,長期、過量的電磁輻射會對人體生殖系統、神經系統和免疫系統造成直接傷害,是心血管疾病、糖尿病、癌突變的主要誘因和造成孕婦流產、不育、畸胎等病變的誘發因素,並可直接影響未成年人的身體組織與骨骼的發育,引起視力、記憶力下降和肝臟造血功能下降,嚴重者可導致視網膜脫落。

此外,電磁輻射也對信息安全造成隱患,利用專門的信號接收設備即可將其接收破譯,導致信息洩密而造成不必要的損失。過量的電磁輻射還會干擾周圍其他電子設備,影響其正常運作而發生電磁兼容性(EMC)問題。

因此,電磁輻射已被世界衛生組織列為繼水源、大氣、噪聲之後的第四大環境污染源,成為危害人類健康的隱形「殺手」,防護電磁輻射已成當務之急。

對於電腦的電磁輻射的危害,目前可採取主動防護和被動防護兩種方法。被動防護法,就是除了改善工作環境和注意使用方法外,採取給經常接觸和操作電腦的人員配備防輻射服、防輻射屏、防輻射窗簾、防輻射玻璃等措施,以減少或杜絕電磁輻射的傷害;主動防護法,則是從電腦電磁輻射的「源頭」——顯示器和機箱等部件下手,將其消滅或屏蔽。

一是購買,即選購市面上實力廠家推出的符合「綠色電腦」標準的產品;二是DIY,即選購通過各種認證標準的「綠色」電腦配件,打造自己的健康電腦。下面我們就重點探討如何選擇符合防輻射標準的配件來DIY健康電腦。

使用電腦時,要調整好螢幕的亮度,一般來說,螢幕亮度越大,電磁輻射越強,反之越小。不過,也不能調得太暗,以免因亮度太小而影響收視效果,且易造成眼睛疲勞。

在操作電腦時,要注意與螢幕保持適當距離。離螢幕越近,人體所受的電磁輻射越大,因此較好的是距螢幕0.5M以外。

此外,在操作電腦後,臉上會吸附不少電磁輻射的顆粒,要及時用清水洗臉,這樣將使所受輻射減輕70%以上。 還有一種是喝茶

常用電腦的人中有83%感到眼睛疲勞,64%經常感到肩酸腰痛,另外,不少人出現流淚、食慾不振、咽喉痛、咳嗽、胸悶等症狀,甚至行動遲緩,記憶力衰退。

電腦輻射不僅危害人的健康,而且影響到工作的質量和效率。對於生活緊張而忙碌的人群來說,抵禦電腦輻射最簡單的辦法就是在每天上午喝2至3杯的綠茶,吃一個橘子。茶葉中含有豐富的維生素A原,它被人體吸收後,能迅速轉化為維生素A。維生素A不但能合成視紫紅質,還能使眼睛在暗光下看東西更清楚,因此,綠茶不但能消除電腦輻射的危害,還能保護和提高視力。如果不習慣喝綠茶,菊花茶同樣也能起著抵抗電腦輻射和調節身體功能的作用

2008年12月26日 星期五

MySQL的優化調效與應用層注意事項

一. 系統參數

1. key_buffer_size ->

係與索引塊的緩衝區大小息息相關,故將之設定為較大後,對於來自於所有用戶執行緒的讀寫處理能力,自然有所助益,但一旦設定的太大,反而會拖累系統的執行效能。

系統的默認值為8MB,可抓系統主機記憶體容量的1/5(註:假設伺服器具2GB記憶體,則以400MB為基準)。

2. back_log ->

該數值的主要意義,指MySQL暫時停止回應新請求之前的短暫時間內可允許多少個請求,被存放於堆疊之中。
期望在短暫時間內能夠連結到較多的請求數量,或在主機進程列表當中發現到大量的等待連接進程時,則可把back_log值予以增加。
但不能無限上綱地擴大,因為作業系統對於接收TCP/IP連接的listen queue大小有其上限。
系統所默認的back_log值為50,只要不把它調到10倍(亦即500)以上,通常不會有太大問題。

3. max_connections ->

若擔心系統所承受的同時上線使用人數過多,導致經常出現「Too many connections」錯誤的話,則可考量將max_connections數值從Default的100加以提高。

4. interactive_timeout ->

系統在面對1個交互連接行為上,所產生的等待時間,以秒為單位,而系統默認值為28800,此時不妨將之調低,改為14400或7200都可,旨在降低其於交互連接過程中的等待秒數。

5. sort_buffer ->

系統在面對所有需要被排序的執行緒,即可個別分配較大的緩衝區,從而提升ORDER BY或GROUP BY的行進速度。 系統默認值僅2MB,可考慮提高到8MB或16MB。

6. table_cache ->

代表所有執行緒在開啟表單時,所能支撐的檔描述符總量,而MySQL每開啟1個表,便需要搭配2個檔描述符。 系統默認值為64,可考慮調整為256或512。

7. record_buffer ->

倘若數值愈大,則每個刻正接受掃描的表單,便可分配到較大的緩衝區,從而加速順序掃描作業之運行。 而系統默認值是128KB,可將之大幅調高到8MB或16MB無妨。

二. 以JOIN取代Sub-Queries

不可諱言,透過子查詢方式,將可1次性地搞定許多邏輯上原需多步驟方能完成的SQL操作,且能一併脫離事務或表單的閉鎖效應,更難能可貴的是,撰寫的難度也不算高。
只不過,在多數情況下,用戶也不妨考慮採用效率更高的連接方式,藉以取代子查詢。系統管理員一旦運用連接後,將不難發現到,查詢速度將比以前快上許多。

三. 慎選欄位屬性

當使用者在建立表單時,基於追求高效能考量,一定得注意表單中欄位的寬度,必須儘可能把它設定得小一些。 有關整數型(INT)欄的定義,採用MEDIUMINT會比採用BIGINT來得好,而能夠以CHAR(6)定義的欄位,便犯不著將之設定為CHAR(255)甚或VARCHAR,因為後兩者都會佔據一些無謂的資料庫空間。

此外,當面對一些諸如「性別」、「縣市」等文本欄位元時,可以考慮將之定義為ENUM型態,此乃由於,在MySQL資料量的運作過程中,ENUM類型會被當做數值型資料來加以處理,而系統對於數值型資料的處理效率,絕對比處理文本類型資料的速度要來得快。

另一方面,使用者亦須培養1個觀念,亦即儘可能將欄位設定為NOT NULL,如此一來,資料庫系統在查詢作業的過程裡頭,便無須再就NULL值進行比較,執行速度也將之加快。

四. 考慮以UNION替代臨時表

自MySQL 4.0版系統開始,便支援聯合(UNION)查詢功能,亦即可將所有原本需要採用臨時表的2條或更多條的SELECT查詢,合併至單一查詢程式之中,而待用戶查詢會話結束後,臨時表將隨即被自動刪除,據此保持資料庫的整齊一致性,並有助效率的提升。

五. 採用事務語法

舉個簡單的例子,當用戶欲將1筆資料,同時插入2個相互關聯的表單時,萬一第1個表單中成功更新之後,資料庫系統出現突發性意外,導致第2個表單中的操作無法順利完成,則資料庫系統裡頭的資料,便將趨於不完整,甚至遭致破壞。
要想避免此類狀況產生,別無他法,只能採用事務語法,確保整個系列語句之中的每條語句,都能一齊「成功」或一齊「失敗」,如此一來,資料庫當中的資料,其一致性與完整性便無遭致破壞之虞。

事務語法係以BEGIN關鍵字來出發,並以COMMIT關鍵字作為結束,此行進的過程中,任1條SQL語句操作失敗的話,只消透過ROLLBACK命令,即可將資料庫回復至BEGIN開始之前的狀態。

BEGIN;
INSERT INTO ....
COMMIT;
六. 透過鎖定表 避免延遲衝擊

即便透過事務語法,堪稱維持資料庫完整性的理想途徑,然其畢竟具有「獨佔」之意涵,在有些情況下,特別是處於大型應用環境當中,便可能影響資料庫效能,
究其主因,在於事務語法執行的過程中,致使資料庫遭到鎖定,故對於其他用戶的請求,也僅能暫時等待到該事務結束才能進行。

倘若該資料庫系統僅少數使用者所採用,此一影響即不會成為大問題,但萬一有眾多使用者同時訪問資料庫的話,則延遲現象便將趨於嚴重。

為解決這個問題,系統管理員不妨採用鎖定表的方式,藉以獲致較佳效能,譬如下例,即是以此方式,來實現與前述(註:採用事務語法)的相同目的。

LOCK TABLE inventory WRITE
SELECT ....
UPDATE ....
UNLOCK TABLES

七. 藉由外鍵(FOREIGN KEY)做法 保持資料關聯性

一旦使用外鍵,便可確保customerinfo表中的 CustomerID,都能鏡射至salesinfo表中CustomerID,其間若有任1條缺乏合法CustomerID的記錄,絕對不會被插入或更新至salesinfo表單裡頭,如同下列步驟。

CREATE TABLE customerinfo
(
CustomerID INT NOT NULL,
PRIMARY KEY(CustomerID)
) TYPE=INNODB;

CREATE TABLE salesinfo
(
SalesID INT NOT NULL,
CustomerID INT NOT NULL,
PRIMARY KEY(CustomerID, SalesID),
FOREIGN KEY(CustomerID) REFERENCES customerinfo(CustomerID) ON DELETECASCADE
) TYPE=INNODB;

ON DELETE CASCADE參數的主要功能,係確保當customerinfo表單之中的任1條客戶記錄遭到刪除時,salesinfo表單裡頭所有與該客戶相關聯的記錄,也將一併被自動刪除。
欲於MySQL系統中採用外鍵,系統管理者務必得留意,在建立表單時,應將表單類型定義為InnoDB。

八. 針對適當欄位元建立索引

事實上,索引絕對可謂增進資料庫效能所慣用之方式,特別是在查詢語句當中,若含括了MAX(), MIN()或ORDERBY等命令時,效能提升的效果尤其顯著。
多數情況下,索引應被建立在一些將被套用於JOIN, WHERE判斷、以及ORDER BY排序的欄位上,而儘量不要出現在資料庫當中某個內含大量重複數值的欄位,
尤其對於ENUM型態的欄位而言,會出現大量重複值,在這般欄位元上建立索引,不僅不會產生任何助益,反倒可能降低資料庫效能。
對於大型資料庫而言,把資料裝載至缺乏FULLTEXT索引的表單中,接著透過ALTER TABLE或CREATE INDEX來建立索引,其實速度會非常快。

九. SQL語句優化

> 語句中沒有使用函數的速度會比有函數的快。

> like 語句使用就查詢方式而論,將會就表單當中的每1條記錄逐一比較,執行速度並不理想。

SELECT * FROM TEST_TABLE WHERE name LIKE "Database%"

但透過下列全不採用LIKE關鍵字或是通配符號的查詢方式,所得查詢結果亦無異於前例,但在執行速度方面,顯然就高明許多。

SELECT * FROM TEST_TABLE WHERE name>= "Database" and name < "Databasf"

> 只查詢你需要的欄位,而不是 SELECT *.

> 處理複雜的數據時,善用臨時資料表(temporary tables).

> 越少聯合資料表查詢越好.

> 使用正確的數據類型, 不要把所有數據都加上引號, 數據庫會因為要把數據轉化為正確的類型而變慢.

> 循環查詢, 最常見到的問題。所謂循環查詢是指在迴圈中執行的查詢,這是非常消耗資源的做法,而且很多時候是絕對不需要的。

循環查詢的錯誤例子

if (isset($_GET['ids'])) {
foreach($_GET['ids'] as $id) {
$rs = mysql_query('SELECT * FROM my_table WHERE my_id = ' . (int) $id);
$row = mysql_fetch_assoc($rs);
print_r($row);
}
}

改正這個錯誤例子

if (isset($_GET['ids'])) {
$ids = array_map('intval', $_GET['ids']);
$ids = implode(',', $ids);
$rs = mysql_query('SELECT * FROM my_table WHERE my_id IN (' . $ids . ')');
while($row = mysql_fetch_assoc($rs)) {
print_r($row);
}
}

十. 資料庫設計

很多時候你會發現資料庫設計是問題的根源,一個差勁的資料模型可以使應用程式的效能和可維護性都深受影響,值得注意的是,一個越是為效能而優化的資料庫,可維護性也越低(這一點是有爭議的,它其實要視乎應用程式的大小和規模)。

建議大家閱讀「MySQL 的資料庫設計手冊」。http://dev.mysql.com/doc/refman/5.0/en/optimizing-database-structure.html

十一. 應用程式層面的 SQL 效能

應用程式層面的 SQL 效能與 SQL 查詢的效能屬於不同的課題,這是有關如何在設計上使 SQL 與應用程式互相配合讓工作做得更好

這方面的研究主要集中於如何降低查詢的次數,從而提高可擴展性和改善效能,不過,高的效能並不等於好的可擴展性,正如具有可擴展性並不等於有高的效能。

ECMA宣布停止ECMAScript 4

全文引用自http://medialand.com.tw/blog/article.asp?id=782

今天早上看到的新聞,ECMA宣布暫時放棄ECMAScript 4規範而採用ECMAScript 3.1。「ECMAScript規範」這個東西雖然目前為止對我們大都數人來說沒有什麼感覺,但是有可能會對於未來一兩年內網路發展造成不太可預期的影響。

先解釋一下ECMAScript規範是啥東西。

ECMAScript是一種程式語言的標準,由ECMA這個機構所制定,跟我們切身最有關係的就是JavaScript以及Flash ActionScript,這兩種都是遵守ECMAScript規範來實作的程式語言,早期原本只有JavaScript 去鳥EMCA,當初大家也都以為JavaScript只會在網頁上來個跑馬燈或下雪花,後來ActionScript加入ECMA家族而且JavaScript轉職成Ajax之後,ECMAScript嚴然成為Web上火熱的標準規範,去年推出的AS3甚至標榜完全遵守ECMAScript 4。 Adobe的動作不止如此,它們提供了名為Tamarin的ECMAScript VM給Mozilla,用意在提升網頁執行ECMAScript時的效能,預計FireFox 4之後Tamarin就會內建到FireFox裡。如果這個計劃屬實,到時用FireFox跑頁面時,不管是Flash或Ajax都可以比現在更順暢許多。

因此。不難想像ECMA宣布否決ECMAScript 4這個消息帶給許多網路開發者有多大的反彈,ECMAScript 4的停止,表示JavaScript或ActionScript在發展的腳步上也跟著暫時止步,減緩了Ajax/Flash提供更完善Client端RIA機制的速度,完全遵守ECMAScript 4的AS3這時更是顯得尷尬。

雖然Flash仍然可以不管ECMA而繼續的朝向未來ECMAScript 4來開發下一代的ActionScript(官方人士現身說法),但是Ajax卻會遇到跨平台瀏覽器支援的最大問題。在未來Flash與Ajax聯手絕對可以組合出比較豐富Combo技的情況下,Flash與Ajax任何一方跳出ECMA規範都不是好事。

而且gskinner說的沒錯 ,沒人想再回到以前那種毫無規範大家個走個兒的那種「網路的西部時代」。

大概逛了一下,許多關心這件事的人們,有人在他的blog裡直接使用ECMAScript 4 is dead這種悲觀字眼,有人是開始擔心AS4是不是要因此又要做大調整,大多數人則很不客氣的把矛頭指向「萬惡的」微軟(感覺大家都十分懷疑是微軟從中作梗反對ECMAScript 4,但我沒找到強而有力的官方聲明就是了)。

2008年12月25日 星期四

Google文件祝你聖誕快樂

Google員工們使用協同作業一起編出來的畫面, 真的是很佩服Google能讓員工有這麼多的自由進而發想創意。
台灣的公司就不可能了, 被看到應該馬上請你回家吃自己, 泣...

文化的不同也會造就不同的成就, 創意或代工...

2008年12月24日 星期三

用php做出類似Google的字詞驗證圖片

雖然日前Google字詞驗證與CAPTCHA都已經宣告被破解, 但還是用php來寫出一個類似的介面, php圖片要扭曲必須要用像素位移的方式, 所以出來的圖片會有一點沙沙的感覺。 其實也可以使用其他附加軟體進行扭曲的動作, 但那樣可攜性就相對降低了。
使用時請在這支php同資料夾加上font資料夾, 裡面放置要產生驗證碼的字型, 幾個都可以, 會隨機挑選, 驗證碼存在$_SESSION['vCode']中, 格式為 驗證碼|時間, 比對時要explode("|", $_SESSION['vCode'])。

也可以加上干擾線條與點數, 變的更難辨識。

測試檔案打包下載

<?php

session_start();   // if header already send, change output_buffering = On at php.ini. otherwise save as UTF-8 without BOM.

$vi = new vCodeImage();
$vi -> SetImage(2,7,130,60,120,1);

class vCodeImage
{
    var $mode;            // 1.文字模式, 2.字母模式, 3.文字字母混合模式, 4.其他文字字母優化模式
    var $v_num;            // 驗證碼個數
    var $img_w;            // 圖像寬度
    var $img_h;            // 圖像�度
    var $int_pixel_num; // 干擾像數個數
    var $int_line_num;    // 干擾線條數量
    var $font_dir;        // 字型文件路徑
    var $border;        // 圖像邊框
    var $borderColor;    // 圖像邊框顏色

    function SetImage($mode, $v_num, $img_w, $img_h, $int_pixel_num, $int_line_num, $font_dir='font', $border=false, $borderColor='0,0,0')
    {
        if(!isset($_SESSION['vCode'])){
            session_register('vCode');
        }
        $_SESSION['vCode'] = "";

        $this -> mode = $mode;
        $this -> v_num = $v_num;
        $this -> img_w = $img_w;
        $this -> img_h = $img_h;
        $this -> int_pixel_num = $int_pixel_num;
        $this -> int_line_num = $int_line_num;
        $this -> font_dir = $font_dir;
        $this -> border = $border;
        $this -> borderColor = $borderColor;
        $this -> GenerateImage();
    }

    function GetChar($mode)
    {
        if($mode == "1"){
            $ychar = "0,1,2,3,4,5,6,7,8,9";
        }else if($mode == "2"){
            $ychar = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z";
        }else if($mode == "3"){
            $ychar = "0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z";
        }else{
            $ychar = "3,4,5,6,7,8,9,a,b,c,d,h,k,p,r,s,t,w,x,y";
        }
        return $ychar;
    }
 
    function RandColor($rs, $re, $gs, $ge, $bs, $be)
    {
        $r = mt_rand($rs, $re);
        $g = mt_rand($gs, $ge);
        $b = mt_rand($bs, $be);
        return array($r, $g, $b);
    }
 
    function GenerateImage()
    {
        $fonts = scandir($this -> font_dir);
        $ychar = $this -> GetChar($this -> mode);
        $list = explode(",", $ychar);
        $cmax = count($list) - 1;
        $fmax = count($fonts) - 2;
        $fontrand = mt_rand(2, $fmax);
        $font = $this -> font_dir."/".$fonts[$fontrand];

        // 驗證碼
        $v_code = "";
        for($i = 0; $i < $this-> v_num; $i++){    
            $randnum = mt_rand(0, $cmax);
            $this_char = $list[$randnum];
            $v_code .= $this_char;
        }

        // 扭曲圖形
        $im = imagecreatetruecolor ($this -> img_w + 50, $this -> img_h);
        $color = imagecolorallocate($im, 32, 81, 183);
        $ranum = mt_rand(0, 2);
        if($ranum == 0){
            $color = imagecolorallocate($im, 32, 81, 183);
        }else if($ranum == 1){
            $color = imagecolorallocate($im, 17, 158, 20);
        }else{
            $color = imagecolorallocate($im, 196, 31, 11);
        }
        imagefill($im, 0, 0, imagecolorallocate($im, 255, 255, 255) );
        imagettftext ($im, 24, mt_rand(-6, 6), 10, $this -> img_h * 0.6, $color, $font, $v_code);

        // 干擾線條
        for($i = 0; $i < $this -> int_line_num; $i++){
            $rand_color_line = $color;
            imageline($im, mt_rand(2,intval($this -> img_w/3)), mt_rand(10,$this -> img_h - 10), mt_rand(intval($this -> img_w - ($this -> img_w/3) + 50),$this -> img_w), mt_rand(0,$this -> img_h), $rand_color_line);
        }

        $ranum = mt_rand(0, 1);
        $dis_range = mt_rand(8, 12);
        $distortion_im = imagecreatetruecolor ($this -> img_w * 1.5 ,$this -> img_h);        
        imagefill($distortion_im, 0, 0, imagecolorallocate($distortion_im, 255, 255, 255));
        for ($i = 0; $i < $this -> img_w + 50; $i++) {
            for ($j = 0; $j < $this -> img_h; $j++) {
                $rgb = imagecolorat($im, $i, $j);
                if($ranum == 0){
                    if( (int)($i+40+cos($j/$this -> img_h * 2 * M_PI) * 10) <= imagesx($distortion_im) && (int)($i+20+cos($j/$this -> img_h * 2 * M_PI) * 10) >=0 ) {
                        imagesetpixel ($distortion_im, (int)($i+10+cos($j/$this -> img_h * 2 * M_PI - M_PI * 0.4) * $dis_range), $j, $rgb);
                    }
                }else{
                    if( (int)($i+40+sin($j/$this -> img_h * 2 * M_PI) * 10) <= imagesx($distortion_im) && (int)($i+20+sin($j/$this -> img_h * 2 * M_PI) * 10) >=0 ) {
                        imagesetpixel ($distortion_im, (int)($i+10+sin($j/$this -> img_h * 2 * M_PI - M_PI * 0.4) * $dis_range), $j, $rgb);
                    }
                }
            }
        }

        // 干擾像素
        for($i = 0; $i < $this -> int_pixel_num; $i++){
            $rand_color_pixel = $color;
            imagesetpixel($distortion_im, mt_rand() % $this -> img_w + 20, mt_rand() % $this -> img_h, $rand_color_pixel);
        }

        // 繪製邊框
        if($this -> border){
            $border_color_line = $color;
            imageline($distortion_im, 0, 0, $this -> img_w, 0, $border_color_line); // 上橫
            imageline($distortion_im, 0, 0, 0, $this -> img_h, $border_color_line); // 左豎
            imageline($distortion_im, 0, $this -> img_h-1, $this -> img_w, $this -> img_h-1, $border_color_line); // 下橫
            imageline($distortion_im, $this -> img_w-1, 0, $this -> img_w-1, $this -> img_h, $border_color_line); // 右豎
        }

        imageantialias($distortion_im, true); // 消除鋸齒

        $time = time();
        $_SESSION['vCode'] = $v_code."|".$time; // 把驗證碼與時間賦與給 $_SESSION[vCode], 時間欄位可以驗證��否超時

        // 生成圖像給瀏覽器
        if (function_exists("imagegif")) {
            header ("Content-type: image/gif");
            imagegif($distortion_im);
        }else if (function_exists("imagepng")) {
            header ("Content-type: image/png");
            imagepng($distortion_im);
        }else if (function_exists("imagejpeg")) {
            header ("Content-type: image/jpeg");
            imagejpeg($distortion_im, "", 80);
        }else if (function_exists("imagewbmp")) {
            header ("Content-type: image/vnd.wap.wbmp");
            imagewbmp($distortion_im);
        }else{
          die("No Image Support On This Server !");
        }

        imagedestroy($im);
        imagedestroy($distortion_im);
    }
}
?>