December 2,2011
[PHP] AJAX 與 cookie
喔~大概有八百年沒有寫文章了...(汗)最近遇到一個需求,需要用到 cookie 紀錄;不過在實作的過程中,發現明明以 AJAX 在 PHP 中 setcookie(),重新整理後卻無法取得 $_COOKIE 資訊的問題。後來以關鍵字餵了 google 大神以後,才找到解決的方法:
1. 設定 setcookie() $path 參數:
以 AJAX 設定 cookie 時,如果沒有指定 $path 參數程式會自動指定一個虛擬目錄給它,但依照 cookie 的特性:「僅有它的目錄以及以下的子目錄能夠存取」;所以未指定 $path 參數的 cookie 可能會造成在其他目錄下的程式無法存取。一勞永逸的方式就是直接指定 $path 參數為根目錄「/」:
做法有很多種,不過大概就是由 JavaScript 寫入 cookie 的概念。
最後我是使用第一種方式,有些問題還真是沒有碰到就不會知道呢~google 大神真是大家的好朋友!(拇指)
1. 設定 setcookie() $path 參數:
以 AJAX 設定 cookie 時,如果沒有指定 $path 參數程式會自動指定一個虛擬目錄給它,但依照 cookie 的特性:「僅有它的目錄以及以下的子目錄能夠存取」;所以未指定 $path 參數的 cookie 可能會造成在其他目錄下的程式無法存取。一勞永逸的方式就是直接指定 $path 參數為根目錄「/」:
<?php2. PHP 伺服端回傳變數,由 JavaScript 寫入 cookie:
// 第三個參數是 cookie 的存活時間,0 表示存活至瀏覽器關閉為止
setcookie('variable', $value, 0, '/');
?>
做法有很多種,不過大概就是由 JavaScript 寫入 cookie 的概念。
最後我是使用第一種方式,有些問題還真是沒有碰到就不會知道呢~google 大神真是大家的好朋友!(拇指)
January 20,2010
[PHP] PDO 的使用方法
PHP 從 PHP5 開始,在資料庫操作方面新增了 PDO(PHP Data Objects)的 extension,利用物件導向的方式與資料庫進行溝通。捨棄以往透過單一函式的方式,而是透過物件導向程式設計的抽象化概念,操作時使用統一的方法,如果需要更換資料庫時,只要在建立物件時給予資料庫的形式,而不用更動到原來的程式碼。這也是物件導向程式設計擁有優良靈活性的最佳表現!
連線的方式:
一般的 SELECT 查詢方式:
利用預載的方式:(推薦使用)
統一採用物件的方式來操作資料庫,不僅增加系統的彈性,透過相同的 quote() 方法,即可針對不同的資料庫形式進行 SQL Injection 的預防;真的非常方便!雖然於其他專業的 ORM(如:Doctrine)比較,仍有不足;但是在比較簡單的功能的實作上,PHP5 內建的 PDO 的確提供良好的資料庫操作模式~推薦使用!^^
連線的方式:
<?php
// 給定資料庫變數
$dbtype_sql = 'mysql';
$host_sql = 'localhost';
$dbname_sql = 'dbname';
$username_sql = 'username';
$password_sql = 'password';
// 資料庫連線
try {
$dbh = new PDO($dbtype_sql . ':host=' . $host_sql . ';dbname=' . $dbname_sql, $username_sql, $password_sql);
// 資料庫使用 UTF8 編碼
$dbh->query('SET NAMES UTF8');
} catch (PDOException $e) {
echo 'Error!: ' . $e->getMessage() . '<br />';
}
?>
一般的 SELECT 查詢方式:
<?php
// 使用 quote 避免 SQL Injection;相當於 mysql_real_escape_string()
$id = $dbh->quote(2);
$name = $dbh->quote('John');
// 組合 SQL 語法,取得符合 id = 2、name = 'John' 的資料
$query = sprintf("SELECT * FROM table WHERE id = %s AND name = %s", $id, $name);
foreach ($dbh->query($query) as $row) {
print_r($row);
}
?>
利用預載的方式:(推薦使用)
<?php
// 組合 SQL 語法,取得符合 id = 2、name = 'John' 的資料
$sth = $dbh->prepare('SELECT * FROM table WHERE id = :id AND name = :name');
$where = array(':id' => 2, ':name' => 'John');
// 使用 execute(),會自動 quote $where 的參數
$sth->execute($where);
foreach ($sth->fetchAll(PDO::FETCH_ASSOC) as $row) {
print_r($row);
}
?>
統一採用物件的方式來操作資料庫,不僅增加系統的彈性,透過相同的 quote() 方法,即可針對不同的資料庫形式進行 SQL Injection 的預防;真的非常方便!雖然於其他專業的 ORM(如:Doctrine)比較,仍有不足;但是在比較簡單的功能的實作上,PHP5 內建的 PDO 的確提供良好的資料庫操作模式~推薦使用!^^
December 29,2009
[新知] Augmented Reality 擴增實境
今天發現了一個我以前就知道的東西(我在說什麼啊...?):Augmented Reality 擴增實境。最早看到應用類似技術的商品是在日本的遊戲 AR-FIGURE 中:利用 Web Cam 與遊戲廠商提供的實體方塊,建立一個存在電腦螢幕中真實環境裡的虛擬人偶(好繞口...)。第一次看到這玩意兒的時候真是嚇死我了,原來遊戲也可以這樣玩!擴增實境其實也是 Virtual Reality 虛擬實境的一種;但不同於 VR 中所有東西都是虛擬的,AR 是一種與現實環境結合的虛擬。隨著現代科技的進步,攝影機技術已經被廣泛運用生活中;也因為如此,以往印象中虛擬實境所需的厚重眼鏡與手套,已經可以藉由我們生活中常見的手機:攝影鏡頭與觸控螢幕來實現!
Google 前陣子提出的 Google Goggles,似乎就有結合類似的技術;透過即時的影像擷取與分析,立即透過網路取得相關資訊。當然這只是非常小部分的應用,更多的應用可以參考「iGarden – NSS ICT Education Blog 擴增實境Augmented Reality(AR)教學」的相關介紹文章,有非常令人驚艷的展示效果!
今天跟 Jace 提到這個技術,他提到 MIT 有個印度的學生已經結合此技術,實作出更接近未來世界的裝置;後來我 google 了一下,發現了 sixthsense 這個專案。這個專案利用成本大約 320 美金的材料,改裝成一個結合攝影與顯示於一身的特殊裝置,透過這個裝置就能夠即時擷取眼前的影像,並直接投影在物體上,利用手指上的顏色標籤作手勢操作,完全就像電影《關鍵報告》的操作方式!超屌!
以往覺得離我們好遠好遠的未來科技,突然有一種近在咫呎的感覺!Google Goggles 已經實現了動畫《東之伊甸》所描繪的技術,或許不久的將來就能體驗,動畫《電腦線圈》中透過「電腦眼鏡」看世界的科技未來!
P.S 這個影片整個很有《魔鬼終結者》的 fu...墨鏡才是本體啊!(噗)
Google 前陣子提出的 Google Goggles,似乎就有結合類似的技術;透過即時的影像擷取與分析,立即透過網路取得相關資訊。當然這只是非常小部分的應用,更多的應用可以參考「iGarden – NSS ICT Education Blog 擴增實境Augmented Reality(AR)教學」的相關介紹文章,有非常令人驚艷的展示效果!
今天跟 Jace 提到這個技術,他提到 MIT 有個印度的學生已經結合此技術,實作出更接近未來世界的裝置;後來我 google 了一下,發現了 sixthsense 這個專案。這個專案利用成本大約 320 美金的材料,改裝成一個結合攝影與顯示於一身的特殊裝置,透過這個裝置就能夠即時擷取眼前的影像,並直接投影在物體上,利用手指上的顏色標籤作手勢操作,完全就像電影《關鍵報告》的操作方式!超屌!
以往覺得離我們好遠好遠的未來科技,突然有一種近在咫呎的感覺!Google Goggles 已經實現了動畫《東之伊甸》所描繪的技術,或許不久的將來就能體驗,動畫《電腦線圈》中透過「電腦眼鏡」看世界的科技未來!
P.S 這個影片整個很有《魔鬼終結者》的 fu...墨鏡才是本體啊!(噗)
May 22,2009
[新知] OpenSource 與授權方式
從出社會工作以來,經常接觸到的幾乎所有的程式,都是開放原始碼。不過對於它的定義與其衍生的自由軟體所採用的授權方式,一直以來都是一知半解。前幾天在 PTT Soft_Job 版看到一篇討論【[請益] 請問要如何規避GPL?】,引起我想要弄清楚的興趣;這些不同的授權方式各自到底代表著什麼意義呢?
詳細看了 Wiki 以及網路上一些前輩們的介紹,發現這些不同的軟體授權方式其實還蠻複雜的...就我理解的部分,稍微介紹一些常用的授權許可證;不一定正確,只是簡單紀錄一下(整個想要逃避責任的口氣):
1. GPL:
(1)其出發點在於開放程式碼、免費使用和引用、修改或衍生程式碼的開放與免費使用。
(2)符合 Copyleft 機制的授權條款。所以修改或衍生的程式碼,也必須強制繼承 GPL 的規範;確保所有使用 GPL 的自由軟體,能一直保持自由開放的原則。
(3)因為強迫繼承的關係,GPL 也引來一些批評,所以在 PTT 才會引起想要規避的討論。畢竟公司發售軟體,目的當然是為了賺錢;在遇到這種有「傳染性」的授權方式時,難免會感到困擾...
2. BSD:
(1)在使用此授權方式的軟體或程式碼時,必須保留版權宣告、三條件表列以及免責聲明。
(2)可以自由的使用,修改原始碼,也可以將修改後的原始碼作為開放原始碼或者專有軟體再發佈。
(3)是使用時限制很少,寬鬆的授權方式。
3. Apache License:
(1)在使用此授權方式的軟體或程式碼時,必須保留版權宣告、三條件表列以及免責聲明。
(2)可以自由的使用,修改原始碼,也可以將修改後的原始碼作為開放原始碼或者專有軟體再發佈。
(3)與 BSD 非常類似,不過在修改原始碼後,必須在版權宣告後加注。
4. MIT:
(1)可根據程式的需要修改授權條款為適當的內容;但在軟體和軟體的所有副本中仍必須包含版權聲明和許可聲明。
(2)可以自由的使用,修改原始碼,也可以將修改後的原始碼作為開放原始碼或者專有軟體再發佈。
(3)與 BSD 同屬限制少又寬鬆的授權方式;唯一的不同點在於 MIT 的內容可依照程式著作權者的需求而更改。
以 jQuery 這個 JavaScript Library 為例,它使用的授權協議為 GPL 和 MIT 雙協議,故在使用上符合自由軟體的精神,而且限制也很寬鬆;在去年微軟也曾經發布要將 jQuery 加入 Visual Studio的相關新聞。
參考資料:
(1)開放原始碼促進會(英文)
(2)OSSF::自由軟體鑄造場(中文)
(3)五種開源協議的比較(BSD,Apache,GPL,LGPL,MIT) - 整理(中文)
P.S 後來拜讀 OSSF::自由軟體鑄造場【軟體的授權觀念與自由軟體授權類別】投影片(by 自由軟體鑄造場 2008 林誠夏)後,又得到更明確的一些觀念:
自由軟體,擁有六大特性、四大自由
六大特性:開放程式原始碼、不特定授權對象、不限制使用地域、不收取授權金、不隨附擔保、釋放四大自由予後手。
四大自由:執行、研究、改良、重製散佈
另外之前我以為使用或繼承 GPL 條款的自由軟體,就不能收取費用;但其實只要收取費用的名目並不是「授權金」(其他名目如:軟體服務費),作為商業軟體販售是完全合法的!但是因為大部分軟體公司在開發專案時,會將原始碼也當作專案明細的一部分販售;如此一來就與 GPL 必須開放原始碼的宗旨相違背,所以一般軟體公司會想要規避 GPL 的原因就在這裡。
自由軟體的原始概念立意良善,是為了不讓程式撰寫人員閉門造車;如果已經有人發明了輪子,就沒有必要自己再重新設計!拜網際網路發達之賜,讓來自世界各地的程式設計師集思廣益,能更自由的運用前人的智慧,發展更好的功能、更穩定的程式,這不是很棒的一件事嗎!^^
詳細看了 Wiki 以及網路上一些前輩們的介紹,發現這些不同的軟體授權方式其實還蠻複雜的...就我理解的部分,稍微介紹一些常用的授權許可證;不一定正確,只是簡單紀錄一下(整個想要逃避責任的口氣):
1. GPL:
(1)其出發點在於開放程式碼、免費使用和引用、修改或衍生程式碼的開放與免費使用。
(2)符合 Copyleft 機制的授權條款。所以修改或衍生的程式碼,也必須強制繼承 GPL 的規範;確保所有使用 GPL 的自由軟體,能一直保持自由開放的原則。
(3)因為強迫繼承的關係,GPL 也引來一些批評,所以在 PTT 才會引起想要規避的討論。畢竟公司發售軟體,目的當然是為了賺錢;在遇到這種有「傳染性」的授權方式時,難免會感到困擾...
2. BSD:
(1)在使用此授權方式的軟體或程式碼時,必須保留版權宣告、三條件表列以及免責聲明。
(2)可以自由的使用,修改原始碼,也可以將修改後的原始碼作為開放原始碼或者專有軟體再發佈。
(3)是使用時限制很少,寬鬆的授權方式。
3. Apache License:
(1)在使用此授權方式的軟體或程式碼時,必須保留版權宣告、三條件表列以及免責聲明。
(2)可以自由的使用,修改原始碼,也可以將修改後的原始碼作為開放原始碼或者專有軟體再發佈。
(3)與 BSD 非常類似,不過在修改原始碼後,必須在版權宣告後加注。
4. MIT:
(1)可根據程式的需要修改授權條款為適當的內容;但在軟體和軟體的所有副本中仍必須包含版權聲明和許可聲明。
(2)可以自由的使用,修改原始碼,也可以將修改後的原始碼作為開放原始碼或者專有軟體再發佈。
(3)與 BSD 同屬限制少又寬鬆的授權方式;唯一的不同點在於 MIT 的內容可依照程式著作權者的需求而更改。
以 jQuery 這個 JavaScript Library 為例,它使用的授權協議為 GPL 和 MIT 雙協議,故在使用上符合自由軟體的精神,而且限制也很寬鬆;在去年微軟也曾經發布要將 jQuery 加入 Visual Studio的相關新聞。
參考資料:
(1)開放原始碼促進會(英文)
(2)OSSF::自由軟體鑄造場(中文)
(3)五種開源協議的比較(BSD,Apache,GPL,LGPL,MIT) - 整理(中文)
P.S 後來拜讀 OSSF::自由軟體鑄造場【軟體的授權觀念與自由軟體授權類別】投影片(by 自由軟體鑄造場 2008 林誠夏)後,又得到更明確的一些觀念:
自由軟體,擁有六大特性、四大自由
六大特性:開放程式原始碼、不特定授權對象、不限制使用地域、不收取授權金、不隨附擔保、釋放四大自由予後手。
四大自由:執行、研究、改良、重製散佈
另外之前我以為使用或繼承 GPL 條款的自由軟體,就不能收取費用;但其實只要收取費用的名目並不是「授權金」(其他名目如:軟體服務費),作為商業軟體販售是完全合法的!但是因為大部分軟體公司在開發專案時,會將原始碼也當作專案明細的一部分販售;如此一來就與 GPL 必須開放原始碼的宗旨相違背,所以一般軟體公司會想要規避 GPL 的原因就在這裡。
自由軟體的原始概念立意良善,是為了不讓程式撰寫人員閉門造車;如果已經有人發明了輪子,就沒有必要自己再重新設計!拜網際網路發達之賜,讓來自世界各地的程式設計師集思廣益,能更自由的運用前人的智慧,發展更好的功能、更穩定的程式,這不是很棒的一件事嗎!^^
April 9,2009
[AJAX] jQuery的多重下拉式選單應用:Select box manipulation
從本網誌回應數最高的文章得知,大家似乎對多重下拉式選單的功能情有獨鍾啊!Ajax 能夠在不換頁的情況下,達到資料庫連結,是許多人夢寐以求的功能;而 jQuery 易上手與輕鬆操作的特性,讓我們能更簡單的運用 Ajax 達成目的。然而隨著時間的推移,過去介紹的 cascade 已經有很長一段時間沒有更新,而且在使用上其實存在不少綁手綁腳的地方;距離 jQuery 的宗旨「Write Less, Do More」似乎是還差那麼一小段距離...
經由公司的 jQuery 教育訓練,Jace 介紹了一個超讚的 jQuery Plugin:Select box manipulation。透過這個外掛的幫助,可以更輕鬆的實現多重下拉式選單的功能唷,甚至連 cascade 不容易做到的「預設值」也完全沒問題,所需要撰寫的程式碼也少於 cascade,整個就是夢幻的 Plugin!這麼神奇的外掛要怎麼用呢?以下簡單的範例,給有需要的人參考吧:範例是三階層的關聯式多重下拉式選單,分為index.php(呈現頁)、action.php(Ajax 後端資料處理頁)、index.js(JavaScript 處理)、以及 selectboxes ...繼續閱讀
經由公司的 jQuery 教育訓練,Jace 介紹了一個超讚的 jQuery Plugin:Select box manipulation。透過這個外掛的幫助,可以更輕鬆的實現多重下拉式選單的功能唷,甚至連 cascade 不容易做到的「預設值」也完全沒問題,所需要撰寫的程式碼也少於 cascade,整個就是夢幻的 Plugin!這麼神奇的外掛要怎麼用呢?以下簡單的範例,給有需要的人參考吧:範例是三階層的關聯式多重下拉式選單,分為index.php(呈現頁)、action.php(Ajax 後端資料處理頁)、index.js(JavaScript 處理)、以及 selectboxes ...繼續閱讀
March 3,2009
[AJAX] JavaScript 的 PHP 函數寫法:nl2br()、htmlspecialchars()
PHP 真的是一種非常方便的語言,其支援的龐大函式庫,可以讓人很輕鬆自在的使用許多實用的函數。其中常用的 nl2br() 與 htmlspecialchars() 在 HTML 顯示的時候很常使用,但是 JavaScript 就沒有提供類似方便使用的函數了;因為某些原因要在前端使用這二個函數,稍微 google 了一下馬上發現有前輩已經寫出來囉!在此作個紀錄並分享給有需要的人:(來源:Replace newlines with BR (platform safe)、Javascript 的 htmlspecialchars function 與 htmlspecialchars_decode function,感謝網路上的前輩們^^)
// javascript 版本的 nl2br
var nl2br = function (string) {
string = escape(string);
if (string.indexOf('%0D%0A') > -1) {
var re_nlchar = /%0D%0A/g ;
} else if (string.indexOf('%0A') > -1) {
var re_nlchar = /%0A/g ;
} else if (string.indexOf('%0D') > -1) {
var re_nlchar = /%0D/g ;
}
return unescape(string.replace(re_nlchar, '<br />'));
}
// javascript 版本的 htmlspecialchars
var htmlspecialchars = function (string, quote_style) {
string = string.toString();
string = string.replace(/&/g, '&');
string = string.replace(/</g, '<');
string = string.replace(/>/g, '>');
if (quote_style == 'ENT_QUOTES') {
string = string.replace(/"/g, '"');
string = string.replace(/\'/g, ''');
} else if (quote_style != 'ENT_NOQUOTES') {
string = string.replace(/"/g, '"');
}
return string;
}
February 5,2009
[PHP] ZendFramework Zend_Db_Table_Rowset::getRow() 的用法
一般在使用 ZendFramework 的 Zend_Db_Table_Rowset fetchAll() 時,都是需要 Rowset 裡面全部的資料;不過偶爾有會有只需要單筆資料列的情況,這個時候就可以藉助 current() 或是 getRow() 取得單筆資料列。
current() 很單純,就是目前 Rowset 中指向的資料列,通常在沒有指定指標的情況下,就是該 Rowset 中的第一筆資料:
current() 很單純,就是目前 Rowset 中指向的資料列,通常在沒有指定指標的情況下,就是該 Rowset 中的第一筆資料:
$table = new Table();getRow() 就比較有彈性,它可以指定取得第幾個資料列,並決定是不是要將指標移至該資料列(預設為不指定)。
$select = $table->select();
$rowset = $table->fetchAll($select);
$row = $rowset->current();
// 這裡的 $row 就會是 $rowset 的第一筆資料列。
getRow($position, $seek = false)用法如下:
// $position 設定取得第幾列資料(從 0 開始)
// $seek 設定是否要將指標移至該資料列(預設為不指定)
$table = new Table();要比較注意的是 $seek 的使用時機,是否有需要移動指標,就看程式的需求囉;使用後呈現的資料,如以下的例子:
$select = $table->select();
$rowset = $table->fetchAll($select);
$row = $rowset->getRow(1);
// 這裡的 $row 就會是 $rowset 的第二筆資料列。
$table = new Table();大概就是這樣;在這邊做個紀錄,感謝 Jace 解惑^^
$select = $table->select();
$rowset = $table->fetchAll($select);
$row = $rowset->current();
// 這裡的 $row 就會是 $rowset 的第一筆資料列。
$row = $rowset->getRow(1);
// 這裡的 $row 就會是 $rowset 的第二筆資料列($seek 預設為 false,故指標不移動)。
$row = $rowset->current();
// 這裡的 $row 還是 $rowset 的第一筆資料列。
$row = $rowset->getRow(1, true);
// 這裡的 $row 就會是 $rowset 的第二筆資料列($seek 設為 true,故指標移動)。
$row = $rowset->current();
// 這裡的 $row 就會變成是 $rowset 的第二筆資料列。
December 25,2008
[CSS] 面對非標準的 IE 瀏覽器,圖片撐破表單的解決方法
在撰寫網頁程式的時候,除了程式的撰寫以外,最花時間的部分大概就是版型的套用吧。有經驗的網頁美工設計師會利用 CSS 進行網站版面的配置,CSS 的運用對網頁程式設計師來說會比較親切;但是對大部分習慣以 Dreamwaver 為開發工具的網頁美工設計師來說,表格 table 的運用似乎比較心應手。雖然說如果一個簡單的網頁設計要從無到有,我也會比較傾向使用表格;但是對於複雜的網頁樣板來說,巢狀的表格真的是會讓人眼花撩亂啊...(噗)
其實以上都是閒聊...(汗)今天碰到的問題是在 Firefox 上看版面沒有問題,但是 IE 上卻發生表格被圖片撐開的情況。在全是表格的網頁上,被撐開的圖片斷層殘破不堪,實在非常有礙觀瞻;雖然大家都知道 IE 對網頁標準支援非常的不完全(wiki 寫的很含蓄:「只是有一些排版錯誤」),不過對於大部分的人來說,IE 幾乎就是瀏覽器的代名詞,所以既然有問題就還是得解決...
因為小弟經驗不足,找了半天還是找不出解決方法~後來經由 Abu 的幫忙,總算是用 CSS 解決問題囉!會發生圖片斷層的原因主要是因為圖片大小超過表單的大小,雖然我明明就把表格的高度與圖片的高度設定的一模一樣,但是好樣的 IE 就是會判斷錯誤,造成圖片斷層的問題。這個時候只要在 <img> 中加入 CSS:
<img style="float: left;" src="/sample.jpg" alt="測試圖片"/>
原本歪七扭八,七零八落的圖片就能完全契合於表格中囉!真是比吃滷肉飯還簡單哩~謝謝 Abu!
其實以上都是閒聊...(汗)今天碰到的問題是在 Firefox 上看版面沒有問題,但是 IE 上卻發生表格被圖片撐開的情況。在全是表格的網頁上,被撐開的圖片斷層殘破不堪,實在非常有礙觀瞻;雖然大家都知道 IE 對網頁標準支援非常的不完全(wiki 寫的很含蓄:「只是有一些排版錯誤」),不過對於大部分的人來說,IE 幾乎就是瀏覽器的代名詞,所以既然有問題就還是得解決...
因為小弟經驗不足,找了半天還是找不出解決方法~後來經由 Abu 的幫忙,總算是用 CSS 解決問題囉!會發生圖片斷層的原因主要是因為圖片大小超過表單的大小,雖然我明明就把表格的高度與圖片的高度設定的一模一樣,但是好樣的 IE 就是會判斷錯誤,造成圖片斷層的問題。這個時候只要在 <img> 中加入 CSS:
<img style="float: left;" src="/sample.jpg" alt="測試圖片"/>
原本歪七扭八,七零八落的圖片就能完全契合於表格中囉!真是比吃滷肉飯還簡單哩~謝謝 Abu!
September 3,2008
[AJAX] jQuery的多重下拉式選單應用,當有預設值的時候
在多重下拉式選單的應用中,常常也會遇到已經有預設值的時候,這時候該怎麼辦呢?其實前陣子我也遇過這個問題,當初還花了一點時間尋找 jQuery的cascade 是不是有提供參數讓我輕鬆預設;不過拜完 Google 大神之後似乎是沒有什麼線索;所以最後我採用了一個很笨的方法,在頁面讀取完畢時如果有預設值的話,就直接丟一個 Ajax 取得第二層的選項。以下是實作的程式碼:(目前我只實作到二階層)
index.php:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery.cascade.js"></script>
<script type="text/javascript" src="jquery.cascade.ext.js"></script>
<script type="text/javascript" src="jquery.templating.js"></script>
</head>
<body>
第一項 <select id="myParentSelect">
<option value="">請選擇</option>
<?php
// 資料庫設定
$host_sql = "localhost";
$username_sql = "username";
$password_sql = "password";
// 預設值設定
$defaultParentId = '3';
$defaultChildId = '13';
$link = mysql_connect($host_sql, $username_sql, $password_sql) or die("無法連結資料庫");
mysql_select_db('target', $link);
mysql_query("SET NAMES UTF8");
$query = "SELECT id, name FROM table where lv = 1";
$result = mysql_query($query, $link);
while ($row = mysql_fetch_assoc($result)) {
echo '<option value="' . $row["id"] . '">' . $row["name"] . '</option>' . "\n";
}
?>
</select>
<!-- 設定一個隱藏的欄位紀錄預設值 -->
<input type="hidden" name="defaultParentId" value="<?php echo $defaultParentId; ?>" />
<input type="hidden" name="defaultChildId" value="<?php echo $defaultChildId; ?>" />
第二項 <select id="myChildSelect">
<option value="">請選擇</option>
</select>
<script type="text/javascript">
// 如果已有預設值,即時送出 Ajax 呼叫
function getSelectedList(defaultParentId, defaultFirstChildId) {
$.ajax({
type: "get",
url: 'action.php',
data: { act: 'default', val: defaultParentId, child: defaultFirstChildId },
dataType: "json",
success: function (json) {
$('select#myChildSelect').append(json.data);
}
});
};
$(function () {
// 檢查是否有預設值
if ($('input[name=defaultParentId]').val()) {
getSelectedList ($('input[name=defaultParentId]').val(), $('input[name=defaultChildId]').val());
}
// 第一階層對應第二階層
$('#myChildSelect').cascade('#myParentSelect', {
ajax: {
type: "post",
url: 'action.php',
data: { act: 'first', val: $('#myParentSelect').val() },
dataType: "json",
},
template: function(item) { return "<option value='" + item.Value + "'>" + item.Text + "</option>"; },
match: function(selectedValue) { return this.When == selectedValue; }
});
});
</script>
</body>
</html>
action.php:
<?php
// 資料庫設定
$host_sql = "localhost";
$username_sql = "username";
$password_sql = "password";
$link = mysql_connect($host_sql, $username_sql, $password_sql) or die("無法連結資料庫");
mysql_select_db('target', $link);
mysql_query("SET NAMES UTF8");
if (!empty($_GET['act'])) {
$action = $_GET['act'];
}
if (!empty($_GET['val'])) {
$parentId = $_GET['val'];
}
if (!empty($_GET['child'])) {
$childId = $_GET['child'];
}
switch ($action) {
case 'first':
$list = array();
$query = "SELECT id, name FROM table where lv = 2 AND parentid= $parentId";
$result = mysql_query($query, $link);
while ($row = mysql_fetch_assoc($result)) {
$arr = array ('When' => $parentId, 'Value' => $row["ID"], 'Text' => $row["NAME"]);
$list[] = $arr;
}
break;
case 'default':
default :
$list = '';
$query = "SELECT id, name FROM table where lv = 2 AND parentid= $parentId";
$result = mysql_query($query, $link);
while ($row = mysql_fetch_assoc($result)) {
$list .= '<option value="' . $row["ID"] . '"';
if ($childId == $row["ID"]) {
$list .= ' selected="selected"';
}
$list .= '>' . $row["NAME"] . '</option>';
}
$list = array('data' => $list);
break;
}
echo json_encode($list);
第二階層的選項,其實是用字串硬湊出來的,所以程式碼看起來還蠻醜的,請見諒。基本上用的概念只是在頁面讀取完畢以後直接送出 Ajax 而已,是蠻笨的方法;不過也不失為解決問題的一種方法啦!如果有其他適合的解法,有希望高手們能提供一下嚕!謝謝^^
index.php:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery.cascade.js"></script>
<script type="text/javascript" src="jquery.cascade.ext.js"></script>
<script type="text/javascript" src="jquery.templating.js"></script>
</head>
<body>
第一項 <select id="myParentSelect">
<option value="">請選擇</option>
<?php
// 資料庫設定
$host_sql = "localhost";
$username_sql = "username";
$password_sql = "password";
// 預設值設定
$defaultParentId = '3';
$defaultChildId = '13';
$link = mysql_connect($host_sql, $username_sql, $password_sql) or die("無法連結資料庫");
mysql_select_db('target', $link);
mysql_query("SET NAMES UTF8");
$query = "SELECT id, name FROM table where lv = 1";
$result = mysql_query($query, $link);
while ($row = mysql_fetch_assoc($result)) {
echo '<option value="' . $row["id"] . '">' . $row["name"] . '</option>' . "\n";
}
?>
</select>
<!-- 設定一個隱藏的欄位紀錄預設值 -->
<input type="hidden" name="defaultParentId" value="<?php echo $defaultParentId; ?>" />
<input type="hidden" name="defaultChildId" value="<?php echo $defaultChildId; ?>" />
第二項 <select id="myChildSelect">
<option value="">請選擇</option>
</select>
<script type="text/javascript">
// 如果已有預設值,即時送出 Ajax 呼叫
function getSelectedList(defaultParentId, defaultFirstChildId) {
$.ajax({
type: "get",
url: 'action.php',
data: { act: 'default', val: defaultParentId, child: defaultFirstChildId },
dataType: "json",
success: function (json) {
$('select#myChildSelect').append(json.data);
}
});
};
$(function () {
// 檢查是否有預設值
if ($('input[name=defaultParentId]').val()) {
getSelectedList ($('input[name=defaultParentId]').val(), $('input[name=defaultChildId]').val());
}
// 第一階層對應第二階層
$('#myChildSelect').cascade('#myParentSelect', {
ajax: {
type: "post",
url: 'action.php',
data: { act: 'first', val: $('#myParentSelect').val() },
dataType: "json",
},
template: function(item) { return "<option value='" + item.Value + "'>" + item.Text + "</option>"; },
match: function(selectedValue) { return this.When == selectedValue; }
});
});
</script>
</body>
</html>
action.php:
<?php
// 資料庫設定
$host_sql = "localhost";
$username_sql = "username";
$password_sql = "password";
$link = mysql_connect($host_sql, $username_sql, $password_sql) or die("無法連結資料庫");
mysql_select_db('target', $link);
mysql_query("SET NAMES UTF8");
if (!empty($_GET['act'])) {
$action = $_GET['act'];
}
if (!empty($_GET['val'])) {
$parentId = $_GET['val'];
}
if (!empty($_GET['child'])) {
$childId = $_GET['child'];
}
switch ($action) {
case 'first':
$list = array();
$query = "SELECT id, name FROM table where lv = 2 AND parentid= $parentId";
$result = mysql_query($query, $link);
while ($row = mysql_fetch_assoc($result)) {
$arr = array ('When' => $parentId, 'Value' => $row["ID"], 'Text' => $row["NAME"]);
$list[] = $arr;
}
break;
case 'default':
default :
$list = '';
$query = "SELECT id, name FROM table where lv = 2 AND parentid= $parentId";
$result = mysql_query($query, $link);
while ($row = mysql_fetch_assoc($result)) {
$list .= '<option value="' . $row["ID"] . '"';
if ($childId == $row["ID"]) {
$list .= ' selected="selected"';
}
$list .= '>' . $row["NAME"] . '</option>';
}
$list = array('data' => $list);
break;
}
echo json_encode($list);
第二階層的選項,其實是用字串硬湊出來的,所以程式碼看起來還蠻醜的,請見諒。基本上用的概念只是在頁面讀取完畢以後直接送出 Ajax 而已,是蠻笨的方法;不過也不失為解決問題的一種方法啦!如果有其他適合的解法,有希望高手們能提供一下嚕!謝謝^^
September 1,2008
[AJAX] jQuery 的 lightBox
一般網頁上圖片的展示,很難讓人不聯想到 Lightbox;這個 Prototype 的燈箱特效。無奈現在公司使用的 jQuery 與 Lightbox 犯沖~沒辦法讓基於 Prototype 寫成的這個外掛直接引用。雖然如此,這麼經典的覽圖介面 jQuery 怎麼會放過呢?所以,jQuery lightBox plugin 就因此誕生了!
基本上官方網站已經講的非常清楚了,使用方法也跟 Lightbox 非常類似;不過更方便,也更有彈性。只要在需引用的網頁中載入:
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/jquery.lightbox-0.5.js"></script>
<link rel="stylesheet" type="text/css" href="css/jquery.lightbox-0.5.css" media="screen" />
之後,寫一隻小小的 JavaScript 於頁面中:
<script type="text/javascript">
$(function() {
$('a[@rel*=lightbox]').lightBox();
});
</script>
就可以完全相容 Lightbox 的使用環境,無痛移植。此外,jQuery lightBox plugin 提供很多可以自訂的參數,自由度提高許多!
基本上官方網站已經講的非常清楚了,使用方法也跟 Lightbox 非常類似;不過更方便,也更有彈性。只要在需引用的網頁中載入:
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/jquery.lightbox-0.5.js"></script>
<link rel="stylesheet" type="text/css" href="css/jquery.lightbox-0.5.css" media="screen" />
之後,寫一隻小小的 JavaScript 於頁面中:
<script type="text/javascript">
$(function() {
$('a[@rel*=lightbox]').lightBox();
});
</script>
就可以完全相容 Lightbox 的使用環境,無痛移植。此外,jQuery lightBox plugin 提供很多可以自訂的參數,自由度提高許多!
June 13,2008
[AJAX] jQuery的多重下拉式選單應用 PART2
昨天Jace傳授密技!原本 Ajax 回傳值我是用字串硬湊出來的,不過有密技可以用比較簡單易懂的方式呈現回傳資料,那就是PHP的json_encode!它會把陣列資料轉變成 json 的格式(其實原本 jQuery 吃的格式就是 json ),所以就不用辛苦的自己湊字串啦!提供第二種方法囉~修改過的地方用紅色標記:
index.php:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery.cascade.js"></script>
<script type="text/javascript" src="jquery.cascade.ext.js"></script>
<script type="text/javascript" src="jquery.templating.js"></script>
</head>
<body>
第一項 <select id="myParentSelect">
<option value="">請選擇</option>
<?php
// 資料庫設定
$host_sql = "localhost";
$username_sql = "username";
$password_sql = "password";
$link = mysql_connect($host_sql, $username_sql, $password_sql) or die("無法連結資料庫");
mysql_select_db('target', $link);
mysql_query("SET NAMES UTF8");
$query = "SELECT id, name FROM table where lv = 1";
$result = mysql_query($query, $link);
while ($row = mysql_fetch_assoc($result)) {
echo '<option value="' . $row["id"] . '">' . $row["name"] . '</option>' . "\n";
}
?>
</select>
第二項 <select id="myFirstChildSelect">
<option value="">請選擇</option>
</select>
第三項 <select id="mySecondChildSelect">
<option value="">請選擇</option>
</select>
<script type="text/javascript">
$(function () {
// 第一階層對應第二階層
$('#myFirstChildSelect').cascade('#myParentSelect', {
ajax: {
type: "post",
url: 'action.php',
data: { act: 'first', val: $('#myParentSelect').val() },
dataType: "json"
},
template: function(item) { return "<option value='" + item.Value + "'>" + item.Text + "</option>"; },
match: function(selectedValue) { return this.When == selectedValue; }
});
// 第二階層對應第三階層
$('#mySecondChildSelect').cascade('#myFirstChildSelect', {
ajax: {
type: "post",
url: 'action.php',
data: { act: 'second', val: $('#myFirstChildSelect').val() },
dataType: "json"
},
template: function(item) { return "<option value='" + item.Value + "'>" + item.Text + "</option>"; },
match: function(selectedValue) { return this.When == selectedValue; }
});
});
</script>
</body>
</html>
action.php:
<?php
// 資料庫設定
$host_sql = "localhost";
$username_sql = "username";
$password_sql = "password";
$link = mysql_connect($host_sql, $username_sql, $password_sql) or die("無法連結資料庫");
mysql_select_db('target', $link);
mysql_query("SET NAMES UTF8");
if (!empty($_GET['act'])) {
$action = $_GET['act'];
}
if (!empty($_GET['val'])) {
$parentId = $_GET['val'];
}
$list = array();
switch ($action) {
case 'first':
$query = "SELECT id, name FROM table where lv = 2 AND parentid= $parentId";
$result = mysql_query($query, $link);
while ($row = mysql_fetch_assoc($result)) {
$arr = array ('When' => $parentId, 'Value' => $row["ID"], 'Text' => $row["NAME"]);
$list[] = $arr;
}
break;
case 'second':
default :
$query = "SELECT id, name FROM table where lv = 3 AND parentid = $parentId";
$result = mysql_query($query, $link);
while ($row = mysql_fetch_assoc($result)) {
$arr = array ('When' => $parentId, 'Value' => $row["ID"], 'Text' => $row["NAME"]);
$list[] = $arr;
}
break;
}
echo json_encode($list);
哈,這樣就清楚多了呢!當然昨天用字串組的方式也可以囉,其所達到的效果是一樣的啦!提供另一種思考方向^^
index.php:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery.cascade.js"></script>
<script type="text/javascript" src="jquery.cascade.ext.js"></script>
<script type="text/javascript" src="jquery.templating.js"></script>
</head>
<body>
第一項 <select id="myParentSelect">
<option value="">請選擇</option>
<?php
// 資料庫設定
$host_sql = "localhost";
$username_sql = "username";
$password_sql = "password";
$link = mysql_connect($host_sql, $username_sql, $password_sql) or die("無法連結資料庫");
mysql_select_db('target', $link);
mysql_query("SET NAMES UTF8");
$query = "SELECT id, name FROM table where lv = 1";
$result = mysql_query($query, $link);
while ($row = mysql_fetch_assoc($result)) {
echo '<option value="' . $row["id"] . '">' . $row["name"] . '</option>' . "\n";
}
?>
</select>
第二項 <select id="myFirstChildSelect">
<option value="">請選擇</option>
</select>
第三項 <select id="mySecondChildSelect">
<option value="">請選擇</option>
</select>
<script type="text/javascript">
$(function () {
// 第一階層對應第二階層
$('#myFirstChildSelect').cascade('#myParentSelect', {
ajax: {
type: "post",
url: 'action.php',
data: { act: 'first', val: $('#myParentSelect').val() },
dataType: "json"
},
template: function(item) { return "<option value='" + item.Value + "'>" + item.Text + "</option>"; },
match: function(selectedValue) { return this.When == selectedValue; }
});
// 第二階層對應第三階層
$('#mySecondChildSelect').cascade('#myFirstChildSelect', {
ajax: {
type: "post",
url: 'action.php',
data: { act: 'second', val: $('#myFirstChildSelect').val() },
dataType: "json"
},
template: function(item) { return "<option value='" + item.Value + "'>" + item.Text + "</option>"; },
match: function(selectedValue) { return this.When == selectedValue; }
});
});
</script>
</body>
</html>
action.php:
<?php
// 資料庫設定
$host_sql = "localhost";
$username_sql = "username";
$password_sql = "password";
$link = mysql_connect($host_sql, $username_sql, $password_sql) or die("無法連結資料庫");
mysql_select_db('target', $link);
mysql_query("SET NAMES UTF8");
if (!empty($_GET['act'])) {
$action = $_GET['act'];
}
if (!empty($_GET['val'])) {
$parentId = $_GET['val'];
}
$list = array();
switch ($action) {
case 'first':
$query = "SELECT id, name FROM table where lv = 2 AND parentid= $parentId";
$result = mysql_query($query, $link);
while ($row = mysql_fetch_assoc($result)) {
$arr = array ('When' => $parentId, 'Value' => $row["ID"], 'Text' => $row["NAME"]);
$list[] = $arr;
}
break;
case 'second':
default :
$query = "SELECT id, name FROM table where lv = 3 AND parentid = $parentId";
$result = mysql_query($query, $link);
while ($row = mysql_fetch_assoc($result)) {
$arr = array ('When' => $parentId, 'Value' => $row["ID"], 'Text' => $row["NAME"]);
$list[] = $arr;
}
break;
}
echo json_encode($list);
哈,這樣就清楚多了呢!當然昨天用字串組的方式也可以囉,其所達到的效果是一樣的啦!提供另一種思考方向^^
June 12,2008
[AJAX] jQuery的多重下拉式選單應用
P.S 2009-04-09 update:有更輕鬆簡單的方法,詳見[AJAX] jQuery的多重下拉式選單應用:Select box manipulation
關於Ajax,我想最棒的地方就是可以於背景呼叫資料庫傳值吧~多重下拉式選單就是一項非常棒的Ajax應用;前幾天Jace丟過來一個國外的網址:jQuery.cascade : Cascading values from forms,這篇文章主要是在說明jQuery的cascade,而它就是用來實現多重下拉式選單的功能。
花了一點時間實作了一下,發現非常簡單就能實現!以前我也作過類似的功能,可是花了我非常多的時間...jQuery把它包裝起來,讓一切變的簡單多了;以下是簡單的範例,給有需要的人參考吧:範例是三階層的關聯式多重下拉式選單,分為index.php(呈現頁)、action.php(Ajax後端資料處理頁)、以及jQuery的cascade
index.php:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery.cascade.js"></script>
<script type="text/javascript" src="jquery.cascade.ext.js"></script>
<script type="text/javascript" src="jquery.templating.js"></script>
</head>
<body>
第一項 <select id="myParentSelect">
<option value="">請選擇</option>
<?php
// 資料庫設定
$host_sql = "localhost";
$username_sql = "username";
$password_sql = "password";
$link = mysql_connect($host_sql, $username_sql, $password_sql) or die("無法連結資料庫");
mysql_select_db('target', $link);
mysql_query("SET NAMES UTF8");
$query = "SELECT id, name FROM table where lv = 1";
$result = mysql_query($query, $link);
while ($row = mysql_fetch_assoc($result)) {
echo '<option value="' . $row["id"] . '">' . $row["name"] . '</option>' . "\n";
}
?>
</select>
第二項 <select id="myFirstChildSelect">
<option value="">請選擇</option>
</select>
第三項 <select id="mySecondChildSelect">
<option value="">請選擇</option>
</select>
<script type="text/javascript">
$(function () {
// 第一階層對應第二階層
$('#myFirstChildSelect').cascade('#myParentSelect', {
ajax: {
type: "post",
url: 'action.php',
data: { act: 'first', val: $('#myParentSelect').val() }
},
template: function(item) { return "<option value='" + item.Value + "'>" + item.Text + "</option>"; },
match: function(selectedValue) { return this.When == selectedValue; }
});
// 第二階層對應第三階層
$('#mySecondChildSelect').cascade('#myFirstChildSelect', {
ajax: {
type: "post",
url: 'action.php',
data: { act: 'second', val: $('#myFirstChildSelect').val() }
},
template: function(item) { return "<option value='" + item.Value + "'>" + item.Text + "</option>"; },
match: function(selectedValue) { return this.When == selectedValue; }
});
});
</script>
</body>
</html>
action.php:
<?php
// 資料庫設定
$host_sql = "localhost";
$username_sql = "username";
$password_sql = "password";
$link = mysql_connect($host_sql, $username_sql, $password_sql) or die("無法連結資料庫");
mysql_select_db('target', $link);
mysql_query("SET NAMES UTF8");
if (!empty($_GET['act'])) {
$action = $_GET['act'];
}
if (!empty($_GET['val'])) {
$parentId = $_GET['val'];
}
$list = '[';
switch ($action) {
case 'first':
$query = "SELECT id, name FROM table where lv = 2 AND parentid= $parentId";
$result = mysql_query($query, $link);
while ($row = mysql_fetch_assoc($result)) {
$list .= '{\'When\':\'' . $parentId . '\',\'Value\':\'' . $row["id"] . '\',\'Text\':\'' . $row["name"] . '\'},';
}
break;
case 'second':
default :
$query = "SELECT id, name FROM table where lv = 3 AND parentid = $parentId";
$result = mysql_query($query, $link);
while ($row = mysql_fetch_assoc($result)) {
$list .= '{\'When\':\'' . $parentId . '\',\'Value\':\'' . $row["id"] . '\',\'Text\':\'' . $row["name"] . '\'},';
}
break;
}
$list .= ']';
echo $list;
實作的重點是在資料的格式:
list = [{'When':'A1','Value':'W','Text':'SubchildA1a'},
{'When':'A1','Value':'X','Text':'SubchildA1b'},
];
其中When代表上一階層的值,Value是此一階層的值,Test則是下拉式選單顯示的文字;要特別注意JavaScript是大小寫敏感的!實作這個範例途中,曾經被大小寫拖了一段時間...後來才發現~所以這地方要特別注意!希望大家都能輕鬆寫出關聯資料庫的多重下拉式選單囉^^
關於Ajax,我想最棒的地方就是可以於背景呼叫資料庫傳值吧~多重下拉式選單就是一項非常棒的Ajax應用;前幾天Jace丟過來一個國外的網址:jQuery.cascade : Cascading values from forms,這篇文章主要是在說明jQuery的cascade,而它就是用來實現多重下拉式選單的功能。
花了一點時間實作了一下,發現非常簡單就能實現!以前我也作過類似的功能,可是花了我非常多的時間...jQuery把它包裝起來,讓一切變的簡單多了;以下是簡單的範例,給有需要的人參考吧:範例是三階層的關聯式多重下拉式選單,分為index.php(呈現頁)、action.php(Ajax後端資料處理頁)、以及jQuery的cascade
index.php:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery.cascade.js"></script>
<script type="text/javascript" src="jquery.cascade.ext.js"></script>
<script type="text/javascript" src="jquery.templating.js"></script>
</head>
<body>
第一項 <select id="myParentSelect">
<option value="">請選擇</option>
<?php
// 資料庫設定
$host_sql = "localhost";
$username_sql = "username";
$password_sql = "password";
$link = mysql_connect($host_sql, $username_sql, $password_sql) or die("無法連結資料庫");
mysql_select_db('target', $link);
mysql_query("SET NAMES UTF8");
$query = "SELECT id, name FROM table where lv = 1";
$result = mysql_query($query, $link);
while ($row = mysql_fetch_assoc($result)) {
echo '<option value="' . $row["id"] . '">' . $row["name"] . '</option>' . "\n";
}
?>
</select>
第二項 <select id="myFirstChildSelect">
<option value="">請選擇</option>
</select>
第三項 <select id="mySecondChildSelect">
<option value="">請選擇</option>
</select>
<script type="text/javascript">
$(function () {
// 第一階層對應第二階層
$('#myFirstChildSelect').cascade('#myParentSelect', {
ajax: {
type: "post",
url: 'action.php',
data: { act: 'first', val: $('#myParentSelect').val() }
},
template: function(item) { return "<option value='" + item.Value + "'>" + item.Text + "</option>"; },
match: function(selectedValue) { return this.When == selectedValue; }
});
// 第二階層對應第三階層
$('#mySecondChildSelect').cascade('#myFirstChildSelect', {
ajax: {
type: "post",
url: 'action.php',
data: { act: 'second', val: $('#myFirstChildSelect').val() }
},
template: function(item) { return "<option value='" + item.Value + "'>" + item.Text + "</option>"; },
match: function(selectedValue) { return this.When == selectedValue; }
});
});
</script>
</body>
</html>
action.php:
<?php
// 資料庫設定
$host_sql = "localhost";
$username_sql = "username";
$password_sql = "password";
$link = mysql_connect($host_sql, $username_sql, $password_sql) or die("無法連結資料庫");
mysql_select_db('target', $link);
mysql_query("SET NAMES UTF8");
if (!empty($_GET['act'])) {
$action = $_GET['act'];
}
if (!empty($_GET['val'])) {
$parentId = $_GET['val'];
}
$list = '[';
switch ($action) {
case 'first':
$query = "SELECT id, name FROM table where lv = 2 AND parentid= $parentId";
$result = mysql_query($query, $link);
while ($row = mysql_fetch_assoc($result)) {
$list .= '{\'When\':\'' . $parentId . '\',\'Value\':\'' . $row["id"] . '\',\'Text\':\'' . $row["name"] . '\'},';
}
break;
case 'second':
default :
$query = "SELECT id, name FROM table where lv = 3 AND parentid = $parentId";
$result = mysql_query($query, $link);
while ($row = mysql_fetch_assoc($result)) {
$list .= '{\'When\':\'' . $parentId . '\',\'Value\':\'' . $row["id"] . '\',\'Text\':\'' . $row["name"] . '\'},';
}
break;
}
$list .= ']';
echo $list;
實作的重點是在資料的格式:
list = [{'When':'A1','Value':'W','Text':'SubchildA1a'},
{'When':'A1','Value':'X','Text':'SubchildA1b'},
];
其中When代表上一階層的值,Value是此一階層的值,Test則是下拉式選單顯示的文字;要特別注意JavaScript是大小寫敏感的!實作這個範例途中,曾經被大小寫拖了一段時間...後來才發現~所以這地方要特別注意!希望大家都能輕鬆寫出關聯資料庫的多重下拉式選單囉^^
June 5,2008
[新知] Comet,Server Push與Ajax的應用?
這二年在Web界引起軒然大波的Ajax,雖然說穿了其內涵不過就是JavaScript的應用,以往也有前輩在許多年前就已經運用這項技術了~然而,在Ajax這個名詞出來以後,這項技術的發展,同時帶動許多著名framework的出現:Prototype、YUI以及目前我們公司使用的jQuery等;在這些好用的框架下,許多以往必須經由繁複程式碼才得以實現的功能,都可以利用函數呼叫的方式輕鬆呈現。
也就因為Ajax的大流行,這幾年有愈來愈多人想把所有本來在單機上執行的桌面程式,全部搬到Web上。桌面程式與網頁程式最大的差別就在,桌面程式與資料庫的連線是一直存在的,但是網頁程式則因為先天上http設計的關係,必須是建立在「客戶端發出請求,伺服端才得以回應」的條件下,才得以與資料庫建立連線;當然,神奇如Ajax也受此制約。這造成了一個問題,如果客戶端想要與伺服端同步更新資料,那應該怎麼辦呢?最常見的方式是Polling,也就是每隔一段時間由客戶端送出請求,看伺服端是否有新的資料回應;只要Polling的間隔時間夠短,客戶端就會有即時更新的錯覺。然而如果資料沒有更新,一來一往無謂的訊息傳送不但浪費頻寬,對伺服端也容易造成龐大負擔。
而Server Push就在需要即時更新資料的需求下出現,早期CGI的網路聊天室就是利用這種方式;如果再結合Ajax,則可以做到背景更新頁面的即時處理。Dojo的作者 Alex Russell 在 2006-03-03 發表的 Comet: Low Latency Data for the Browser,首次提出「Comet」這個新名詞!關於Comet詳細的介紹,可以參考Lighty RoR的文章:Comet For Ruby on Rails and Mongrel與淺談 Comet PUSH Server 架構。
我覺得,此理論的實現,確實可以讓桌面程式網頁化更輕鬆愉快!但是,目前似乎並沒有特別受到Web界的注意...所以,一切還是等網路前輩們的努力推廣吧~小輩的我就先暫時觀望吧^^|||
也就因為Ajax的大流行,這幾年有愈來愈多人想把所有本來在單機上執行的桌面程式,全部搬到Web上。桌面程式與網頁程式最大的差別就在,桌面程式與資料庫的連線是一直存在的,但是網頁程式則因為先天上http設計的關係,必須是建立在「客戶端發出請求,伺服端才得以回應」的條件下,才得以與資料庫建立連線;當然,神奇如Ajax也受此制約。這造成了一個問題,如果客戶端想要與伺服端同步更新資料,那應該怎麼辦呢?最常見的方式是Polling,也就是每隔一段時間由客戶端送出請求,看伺服端是否有新的資料回應;只要Polling的間隔時間夠短,客戶端就會有即時更新的錯覺。然而如果資料沒有更新,一來一往無謂的訊息傳送不但浪費頻寬,對伺服端也容易造成龐大負擔。
而Server Push就在需要即時更新資料的需求下出現,早期CGI的網路聊天室就是利用這種方式;如果再結合Ajax,則可以做到背景更新頁面的即時處理。Dojo的作者 Alex Russell 在 2006-03-03 發表的 Comet: Low Latency Data for the Browser,首次提出「Comet」這個新名詞!關於Comet詳細的介紹,可以參考Lighty RoR的文章:Comet For Ruby on Rails and Mongrel與淺談 Comet PUSH Server 架構。
我覺得,此理論的實現,確實可以讓桌面程式網頁化更輕鬆愉快!但是,目前似乎並沒有特別受到Web界的注意...所以,一切還是等網路前輩們的努力推廣吧~小輩的我就先暫時觀望吧^^|||
May 15,2008
[PHP] Zend_Search_Lucene中文分詞實做
最近在練習中有用到搜尋的功能。一般對MySQL資料庫作搜尋,常用的做法是針對資料表中的特定欄位,用「%」LIKE的方式去尋找。然而這樣的做法常伴隨著許多限制,使用者必須先選定所要輸入的資料欄位,再對其進行搜尋;習慣了Google搜尋所帶來的便利,最理想的方式是只有一個輸入格,且可以在此輸入格中任意輸入,即可對整個資料庫進行搜尋。在MySQL中稱為Full-Text(全文檢索);然而拜完Google大神以後,網路上前輩們幾乎是一面倒的否定全文檢索。最主要的原因是因為它不支持中文!
全文檢索的做法,即是對資料庫裡的資料進行「分詞」的索引處理,有了索引,搜尋起來自然有效率的多;然而中文字不同於英文,一個句子中單獨一個中文字就可能有它的意思,另一個最大的分別在於中文句子可不像英文句子由單字與「空格」組成;建立索引時的「分詞」的動作,就是以空格進行判斷!
全文檢索的問題在網路上一直存在著,但是前輩們似乎都沒有非常完美的解答;甚至有人直接勸退提問者:「全文檢索的功能,是可以讓你寫好幾篇博士論文的研究!」如此可見,Google雲端運算的強大。既然資料庫端無解,我就從PHP的方向著手吧~Google的確是大神,讓我找到了Zend Framework就有分詞的函式Zend Search Lucene;而且原本這個功能其實也不支持中文,萬能的Google大神還幫我找到了支持中文的解決方法!
在PHP製作中文全文搜尋不求人中,作者巨細靡遺的說明了資料夾配置、原始程式碼,還非常貼心的提供範例程式的下載。在如何讓Zend_Search_Lucene支持中文分詞中,作者改良了分詞用的類別,讓中文分詞的動作更加準確!既然有如此完整的範例,我當然是馬上適用在練習中啦!
目前練習所利用的開發框架,是Jace一手打造的Wacow Framework。結合Zend Framework與Smarty,以及許多在專案製作時常會用到的工具,是公司目前專案開發的主力,也是我目前需要熟練的工具。我把建立索引的功能放在首頁,這樣只要有人進入首頁就會觸發建立索引(當然這樣做的代價是每次進首頁的速度都會被拖慢)。因為自動載入類別的關係,在建立索引時不需再額外include或require,程式碼如下:
IndexController.php(部分節錄)
// 建立分詞索引
// 關閉 Notice 錯誤提醒
error_reporting(E_ALL ^ E_NOTICE);
// 資料是 utf8 為編碼的這句為重點。如果你是 utf8 的話必需加入,否則資料會錯誤;另Phpbean是需要另外建立的中文分詞的類別
Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Phpbean());
if (function_exists("set_time_limit") && ! get_cfg_var('safe_mode')) {
set_time_limit(0);
}
$index = new Zend_Search_Lucene('index', true);
$itemTable = new Items();
$itemRowset = $itemTable->fetchAll();
foreach ($itemRowset as $itemRow) {
$url = '/gime/item/detail/id/' . $itemRow->id; // 建立連結
$itemName = $itemRow->name; // 抓出物品名稱
$description = $itemRow->description; // 抓出物品敘述
//儲存網頁的位置以在搜尋結果中連結.
$doc = new Zend_Search_Lucene_Document(); // 建立新的索引文件
$doc->addField(Zend_Search_Lucene_Field::UnIndexed('url', strtolower($url)));
$doc->addField(Zend_Search_Lucene_Field::Text('name', strtolower($itemName), 'utf-8'));
$doc->addField(Zend_Search_Lucene_Field::Text('contents', strtolower($description), 'utf-8'));
$index->addDocument($doc); //把索引文件加到索引中
}
$index->commit(); //提交,及保存索引
Phpbean.php
class Phpbean extends Zend_Search_Lucene_Analysis_Analyzer_Common
{
private $_position;
private $_cnStopWords = array();
public function setCnStopWords($cnStopWords){
$this->_cnStopWords = $cnStopWords;
}
/**
* Reset token stream
*/
public function reset()
{
$this->_position = 0;
$search = array(",", "/", "\", ".", ";", ":", """, "!", "~", "`", "^", "(", ")", "?", "-", "'", "<", ">", "$", "&", "%", "#", "@", "+", "=", "{", "}", "[", "]", ":", ")", "(", ".", "。", ",", "!", ";", "“", "”", "‘", "’", "[", "]", "、", "—", " ", "《", "》", "-", "…", "【", "】","的");
$this->_input = str_replace($search,' ',$this->_input);
$this->_input = str_replace($this->_cnStopWords,' ',$this->_input);
}
/**
* Tokenization stream API
* Get next token
* Returns null at the end of stream
*
* @return Zend_Search_Lucene_Analysis_Token|null
*/
public function nextToken()
{
if ($this->_input === null) {
return null;
}
$len = strlen($this->_input);
while ($this->_position < $len) {
while ($this->_position < $len && $this->_input[$this->_position] == ' ') {
$this->_position++;
}
$termStartPosition = $this->_position;
$temp_char = $this->_input[$this->_position];
$isCnWord = false;
if (ord($temp_char) > 127) {
$i = 0;
while ($this->_position < $len && ord($this->_input[$this->_position]) >127) {
$this->_position = $this->_position + 3;
$i ++;
if ($i == 2) {
$isCnWord = true;
break;
}
}
if ($i == 1) continue;
} else {
while ($this->_position < $len && ctype_alnum($this->_input[$this->_position])) {
$this->_position++;
}
// echo $this->_position.":".$this->_input[$this->_position]."\n";
}
if ($this->_position == $termStartPosition) {
$this->_position++;
continue;
}
$token = new Zend_Search_Lucene_Analysis_Token(
substr($this->_input,
$termStartPosition,
$this->_position - $termStartPosition),
$termStartPosition,
$this->_position);
$token = $this->normalize($token);
if ($isCnWord) $this->_position = $this->_position - 3;
if ($token !== null) {
return $token;
}
}
return null;
}
}
SearchController.php(部分節錄)
Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Phpbean());
$index = new Zend_Search_Lucene('index');
$query = $this->_request->getParam('query'); // 擷取來自表單的關鍵字
$query = trim($query);
if (strlen($query) > 0) {
try {
$query2 = Zend_Search_Lucene_Search_QueryParser::parse(strtolower($query), "utf-8");
$hits = $index->find($query2); // 根據關鍵字找到資料,並將資料回存為物件
}
catch (Zend_Search_Lucene_Exception $ex) {
$hits = array();
}
$numHits = count($hits); // 根據關鍵字找到資料的數量
}
非常簡單的實作;然而就全文檢索來說還是有缺點的!首先,建立分詞索引時必定會耗費系統資源,故比較好的做法是批次定時處理建立索引的動作。第二點是中文的問題,因為中文字詞與連貫的句子的關係,在分詞時是以二個字為一個詞的最基本單位,所以單一個中文字是不會有任何搜尋結果的。最後因為建立分詞索引為觸發事件,如果沒有去觸發它就無法更新分詞至目前資料庫的最新狀態。我覺得分詞索引的方式很像是MySQL的View資料表,也是將資料表中的欄位作一個資料上的更新,只是它沒有欄位的限制,可以針對建立的「詞」索引進行搜尋。就某方面來說是很好用的功能,也不失為中文在全文索引時的一種解決方案。^^
全文檢索的做法,即是對資料庫裡的資料進行「分詞」的索引處理,有了索引,搜尋起來自然有效率的多;然而中文字不同於英文,一個句子中單獨一個中文字就可能有它的意思,另一個最大的分別在於中文句子可不像英文句子由單字與「空格」組成;建立索引時的「分詞」的動作,就是以空格進行判斷!
全文檢索的問題在網路上一直存在著,但是前輩們似乎都沒有非常完美的解答;甚至有人直接勸退提問者:「全文檢索的功能,是可以讓你寫好幾篇博士論文的研究!」如此可見,Google雲端運算的強大。既然資料庫端無解,我就從PHP的方向著手吧~Google的確是大神,讓我找到了Zend Framework就有分詞的函式Zend Search Lucene;而且原本這個功能其實也不支持中文,萬能的Google大神還幫我找到了支持中文的解決方法!
在PHP製作中文全文搜尋不求人中,作者巨細靡遺的說明了資料夾配置、原始程式碼,還非常貼心的提供範例程式的下載。在如何讓Zend_Search_Lucene支持中文分詞中,作者改良了分詞用的類別,讓中文分詞的動作更加準確!既然有如此完整的範例,我當然是馬上適用在練習中啦!
目前練習所利用的開發框架,是Jace一手打造的Wacow Framework。結合Zend Framework與Smarty,以及許多在專案製作時常會用到的工具,是公司目前專案開發的主力,也是我目前需要熟練的工具。我把建立索引的功能放在首頁,這樣只要有人進入首頁就會觸發建立索引(當然這樣做的代價是每次進首頁的速度都會被拖慢)。因為自動載入類別的關係,在建立索引時不需再額外include或require,程式碼如下:
IndexController.php(部分節錄)
// 建立分詞索引
// 關閉 Notice 錯誤提醒
error_reporting(E_ALL ^ E_NOTICE);
// 資料是 utf8 為編碼的這句為重點。如果你是 utf8 的話必需加入,否則資料會錯誤;另Phpbean是需要另外建立的中文分詞的類別
Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Phpbean());
if (function_exists("set_time_limit") && ! get_cfg_var('safe_mode')) {
set_time_limit(0);
}
$index = new Zend_Search_Lucene('index', true);
$itemTable = new Items();
$itemRowset = $itemTable->fetchAll();
foreach ($itemRowset as $itemRow) {
$url = '/gime/item/detail/id/' . $itemRow->id; // 建立連結
$itemName = $itemRow->name; // 抓出物品名稱
$description = $itemRow->description; // 抓出物品敘述
//儲存網頁的位置以在搜尋結果中連結.
$doc = new Zend_Search_Lucene_Document(); // 建立新的索引文件
$doc->addField(Zend_Search_Lucene_Field::UnIndexed('url', strtolower($url)));
$doc->addField(Zend_Search_Lucene_Field::Text('name', strtolower($itemName), 'utf-8'));
$doc->addField(Zend_Search_Lucene_Field::Text('contents', strtolower($description), 'utf-8'));
$index->addDocument($doc); //把索引文件加到索引中
}
$index->commit(); //提交,及保存索引
Phpbean.php
class Phpbean extends Zend_Search_Lucene_Analysis_Analyzer_Common
{
private $_position;
private $_cnStopWords = array();
public function setCnStopWords($cnStopWords){
$this->_cnStopWords = $cnStopWords;
}
/**
* Reset token stream
*/
public function reset()
{
$this->_position = 0;
$search = array(",", "/", "\", ".", ";", ":", """, "!", "~", "`", "^", "(", ")", "?", "-", "'", "<", ">", "$", "&", "%", "#", "@", "+", "=", "{", "}", "[", "]", ":", ")", "(", ".", "。", ",", "!", ";", "“", "”", "‘", "’", "[", "]", "、", "—", " ", "《", "》", "-", "…", "【", "】","的");
$this->_input = str_replace($search,' ',$this->_input);
$this->_input = str_replace($this->_cnStopWords,' ',$this->_input);
}
/**
* Tokenization stream API
* Get next token
* Returns null at the end of stream
*
* @return Zend_Search_Lucene_Analysis_Token|null
*/
public function nextToken()
{
if ($this->_input === null) {
return null;
}
$len = strlen($this->_input);
while ($this->_position < $len) {
while ($this->_position < $len && $this->_input[$this->_position] == ' ') {
$this->_position++;
}
$termStartPosition = $this->_position;
$temp_char = $this->_input[$this->_position];
$isCnWord = false;
if (ord($temp_char) > 127) {
$i = 0;
while ($this->_position < $len && ord($this->_input[$this->_position]) >127) {
$this->_position = $this->_position + 3;
$i ++;
if ($i == 2) {
$isCnWord = true;
break;
}
}
if ($i == 1) continue;
} else {
while ($this->_position < $len && ctype_alnum($this->_input[$this->_position])) {
$this->_position++;
}
// echo $this->_position.":".$this->_input[$this->_position]."\n";
}
if ($this->_position == $termStartPosition) {
$this->_position++;
continue;
}
$token = new Zend_Search_Lucene_Analysis_Token(
substr($this->_input,
$termStartPosition,
$this->_position - $termStartPosition),
$termStartPosition,
$this->_position);
$token = $this->normalize($token);
if ($isCnWord) $this->_position = $this->_position - 3;
if ($token !== null) {
return $token;
}
}
return null;
}
}
SearchController.php(部分節錄)
Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Phpbean());
$index = new Zend_Search_Lucene('index');
$query = $this->_request->getParam('query'); // 擷取來自表單的關鍵字
$query = trim($query);
if (strlen($query) > 0) {
try {
$query2 = Zend_Search_Lucene_Search_QueryParser::parse(strtolower($query), "utf-8");
$hits = $index->find($query2); // 根據關鍵字找到資料,並將資料回存為物件
}
catch (Zend_Search_Lucene_Exception $ex) {
$hits = array();
}
$numHits = count($hits); // 根據關鍵字找到資料的數量
}
非常簡單的實作;然而就全文檢索來說還是有缺點的!首先,建立分詞索引時必定會耗費系統資源,故比較好的做法是批次定時處理建立索引的動作。第二點是中文的問題,因為中文字詞與連貫的句子的關係,在分詞時是以二個字為一個詞的最基本單位,所以單一個中文字是不會有任何搜尋結果的。最後因為建立分詞索引為觸發事件,如果沒有去觸發它就無法更新分詞至目前資料庫的最新狀態。我覺得分詞索引的方式很像是MySQL的View資料表,也是將資料表中的欄位作一個資料上的更新,只是它沒有欄位的限制,可以針對建立的「詞」索引進行搜尋。就某方面來說是很好用的功能,也不失為中文在全文索引時的一種解決方案。^^
April 18,2008
[新知] 初探物件導向(二)
這幾天承蒙Jace的諄諄教誨,當初一知半解的物件導向現在總算是有些概念了!
承接上篇的繼承,多型是敘述繼承的狀態,解釋繼承的概念:由於子類別繼承於相同的父類別,因此由子類別建立的物件當然也繼承父類別的方法。而這種「不同物件卻有相同方法」的狀態,即是多型。
抽象類別,依照我的理解可以解釋為一個不能被New(建立)的父類別;當多個類別擁有許多共通的實體變數與方法時,就可以被獨立抽離出來成為一個抽象類別的概念。另外還有抽象方法,代表該方法不能被實作,但繼承該類別的子類別,此方法一定要被實作執行。
介面(interface)則類似抽象,但介面沒有實體變數,只有方法,而且該方法不能被實作(抽象方法),而是經由繼承(implements)自該介面的類別實作,且一定要被執行。
關於抽象與介面,Jace有非常簡潔的說明...不過這太簡潔了吧,不懂的人應該還是不懂?(還有另外一個關於「介面」的說明...)
承接上篇的繼承,多型是敘述繼承的狀態,解釋繼承的概念:由於子類別繼承於相同的父類別,因此由子類別建立的物件當然也繼承父類別的方法。而這種「不同物件卻有相同方法」的狀態,即是多型。
抽象類別,依照我的理解可以解釋為一個不能被New(建立)的父類別;當多個類別擁有許多共通的實體變數與方法時,就可以被獨立抽離出來成為一個抽象類別的概念。另外還有抽象方法,代表該方法不能被實作,但繼承該類別的子類別,此方法一定要被實作執行。
介面(interface)則類似抽象,但介面沒有實體變數,只有方法,而且該方法不能被實作(抽象方法),而是經由繼承(implements)自該介面的類別實作,且一定要被執行。
關於抽象與介面,Jace有非常簡潔的說明...不過這太簡潔了吧,不懂的人應該還是不懂?(還有另外一個關於「介面」的說明...)
[PHP] 表單輸入時對於HTML的過濾
在PHP中最常見的應用就是互動表單,因此接收用戶端資訊是非常常見的事!然而俗話說:「世風日下,人心不古」,這年頭誰知道用戶端的人在想些什麼?用戶端送出的資訊很有可能會包含一些惡意的語法,對於24小時暴露在網路環境的網站來說,時時刻刻都得小心防範駭客的攻擊,提升自我的資訊安全觀念非常重要。所以在接收用戶端資訊後,存入資料庫之前,都會先對其進行基本的過濾;第一個要判斷的就是HTML語法的攻擊!
許多惡意語法都是建立在HTML上,PHP本身有提供轉換HTML碼的函數:htmlspecialchars()與htmlentities();其中htmlspecialchars()只會轉換HTML相關碼:
之前在題目試作/哇寶基本能力測試一文中,也有提到相關的觀念。另外附上那個時候google到的一個國外防止XSS的網頁:PHP XSS (cross site scripting) filter function,他有對HTML作是否可能被當作惡意的語法作判斷,不過測試後發現對中文的處理好像有點問題...就當作是英文的過濾函式吧~
許多惡意語法都是建立在HTML上,PHP本身有提供轉換HTML碼的函數:htmlspecialchars()與htmlentities();其中htmlspecialchars()只會轉換HTML相關碼:
- '&' => '&'
- '"' => '"'
- ''' => '''
- '<' => '<'
- '>' => '>'
之前在題目試作/哇寶基本能力測試一文中,也有提到相關的觀念。另外附上那個時候google到的一個國外防止XSS的網頁:PHP XSS (cross site scripting) filter function,他有對HTML作是否可能被當作惡意的語法作判斷,不過測試後發現對中文的處理好像有點問題...就當作是英文的過濾函式吧~
April 16,2008
[新知] 初探物件導向
說來慚愧,之前完全沒有注意物件導向的定義與使用;但是因為現在工作所使用的撰寫方式為全物件導向,這意味著我要重頭學起~從《深入淺出JAVA 第二版》開始!
事實上維基百科對於物件導向程式設計的介紹也非常完整,但是頂多也就這麼一個頁面的介紹,要把物件導向的全貌解釋清楚,還略嫌不足;當初看完整篇介紹,其實對物件導向仍是一知半解的狀態...
之前Jace就在如何學習ZendFramework的介紹文中推薦過《深入淺出JAVA 第二版》這本書。我目前先挑選書中對物件導向介紹的章節研讀:2、拜訪物件村;4、物件的行為;7、物件村的優質生活(繼承與多型);8、深入多形;9、物件的前世今生。目前已經讀完類別、物件、封裝與繼承的觀念;現在可以說是稍微有一點點概念了~
類別(class)他就像是一個規則、一個模子,物件(Object)則是利用這個規則、模子做出來的東西。類別只是規範,如果要在程式中使用的話,就一定得先New一個物件出來!類別包含實體變數(instance variables或稱屬性)與方法(method),也被稱作是狀態與行為;實體變數被用來記載此類別已知的事物,而方法則是用來說明類別執行的動作。類別所描述的是物件「知道什麼」與「執行什麼」!
狀態影響行為,行為影響狀態。方法可以引用實體變數的值作判斷,實體變數可以用參數的方式影響方法;而方法則可以利用的set或是get的方式,對實體變數作存取的動作。封裝的意義在於避免洩漏資料,為了不讓實體變數就這樣直接暴露在隨時隨地可以任意設定的狀況下,在習慣上會將實體變數標示為private,另外利用標示為public的方法setter與getter,對實體變數進行存取,也可在此同時進行限制及過濾。
繼承也是物件導向的特色之一。子類別可以用繼承的方式沿用父類別的實體變數及方法;唯父類別實體變數與方法的標示需為public或protect。A extends B意味著B的種類中含有A,B擁有的所有特性A也會有,然而A擁有的特性B並不一定會有;如白馬是馬,白馬跟馬一樣有長長的臉而且跑的很快,但是並不代表所有的馬都是白色的。子類別繼承父類別所有的方法,但是也可以依照子類別自己的需求,建立新方法;或是完全改寫繼承自父類別的方法(override),但實體變數不行。
事實上維基百科對於物件導向程式設計的介紹也非常完整,但是頂多也就這麼一個頁面的介紹,要把物件導向的全貌解釋清楚,還略嫌不足;當初看完整篇介紹,其實對物件導向仍是一知半解的狀態...
之前Jace就在如何學習ZendFramework的介紹文中推薦過《深入淺出JAVA 第二版》這本書。我目前先挑選書中對物件導向介紹的章節研讀:2、拜訪物件村;4、物件的行為;7、物件村的優質生活(繼承與多型);8、深入多形;9、物件的前世今生。目前已經讀完類別、物件、封裝與繼承的觀念;現在可以說是稍微有一點點概念了~
類別(class)他就像是一個規則、一個模子,物件(Object)則是利用這個規則、模子做出來的東西。類別只是規範,如果要在程式中使用的話,就一定得先New一個物件出來!類別包含實體變數(instance variables或稱屬性)與方法(method),也被稱作是狀態與行為;實體變數被用來記載此類別已知的事物,而方法則是用來說明類別執行的動作。類別所描述的是物件「知道什麼」與「執行什麼」!
狀態影響行為,行為影響狀態。方法可以引用實體變數的值作判斷,實體變數可以用參數的方式影響方法;而方法則可以利用的set或是get的方式,對實體變數作存取的動作。封裝的意義在於避免洩漏資料,為了不讓實體變數就這樣直接暴露在隨時隨地可以任意設定的狀況下,在習慣上會將實體變數標示為private,另外利用標示為public的方法setter與getter,對實體變數進行存取,也可在此同時進行限制及過濾。
繼承也是物件導向的特色之一。子類別可以用繼承的方式沿用父類別的實體變數及方法;唯父類別實體變數與方法的標示需為public或protect。A extends B意味著B的種類中含有A,B擁有的所有特性A也會有,然而A擁有的特性B並不一定會有;如白馬是馬,白馬跟馬一樣有長長的臉而且跑的很快,但是並不代表所有的馬都是白色的。子類別繼承父類別所有的方法,但是也可以依照子類別自己的需求,建立新方法;或是完全改寫繼承自父類別的方法(override),但實體變數不行。
April 15,2008
[新知] MVC的觀念
經由透視WebMVC的作者Jace親自講解,讓我稍微了解到什麼是MVC架構。透過一個簡單的留言版程式的範例解構,重新建立一個符合MVC架構的留言版程式。
依照過去一般留言版程式的撰寫模式,先將其分為二個部分:一個是業務邏輯、表現邏輯。業務邏輯(business)是指PHP控制與執行的部分;表現邏輯(present)則是指單純HTML或XML輸出呈現的部分。一但程式分為此二部分,表現邏輯就相當於View的部分;之後再將業務邏輯分成Model與Controller。
Model在留言版程式中所代表的角色,就有點像是「取得資料」這一部分;不論取得資料的方式是經由文字檔或是資料庫的連結讀出寫入,這一塊在MVC的架構中就相當於Model的部分。所以在範例的留言版程式中,Guestbook.php扮演的角色是用來與資料來源溝通的管道。
Controller在留言版程式中所代表的角色,就比較像是「操縱動作」這一部分;從留言版程式的功能面來說,分為選擇頁面(首頁/新增頁/RSS的XML頁面)、新增資料時取得的變數與重新導向。如果說Guestbook.php是與資料來源溝通的管道,Actions.php就像是觸發事件,以及運用Guestbook.php去產生動作的角色;當然最後所呈現的結果是View。所以Controller可以說是串聯Model與View的重要橋樑。
其後又提到一些物件導向的觀念,因為我這方面實在是很弱;所以整個聽下來有些吃力。在我粗淺的理解後導出的一個見解是:利用抽象化後繼承父類別的子類別,可以減少使用判斷式,以及更動到原有程式碼的機會。大概是這樣的意思吧?(抓頭)關於物件導向,Jace建議我看《深入淺出 Java 程式設計 第二版》這本書,我想我得好好花時間研究一下囉!
依照過去一般留言版程式的撰寫模式,先將其分為二個部分:一個是業務邏輯、表現邏輯。業務邏輯(business)是指PHP控制與執行的部分;表現邏輯(present)則是指單純HTML或XML輸出呈現的部分。一但程式分為此二部分,表現邏輯就相當於View的部分;之後再將業務邏輯分成Model與Controller。
Model在留言版程式中所代表的角色,就有點像是「取得資料」這一部分;不論取得資料的方式是經由文字檔或是資料庫的連結讀出寫入,這一塊在MVC的架構中就相當於Model的部分。所以在範例的留言版程式中,Guestbook.php扮演的角色是用來與資料來源溝通的管道。
Controller在留言版程式中所代表的角色,就比較像是「操縱動作」這一部分;從留言版程式的功能面來說,分為選擇頁面(首頁/新增頁/RSS的XML頁面)、新增資料時取得的變數與重新導向。如果說Guestbook.php是與資料來源溝通的管道,Actions.php就像是觸發事件,以及運用Guestbook.php去產生動作的角色;當然最後所呈現的結果是View。所以Controller可以說是串聯Model與View的重要橋樑。
其後又提到一些物件導向的觀念,因為我這方面實在是很弱;所以整個聽下來有些吃力。在我粗淺的理解後導出的一個見解是:利用抽象化後繼承父類別的子類別,可以減少使用判斷式,以及更動到原有程式碼的機會。大概是這樣的意思吧?(抓頭)關於物件導向,Jace建議我看《深入淺出 Java 程式設計 第二版》這本書,我想我得好好花時間研究一下囉!
April 11,2008
[AJAX] 初探jQuery
因為哇寶在Ajax的應用上是採用jQuery,所以利用時間稍為了解一下。
我以往在處理Ajax時大部分是借用網上的範例JS檔,所以它通常都有一套制式的規範,哪裡要new,哪裡要丟參數,範例上都寫得清清楚楚,只要按部就班,通常都能很快達到我想要的功能。另外一種是土法煉鋼,自己造輪子;先從JS丟參數到php,再由php切我要的參數去跟伺服端Query我要的資料,最後呈現。這二種方式其實好像都不是正統的方式說...在看完jQuery的介紹後更是讓我有這樣的感覺~
網路上其實有很多淺顯易懂的介紹,我是看:國二學生認真打雜的jQuery 學習心得筆記一系列文章稍微接觸jQuery這個Framework的。詳盡且生動有趣的介紹,讓我對jQuery有粗淺的認識!有興趣可以去逛逛~^^
我以往在處理Ajax時大部分是借用網上的範例JS檔,所以它通常都有一套制式的規範,哪裡要new,哪裡要丟參數,範例上都寫得清清楚楚,只要按部就班,通常都能很快達到我想要的功能。另外一種是土法煉鋼,自己造輪子;先從JS丟參數到php,再由php切我要的參數去跟伺服端Query我要的資料,最後呈現。這二種方式其實好像都不是正統的方式說...在看完jQuery的介紹後更是讓我有這樣的感覺~
網路上其實有很多淺顯易懂的介紹,我是看:國二學生認真打雜的jQuery 學習心得筆記一系列文章稍微接觸jQuery這個Framework的。詳盡且生動有趣的介紹,讓我對jQuery有粗淺的認識!有興趣可以去逛逛~^^
April 6,2008
[PHP] ZendFramework 1.5.1安裝
ZendFramework是PHP的一個開發用框架,主要以PHP5作為撰寫時的基礎。要使用之前當然得先建立環境,以下是安裝的順序:參考「在Zend Framework上開發一個HelloWorld」
1、首先先從ZendFramework的官方網站下在最新版本的ZendFramework 1.5.1;解壓縮後放在任意資料夾。我是放在「C:\ZendFramework」這個目錄下。
2、修改Apache httpd.conf設定:
(1)啟動 Apache的 .htaccess功能,搜尋「AllowOverride」 並將其設定為 All
(2) 開啟 LoadModule rewrite_module modules/mod_rewrite.so。
3、修改PHP php.ini設定:
(1)設定include_path = ".;C:\ZendFramework"
(2)開啟extension=php_pdo.dll、extension=php_pdo_mysql.dll
重新啟動Apache,如此一來基本的環境算是建置完成了。
1、首先先從ZendFramework的官方網站下在最新版本的ZendFramework 1.5.1;解壓縮後放在任意資料夾。我是放在「C:\ZendFramework」這個目錄下。
2、修改Apache httpd.conf設定:
(1)啟動 Apache的 .htaccess功能,搜尋「AllowOverride」 並將其設定為 All
(2) 開啟 LoadModule rewrite_module modules/mod_rewrite.so。
3、修改PHP php.ini設定:
(1)設定include_path = ".;C:\ZendFramework"
(2)開啟extension=php_pdo.dll、extension=php_pdo_mysql.dll
重新啟動Apache,如此一來基本的環境算是建置完成了。
