顯示具有 Zend Framework 標籤的文章。 顯示所有文章
顯示具有 Zend Framework 標籤的文章。 顯示所有文章

2009年2月25日 星期三

Zend_File的功能

Zend Framework的文件上列出Zend_File的功能算非常完整的,看文件看得非常認真,想說,就用現成的套件就可以了,把文件都看完後,上線實做卻發現一堆的功能都是正在開發中,實際檢視原始碼,才發現天啊! 根本就沒有這些功能的程式碼,心裡真是圈圈叉叉。

解決方式有兩個,自己寫一個物件或是在每段程式碼都代入上傳的程式碼,當然是寫一個物件,省得多寫一堆東西。煩啊!!

2008年12月6日 星期六

連接db的問題

使用Zend_Db連接資料庫時,最好使用$db->closeConnection()關閉每次
使用後的資料庫連結,以免產生一堆有的沒的問題,
這是上線後的網站實際發生的狀況,使用$db->closeConnection()後就少了一些問題,
win上的記憶體管理做得似乎並不好。

Zend Framework出現空白頁

錯誤訊息顯示:
Fatal error: Cannot redeclare class Zend_Loader in .....lib\Zend\Loader.php on line 31

查了一下php manual
require及include的差別

require:只要在程式中都會執行檔案含入的動作,不論是不是在判斷式中

include:只有判斷式正確,才會執行檔案含入的動作


看了一下含入的路徑,由於是windows平台
路徑是: d:\a\b\c/lib

改了一下程式碼

/lib改成 DIRECTORY_SEPARATOR.'lib'

路徑就成了d:\a\b\c\lib


經過這些手續,暫時消除這個問題,不過還要再觀察一陣子。

2008年10月14日 星期二

沒有轉址軟體時,使用zend framework的解法

http://akrabat.com/2008/06/03/zend-framework-urls-without-mod_rewrite/

2008年10月9日 星期四

iis上支援轉址的免費軟體

http://cheeso.members.winisp.net/IIRF.aspx

2008年9月25日 星期四

身份證字號的validator

下面程式是參考
http://zh.wikipedia.org/wiki/%E4%B8%AD%E8%8F%AF%E6%B0%91%E5%9C%8B%E5%9C%8B%E6%B0%91%E8%BA%AB%E5%88%86%E8%AD%89


這篇文章的身份證字號檢查公式,轉換成Zend framework的validator,進行身份證號碼的驗證。

有了公式之後要進行驗證就比較容易,不用看程式碼去倒推公式,如果沒有公式,光看程式碼,看個老半天,也看不出個所以然來,還要去適應各種程式碼的寫法,太累了,這個公式真是造福大家,直接將公式轉換成Zend Framework的程式碼,就容易多了。

require_once('Zend/Validate/Abstract.php');

class App_Validate_IdCheck extends Zend_Validate_Abstract{
const SIZE='size';
const FORMAT='format';
const CHECK='check';

protected $_messageTemplates=array(
self::SIZE=>"'%value%' 身份證字串長度不符合。",
self::FORMAT=>"'%value%' 的第一個字元必須是英文字母,其他必須是數字。",
self::CHECK=>"'%value%' 是非法的身份證字號。"
);

public function isValid($value){
$this->_setValue($value);
if(strlen($value) !=10){
$this->_error(self::SIZE);
return false;
}

$value=strtoupper($value);
if(!ereg("[A-Z]{1}[0-9]{9}",$value)){
$this->_error(self::FORMAT);
return false;
}

if($this->check($value)){
return true;
}
else{
$this->_error(self::CHECK);
return false;
}
}

private function check($value){
$first=array('A'=>10,'B'=>11,'C'=>12,'D'=>13,'E'=>14,
'F'=>15,'G'=>16,'H'=>17,'I'=>34,'J'=>18,
'K'=>19,'L'=>20,'M'=>21,'N'=>22,'O'=>35,
'P'=>23,'Q'=>24,'R'=>25,'S'=>26,'T'=>27,
'U'=>28,'V'=>29,'W'=>32,'X'=>30,'Y'=>31,
'Z'=>33);
/**
* convert the first alpha character to two digits
* and combines to the rest digits
*/
$value=$first[$value[0]].substr($value,1);

$sum=(int)$value[0];
for($i=1;$i<=9;$i++){
$sum+=$value[$i]*(10-$i);
}

/**
* get the single-digit of 10-$sum
*/
$single=10 - ($sum % 10);

if($single == $value[10]){
return true;
}
else{
return false;
}
}
}

判斷身份證字號的處理邏輯

http://blog.nahoya.com/archives/2007_12/177

http://zh.wikipedia.org/wiki/%E4%B8%AD%E8%8F%AF%E6%B0%91%E5%9C%8B%E5%9C%8B%E6%B0%91%E8%BA%AB%E5%88%86%E8%AD%89

處理邏輯
1.判斷身份證字號的字串長度,長度必須等於10個字元。
2.判斷身份證字號的字串格式,第一個字元必須是英文字母,第二個字元必須是數字1或數字2,其他的字元必須是數字。
英文
縣市 / 地區
數字
A
台北市
10
B
台中市
11
C
基隆市
12
D
台南市
13
E
高雄市
14
F
台北縣
15
G
宜蘭縣
16
H
桃園縣
17
I
嘉義市
34
J
新竹縣
18
K
苗栗縣
19
L
台中縣
20
M
南投縣
21
英文
縣市 / 地區
數字
N
彰化縣
22
O
新竹市
35
P
雲林縣
23
Q
嘉義縣
24
R
台南縣
25
S
高雄縣
26
T
屏東縣
27
U
花蓮縣
28
V
台東縣
29
W
金門縣
32
X
澎湖縣
30
Y
陽明山管理局
31
Z
連江縣
33
3.每個縣市都有一個相對應的英文字母代表,每個英文字母也都有一個對應的二位數
4.將英文字母轉換為二個數字字元與原來的數字字串進行合併,轉換為十一個數字字元。
5.轉換後的數字字串總共有11個數字字元,將前十個數字進行如下的運算
第一個數字+
第二個數字*9+
第三個數字*8+
第四個數字*7+
第五個數字*6+
第六個數字*5+
第七個數字*4+
第八個數字*3+
第九個數字*2+
第十個數字*1
6.第5個步驟運算得到的和,只取個位數部份
7.用十減去第6步驟得到的值,與第4步驟得到的值的第十一個數字字元進行比對。
如果相同,表示身份證字號是正確的
如果不相同,表示身份證字號是不正確的

2008年9月2日 星期二

下載檔案的問題

Zend Framework的response物件會暫存許多網頁內容,要將存入資料庫中的檔案下載前,必須清空response物件,不然會出現錯誤訊息,這個錯誤找了好久,才找到。

多加一道命令,清空respone物件

$this->getResponse()->clearBody();

ie跟firefox處理下載的中文檔名方式也不同,經由ie下載的檔案要先以urlencode()函數處理過,才能下載,經由firefox下載的檔案就不能以urlencode()函數處理過,不然下載的檔名會是編碼過的字串。

處理的邏輯,不難,只要判斷使用者的瀏覽器類型,再分別處理就可以了。

2008年9月1日 星期一

分頁的action helper

很久之前就想要寫一個分頁的物件,本來的構想是在server端把資料的總頁數抓出來後,再送到client,使用jQuery的pagination plugin進行處理,不過如果完全由jQuery的plugin進行處理,會有安全性的問題,一定要由server端再進行確認的處理,同樣的事情,server端及client端,兩邊都要做,真的是有點囉嗦,後來就決定完全由server端進行分頁的處理。

server端的分頁物件的撰寫邏輯是這樣的:

如果頁數少於或等於十筆,就顯示全部頁數。

如果頁數大於十筆,就分成三種狀況做處理

目前頁數小於第五頁,就顯示1~5頁及最後兩頁,其他的用三個點號顯示

總頁數減目前頁數的絕對值小於或等於五頁,就顯示前二頁及最後五頁,其他的用三個點號顯示
非以上兩種狀況,就顯示前二頁及最後兩頁及目前頁數與目前頁數的前二頁與後二頁,其他的用三個點號顯示

分頁的外觀設定,就由client端的css做設定,server端的程式就專注在頁數的計算,將程式邏輯及外觀設定做清楚的切割。

分頁物件的css設定

在樣板中將server傳來的page資料用div包起來,設定顯示的css碼即可

假設div的設定是
server傳來的page資料


非目前頁數的css設定

.page ul li a{
css設定資料
}

目前頁數的css設定

.page ul li span{
css設定資料
}

整個物件花了不少時間思考,該怎麼做,想通後,心裡滿高興的,雖然網路上有非常多的分頁物件可以參考,不過要一行行拆解,真是花時間,而且看得頭昏眼花,眼睛不舒服,就不太想再看這些程式碼了,最後還是決定自己寫一個,比較能夠掌控,而且整個物件的用法也有一致性,不會感覺怎麼有個物件的用法跟整個程式的搭配度不太吻合。

2008年6月18日 星期三

Zend_Acl_Role的設計




/**

* 程式碼是以陳瑩光老師新版學務系統的認證模組改寫的。

*/




要實做Zend_Acl_Role的多重繼承架構,有四個區塊的觀念必須弄清楚,才能把整個架構完整的實做,這四個區塊都弄楚了,程式的實做就是水到渠成的事情。




第一個要弄清楚的區塊就是Zend_Acl_Role的多重繼承觀念,Zend_Acl_Role的繼承關係,跟Zend_Acl_Resource不一樣,Zend_Acl_Resource只能有一個parent,但Zend_Acl_Role卻可以有很多個parent,就像現實生活中的人物一樣,每個人都身兼多重身份,Zend_Acl_Role也可以同時繼承多個parent,與一個實例說明:假設一個Zend_Acl_Role的身份是專案經理,同時繼承了程式設計師、架構設計師及資料庫規畫師的身份,那麼專案經理就同時繼承了指定給這三個身份的所有資源。




第二個要弄清楚的區塊是資料庫結構,如果不使用資料庫,而將Zend_Acl_Role的資料寫在程式碼中,程式碼會變得很冗長,要一行一行coding,不是用幾個迴圈就可以解決的,也難以維護,如果資料非常龐雜,不但程式碼的行數會呈等比級數增加,也會很難搞清楚其中的繼承關係,程式也容易寫錯,為了一勞永逸,最好將這些資料都存入資料庫進行維護管理。存成xml或是ini檔也是可以解決部份的問題,不過資料如果太複雜,也會造成難以維護的結果,最好的解決辦法,就是使用資料庫。




第三個要弄清楚的就是陣列結構,使用陣列結構,只要從資料庫中抓一次資料,將資料轉為陣列結構,在後續的程序中直接使用陣列結構進行資料的操作,如果不使用陣列,那麼後續的程序,會不斷的讀取資料庫,雖然不能說這樣的作法有錯,但資料庫的資料都是存放在硬碟中的,每次讀取資料庫中的資料都會讀取硬碟,而陣列是存放在記憶體裡頭,在速度上,記憶體比硬碟快很多,因此,陣列的操作速度會比資料庫的操作速度快,為了加快速度,最好儘量使用陣列結構進行程式資料的存取。




第四個區塊就是程式的邏輯,這部份要花費很大的心思才能搞懂,如果弄懂了,程式的實做就很快了,只要照著你的思考順序,一步步的將解決方式寫出來就可以建構完整的程式碼了。




用freemind畫了四個區塊的架構圖,以後如果忘記了,不用看程式碼,也不用看說明,看這張圖就一目了然了。



以Zend Framework實做Zend_Acl_Role的雛型


class AclController extends Zend_Controller_Action{
public function init(){
$this->_helper->viewRenderer->setNoRender();
Zend_Loader::loadClass('Zend_Acl');
Zend_Loader::loadClass('Zend_Acl_Role');
Zend_Loader::loadClass('Zend_Acl_Resource');

$acl=new Zend_Acl();
Zend_Registry::set('acl',$acl);
}

public function roleAction(){

$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 a.id,b.parent_id from acl_role as a left outer join acl_inheritance as b on a.id=b.child_id';
$stmt=$db->query($sql);
$rows=$stmt->fetchAll();

/**
* 將資料轉為所需的陣列結構
* Zend_Acl_Role註冊時所需的陣列結構
*/
$roles=array();
foreach($rows as $row){
if(!isset($roles[$row['id']]))
$roles[$row['id']]=array();
if(isset($row['parent_id']))
$roles[$row['id']][]=$row['parent_id'];
}

$acl=Zend_Registry::get('acl');
do{
$flag=false;

/**
* 註冊role
*/
foreach($roles as $key=>$role){
if(!$acl->hasRole($key) && (!isset($role) || $this->hasAllRole($role))){
$acl->addRole(new Zend_Acl_Role($key),$role);
}
/**
* 檢查第一維的key是否都己註冊為role
* 是---離開
* 否---繼續
*/
if(!$acl->hasRole($key))
$flag=true;
}
}while($flag);

}

public function hasAllRole(array &$role){
$acl=Zend_Registry::get('acl');
foreach($role as $parent_id){
if(!$acl->hasRole($parent_id))
return false;
}
return true;
}

}

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月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的架構都是高手建構出來的,模仿他們的設計,可以吸取高手的菁華,快速提升程式碼的品質。