2008年6月17日 星期二

Zend_Acl_Resource的樹狀結構



Zend_Acl_Resource的樹狀結構

要建立Zend_Acl_Resource的樹狀結構,對我來說難度滿高的,想了很久,都想不出解法,最後看了陳瑩光老師寫的新版學務系統中的認證模組,找到了解法,不過雖然解法找到了,卻不明瞭為何要這樣寫,思考了很久,才把需要了解的區塊,一個個弄清楚,再把整個解法背後運用的思考邏輯用freemind全部畫出來,再依照這張畫出來的圖,自己弄出一個建構Zend_Acl_Resource樹狀結構的原型,我自己寫的程式改良了原來程式碼的部份寫法,不過,沒有將錯誤機制考慮在內,也就是說,在資料庫內的資料都必須是正確的。



建立Zend_Acl_Resource樹狀結構的資料庫內的欄位資料

資料表:resource

欄位
id----------Primary key(resource的名稱)
parent_id---參照id或是null


要建立Zend_Acl_Resource的樹狀結構的第一步就是將資料從資料庫中抓到陣列中,如果不這麼做,那麼每建立一層樹狀結構就要把資料表的全部資料讀取一遍,是非常耗時的,如果把資料抓到陣列中,由於陣列是存放在記憶體中,比起存放在資料表中的資料,讀取速度快非常多,為了效能的考量,一定要先將資料讀入陣列中。

第二步就是開始建立整個樹狀結構,原理是利用迴圈的方式,第一次迴圈會找出所有id未註冊且parent_id是null的陣列值,註冊為最上層的resource,第二次迴圈會找出所有id未註冊且parent_id(參照到最上層resource的id)已註冊的陣列值,註冊為第二層的resource,第三次迴圈會找出所有id未註冊且parent_id(參照到第二層的resource的id)已註冊的陣列值,註冊為第三層的resource。這個迴圈會一直持續到所有id都註冊為止。


Zend_Loader::loadClass('Zend_Acl');
Zend_Loader::loadClass('Zend_Acl_Role');
Zend_Loader::loadClass('Zend_Acl_Resource');
Zend_Loader::loadClass('Zend_Db');
Zend_Loader::loadClass('Zend_Config');
Zend_Loader::loadClass('Zend_Registry');

$baseDir=Zend_Registry::get('baseDir');

$config=new Zend_Config(require($baseDir.'/application/etc/db.php'));

/**
* 讀取資料表欄位,將資料表內的資料讀入陣列
*/
$db=Zend_Db::factory($config->public);
$db->query('set names utf8');
$sql='select id,parent_id from resource';
$stmt=$db->query($sql);
$rows=$stmt->fetchAll();




/**
* 建立resource的樹狀結構
*/
$acl=new Zend_Acl();
do{
$flag=false;
foreach($rows as $row){

/**
* 建立resource樹狀結構的判斷流程程式碼
*/
if(!$acl->has($row['id']) && ($row['parent_id']===null || $acl->has($row['parent_id']) ) ){
$acl->add(new Zend_Acl_Resource($row['id']),$row['parent_id']);
}

/**
* 判斷所有id是否已註冊為resource,如果有未註冊的id,旗標設為true,繼續執行迴圈
* 如果所有的id都已註冊,就會跳出迴圈
*/
if(!$acl->has($row['id']))
$flag=true;

}
}while($flag);

2008年6月11日 星期三

php上傳物件

參考網址

http://www.devshed.com/c/a/PHP/Developing-a-Modular-Class-For-a-PHP-File-Uploader/1/


檔案上傳物件

上列網址是一個檔案上傳物件的實例,用了一些php內建的函數及物件,使用內建函數及物件,執行效率會提高(因為是用c寫的),程式內也用了迴圈的方式把全域陣列$_FILE中的key/value都對應到物件中的屬性,這樣就不用寫一堆討人厭的$_FILE['userfile']['name']這類一長串不好輸入的字元,整個程式碼很清爽。

撰寫這個物件的背景知識

使用的函數及物件
Exception物件
in_array()函數
move_uploaded_file()函數

使用的全域陣列
$_FILE['userfile']['name'] 原始檔名
$_FILE['userfile']['tmp_name'] 儲在server上的暫存檔名
$_FILE['userfile']['type'] 檔案的mime型態
$_FILE['userfile']['size'] 檔案大小,單位是byte
$_FILE['userfile']['error'] 上傳錯誤,錯誤代碼查php manual就知道了


從上列網址post上來的上傳物件的範例程式碼


class FileUploader{

private $uploadFile;

private $name;

private $tmp_name;

private $type;

private $size;

private $error;

private $allowedTypes=array
('image/jpeg','image/gif','image/png','text/plain','application/ms-word');

public function __construct($uploadDir='C:uploaded_files'){

if(!is_dir($uploadDir)){

throw new Exception('Invalid upload directory.');

}

if(!count($_FILES)){

throw new Exception('Invalid number of file upload parameters.');

}

foreach($_FILES['userfile'] as $key=>$value){

$this->{$key}=$value;

}

if(!in_array($this->type,$this->allowedTypes)){

throw new Exception('Invalid MIME type of target file.');

}

$this->uploadFile=$uploadDir.basename($this->name);

}

// upload target file to specified location

public function upload(){

if(move_uploaded_file($this->tmp_name,$this->uploadFile)){

return true;

}

// throw exception according to error number

switch($this->error){

case 1:

throw new Exception('Target file exceeds maximum allowed size.');

break;

case 2:

throw new Exception('Target file exceeds the MAX_FILE_SIZE value specified on the upload form.');

break;

case 3:

throw new Exception('Target file was not uploaded completely.');

break;

case 4:

throw new Exception('No target file was uploaded.');

break;

case 6:

throw new Exception('Missing a temporary folder.');

break;

case 7:

throw new Exception('Failed to write target file to disk.');

break;

case 8:

throw new Exception('File upload stopped by extension.');

break;

}

}

}

?>



物件使用範例




try{

if($_POST['send']){

require_once 'fileuploader.php';

$fileUploader=new FileUploader();

if($fileUploader->upload()){

echo 'Target file uploaded successfully!';

}

}

}




catch(Exception $e){

echo $e->getMessage();

exit();

}

?>

2008年6月10日 星期二

郵件過量

用evolution收信,一段時間後信箱容量超過2G,就不能再收信,覺得很悶,找了一下郵件的放置位置,發現evolution中同一個資料夾的郵件都放在同一個檔案裡頭,難怪資料夾的容量到了一定上限就不能再存了.

上網找了一下資料,解決方式不難,只要再建一個資料夾,建立新的郵件規則,將收到的信都存到這個資料夾中,就解決了.

測試了一下,果然可以繼續收信,只不過不知道有沒有漏掉重要的信件.

workbench的使用



http://dev.mysql.com/downloads/workbench/5.0.html

MySQL Workbench可以很方便的畫出EER(enhance entity relationship)圖,圖形介面的操作方式非常容易上手,可以很快的畫出資料表跟資料表之間的關係,要修改資料表或資料庫的設定也非常容易,用滑鼠點一點、按一按,就修改好了,這種針對資料庫的專用工具,比起自己用freemind或dia畫EER圖,更有效率,由於Workbench將資料庫層面的物件關係加在設計裡頭,也更容易看出資料表之間的關連,不用自己發揮想像力,克難地使用不適當地工具,進行資料庫的設計。

用workbench畫好EER圖後,這張EER圖可以依使用者的需求輸出成pdf、圖檔或是sql命令,最方便地部份就是輸出成sql命令了,將資料庫設計好後,直接將sql命令匯到mysql server後,整個資料庫就在server上全部建立完成了。只不過根據我自己的測試,workbench有一項小缺點,他不會檢查foreign key的型態與referenced key的型態是否一致,這二個如果不一致是沒辦法在mysql裡頭建立資料表的,但workbench不會檢查這項錯誤,如果將這類的sql命令匯入mysql中,資料表會無法建立,致於還有沒有其他的缺點,就不清楚了。

workbench目前只有window版,沒有linux版,有點不方便,我家裡的電腦已經換成ubuntu了,如果沒有linux版,在家裡就沒辦法用了,不過網站上的roadmap,指出今年會推出linux版,看來需要耐心等待linux版的推出,不然就要再想想別的辦法了。

2008年6月6日 星期五

Zend Controller設計概念

Zend Controller是Zend Framework的核心元件,Zend Controller 實做了MVC及Front Controller的設計模式,使用MVC可以將網站程式的商業邏輯及呈現外貌的程式碼分離,Front Controller會將使用者的送出的要求全部導向單人入口。

為了顧及程式的延展性,Zend Controller可以讓程式設計師subclass,或是使用interface及abstract的方式擴增程式的功能,或是撰寫plugin及action helper達到相同的功能。

Zend Controller的設計提供一個撰寫程式的架構,基本上,遵循這些設計模式,幾乎大部份的程式功能都可以有條不紊的實做出來,Zend Controller的架構比自己建立的架構,具有更高的流通性,由於Zend網站上就有現成的文件及程式碼解說,與別人進行交流時不用再重頭適應彼此的撰寫模式及架構,也可避免大家都浪費心力做同一件事情--建立基礎架構,而且Zend Controller的架構都是高手建構出來的,模仿他們的設計,可以吸取高手的菁華,快速提升程式碼的品質。

2008年6月5日 星期四

css概念


參考網址

http://www.hsiu28.net/style/

http://css.1keydata.com/tw/



如果以我的思考方式解釋css(cascading style sheet),css是一種表現網頁物件的方式,在css中,每個物件都是一個box,這個box中可以出現文字、圖片,也能設定這個box的邊框大小、背景的樣式,box中出現的文字、圖片也可以再進行設定,在網頁中出現的大大小小的box,組成了整個網頁的外貌。

組成網頁的box,可以在box中再裝進其他的box,或是進行box位置的排列,這會產生許多不同的變化,讓網頁產生不同的面貌,使用這種方式設計網頁,會使整個網頁的程式碼減少,因為是以box為單位,進行設定,而不是對所有的單一元素進行設定,而且不同的box,可以使用套用相同的設定,這樣不但使程式碼減少,而且網頁內容—html碼,及網頁呈現方式—css碼,可以完全分離,如果要改變網頁的外貌,只要更改css碼,所有的網頁外觀就會立刻更換,而不用繁鎖的一一更改所有網頁元素的設定。

花了點時間,用freemind把css的模式畫出來,也標記了常用的屬性,這樣要用到時就比較方便了,不用再上網查css屬性要怎麼用,也比較不容易在box model的迷宮中走失。

善用工具,不求甚解

以前從國小升上國中時,翻看數學,物理,化學,這些科目的教科書,感覺有如天書,經過一段時間後,與書本那種遙遠的距離感消失了,但那神秘感也消失殆盡,只感覺這些只是用另一種不常見的符號,解釋周遭現象的另一種方式.但心裡總覺得這些背後應該還有更神秘的原理支配著,這種感覺常讓我懷疑,學習這些東西,並沒有真的碰到核心.

剛接觸php程式語言時,也是一頭霧水,等到了解基本語法時,就會感覺好像只是運用一些語句,組合出各種狀況下要電腦做的事情,似乎又是另外一種換句話說的方式,底層的運作到底是怎麼樣的一個狀況,這個問題一直縈繞心頭.

接觸的電腦知識稍微廣些後,知道要通透了解整個的運作是不可能的,跟php相關的電腦議題含括apach,mysql,linux,c語言,設計模式等,要再搞懂底下的這些就要再花很大的功夫,如果再延伸下去,那是沒完沒了的.

很多底層的東西,只要大概了解就好,不須全盤鑽研,就像建築師,只要能善用建築材料,組合出客戶想要的建築物就可以了,甚於房子怎麼搭,鋼筋怎麼綁,那是另一種專業,不需太過清楚,如果一個建築師花大量的心力在研究怎麼砌磚頭,那他大概不會是一位出色的建築師,也許磚頭砌得很好,但建物的造型設計,人性化等方面大概很難兼顧.

接觸php必須以宏觀角度審視整個程式運作流程,致於函數的底層運作機制,不須全盤了解,就像建築師一樣,只要會善用最適當的材料,工法,就能組合出最佳設計,php也一樣,善用工具,才能以宏觀角度使整 個程式運作更符合需求,否則會陷入不斷追求最佳工具的迴圈中,跳脫不出來.