星期一, 6月 28, 2010

SQL Injection

PHP
過去都用addslashes,不過還不夠悍,目前都用mysql_real_escape_string
"PHP的mysql_real_escape_string函數會分析哪些字元需要進行處理,而addslashes則單純對所有的單引號(‘),雙引號(“),反斜線(\)和NUL字元加入反斜線。"

用法
// Query
$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",
mysql_real_escape_string($user),
mysql_real_escape_string($password));


References
PHP防止 SQL Injection: Addslashes還是Mysql_real_escape_string

星期五, 6月 25, 2010

ajax錯誤時,回傳的error message內容

ajax錯誤時,可利用error來handle錯誤處理
從xhr中,可取得回傳的error message
從xhr.status得知錯誤代碼是什麼,也就是http status codes
再針對不同的status做處理囉
jQuery.ajax({
   url: "http://xxx",
   ...
   error:function (xhr, ajaxOptions, thrownError){
     $("body").append(xhr.status);
     $("body").append(xhr.responseText );

    alert(thrownError);
   }    
});

xhr是XMLHttpRequest物件,有以下屬性及方法
  • status
    Returns the HTTP status code.
  • statusText
    Returns the HTTP status text.
  • getResponseHeader() method
  • getAllResponseHeaders() method
  • Response Entity Body
  • responseText attribute
    Returns 就回傳取到的內容囉
  • responseXML attribute

星期二, 6月 22, 2010

耶? blogger有新的版面設計工具了

ya~~ 今天突然發現blogger有新的設計工具
看到可以用slider調框大小 真是令人感動
之前用css調到快起肖了 還一直破版面...

另外css也將系統預計的css隱藏了
只會自己定義的css 不用再從一堆css中找了 ya~~

不過殘念... 舊的版面不能用新的設計工具....
所以只好將網站換個風格...

星期五, 6月 18, 2010

利用Zend_Navigation達到Menu、breadcrumbs及sitemap

主要做法就是在xml裡配置階層結構
步驟就照著reference的範例做
不過有遇到些問題,所以有問題的地方有特別註釋

1.設定Bootstrap.php
protected function _initNavigation()
{
$this->bootstrap('layout');
$layout = $this->getResource('layout');
//$view = $layout->getView(); //加了這行...會導致在layout.phtml呼叫helper會掛...所以..註解掉...
$config = new Zend_Config_Xml(APPLICATION_PATH . '/configs/navigation.xml', 'nav'); //指定要讀取的架構檔,命名為navigation.xml

$container = new Zend_Navigation($config);
Zend_Registry::set("Zend_Navigation", $container); //範例裡沒加,但沒加又跑不動...怪...
//$view->navigation($container); //嗯...也是能動咧...
}

2.編寫階層結構xml
path: application/configs/navigation.xml (xml檔名取命跟Bootstrap裡load的地方一樣)
<?xml version="1.0" encoding="UTF-8"?>
<configdata>
<nav>
<home>
<label>Home</label>
<uri>/</uri>
</home>
<courses>
<label>球場管理</label>
<uri>/courses/</uri>
<pages>
<add>
<label>新增球場</label>
<uri>/courses/add/</uri>
</add>
<edit>
<label>編輯球場</label>
<uri>/courses/edit/</uri>
</edit>
</pages>
</courses>
<about>
<label>關於我們</label>
<uri>/index/about/</uri>
</about>
</nav>
</configdata>

3.設定layout.phtml
<body>
...
<?php echo $this->navigation()->Menu()?>
<?php echo $this->navigation()->breadcrumbs()->setLinkLast(false)->setMinDepth(0)->render(); ?>
...

4.設定Controller
在每個controller的init裡加上以下程式碼
public function init()
{
//navigation
$uri = $this->_request->getPathInfo(); //原作是寫這樣啦,不過遇到有參數的uri就噴了
$uri = $this->_request->getControllerName()."/". $this->_request->getActionName(); //我把比對的uri改成這樣,也不怕最後有沒有斜線結尾

$activeNav = $this->view->navigation()->findByUri(strtolower($uri)); //避免大小寫問題,全轉為小寫
$activeNav->active = true;
//$activeNav->setClass("active"); //uri沒配對到時 會出現error,所以...
}


錯誤訊息
$activeNav->setClass("active");
出現Fatal error: Call to undefined method stdClass::setClass() ...
是因為uri對應失敗,所以無法設定class為active

xml裡放網站根目錄是比較正確的做法
不應該把會變動的前置資料夾放在裡面 ex. project/public
只不過這樣會導致zend_navigation產生的鏈結會從根開始跑 就會找不到位置

比較好的做法應該是該鏈結加上$this->_request->getBaseUrl()."/"
只是不知從哪去改... echo前去改...應該有更好的方法...找到再po上來

另外一個問題是如果... 鏈結需有必要的參數...
就還得要再將參數組成uri...

Reference
Zend_Navigation – creating a menu, a sitemap and breadcrumbs 用錄影的 不錯...

星期六, 6月 05, 2010

系統分析設計與實作 Week 9

Iteration 1
目的:將需求轉實作
=>要求都要配Controller
整合是持續性的在做整合

軟體開發方法
  1. Data-Orented
    易陷入細節,不易抓出圖
  2. Service-Oriented
    延展、彈性、重複利用


測試 unittest
功能性 => Controller
單元性 => Unit test, Business Object

User方面有UAT(User Acceptance Test)使幅者接受度測試

設計資料庫
設計表格
4大類 (人,事(event)/時,地物)
  1. 抓名詞(需求陳述中抓)
    但片斷,不易看到全貌,需求明確,才能完整
  2. 抓核心
    訂烏龜系統=>訂的event
    門禁管理=>刷卡的event (書UML.P148)
    儘可能容變動的需求
需求不再是主導系統的唯一來源
Enterprise => Transaction
Sub query易隱念企業邏輯,反而影響維

Q & A
  1. UML必要畫?
    UML是個語言,語言是用來溝通,所以獨立一個人開發時,基本上不用畫
  2. 交接時?
    需要時再畫,多一張就多需要維護成本
  3. 如何引導客戶提出需求
    客戶分1.Domain Expert可用活動圖(作業流程)或火箭圖
    2.Operator 直接用畫面UI溝通
    流程圖最好能當場畫,讓使用者確認,避免誤解
  4. CURD
    利用actor當授權

系統分析設計與實作 Week 7

烏龜訂購系統
phase 2 萃取穩定的結構共用元素(企業物件)
  1. middle ware
  2. controller
一開始不容易馬上判斷出來,可先放controller,再透過重構方式「逐漸萃取」
ex. 「計算訂購總額」應該放哪
hint: 推理,不要強記
「計算訂購總額」理論上放在訂購object上,但應該抽出到BO(企業物件),當共用的元素
過去,放store_procedure或script都不算好
但一開始要不容易抽,所以折衷先放controller
將來重構放到business object
=>將可共用的企業規則抽出

交易事件
人,(事/時),地,物
  1. 界定範圍
    利用UC,一般抓到5,6成就夠了
    • User Case View
    • Locial View
      -UC Realization
      -Class Model (配合codegen)
    UC都是片斷,有滿足即可,不要流程,至於滿足的程度依"Session"來判斷
  2. 撰寫UC敘述
    把「容易變」的跟「不容易變」的分開
    共用的可抽出來放
    =>產出Document
  3.  
  4. 實現UC (logical view realization)
    用UC Diagram當doc type
    *橋接實作,即建Conroller
  5. 建Controller
    設計可能會漏掉,由實作(feedback)去做調整,補足或修正Controller, UC Description
    隨時都在調,因此文件要少、精簡,過程中都是只是最後文件的snapshot

16.1.3.資訊系統的分層結構
  • 表達層(Presentation):UI
  • 中間層:CO(Control Object)
    DAO: 將DB存取細節放至DAO,任何跟DB有關的存取透過小弟DAO解決
    Adapter:外部系統的鏈結
    軟體主結構即抽出的概念性物件BO
  • 資料層:Database

三大物件
  1. Controller
  2. Boundary
    實體變動
  3. BO
    應付Domain變動,一開始不易抓,先放controller

循序圖不是要表達精細,重點在完成某功能時,反應run time的流程
EA做Sequence Diagram時,拉物件會要選擇"Simple link or Instance", 選instance,因為是物件
隱含的method用加雙斜線 ex.到db抓資料=>//select

不用每個UC都畫Sequence,只畫比較需要的
何謂需要
programmer無法看出必要的method(無共識時)
UI, Controller 應分開獨立的Project

系統結構面
Jobcason將結構分為
控制
實體
邊界
目的:好分類->好維護
結構只對developer有好處(好維護),User只看畫面

---
為何叫物件導向
都是用類別在定義,為何不是類別導向
心中想像的是物件在互動,而利用class描述出來,
ex. 作曲做的是音樂,但是得利用五線譜「作曲」記錄

安裝PHPUnit

phpunit官網:http://www.phpunit.de/

有兩個主要的版本,依php版本決定
  • PHPUnit 3.7 requires PHP 5.3.3
  • PHPUnit 3.8 requires PHP 5.4.7


兩種方法
  1. 直接使用phpunit
    https://github.com/sebastianbergmann/phpunit/

    <php
    include "phth to PHPUnit";
    class StackTest extends PHPUnit_Framework_TestCase
    {
        public function testPushAndPop()
        {
            $stack = array();
            $this->assertEquals(0, count($stack));
     
            array_push($stack, 'foo');
            $this->assertEquals('foo', $stack[count($stack)-1]);
            $this->assertEquals(1, count($stack));
     
            $this->assertEquals('foo', array_pop($stack));
            $this->assertEquals(0, count($stack));
        }
    }
    ?>
  2. 安裝phpunit
    wget https://phar.phpunit.de/phpunit.phar
    chmod +x phpunit.phar
    mv phpunit.phar /usr/local/bin/phpunit
    vi composer.json
    {
    "require-dev": {
    "phpunit/phpunit": "3.7.*"
    }
    }
    composer install
    程式裡加上
    require 'vendor/autoload.php';

其他PHPUnit官網寫很清楚,而且很多觀念教學,真棒

Zend View 常用動作

  1. jquery觸發submit
    $('form:first').trigger("submit");
  2. url路徑
    //根目錄 - 從web root到public
    $this->baseUrl('course/add'); //參數加入即會自動補
    =>/myweb/public/course/add
  3. 目前url
    $this->url(array('controller'=>'course','action'=>'add')); //如果當前的url是在同一個controller下的話,可以不用給controller參數
    =>/myweb/public/course/add/
  4. Controller, Action Name及參數
    $request = Zend_Controller_Front::getInstance()->getRequest();
    $controllerName = $request->getControllerName();
    $actionName = $request->getActionName();
    $paramArray = $request->getParams();
    $params = '';

    foreach($paramArray as $key => $value)
      $params .= $key . "/" . $value;
  5. 添加CSS 和 JS
    //將js,css放在public裡的js,css資料夾
    <script type="text/javascript" src="<?php echo $this->baseUrl('js/jquery-xxx.min.js');? >" >
    </script?>
    <link rel="stylesheet" type="text/css" href="<?php echo $this->baseUrl('css/xxx.css'); ? >" >
References
Zend - Get everything after base Url (Controller, Action, and any params)

zend DB 常用動作

直接對Zend_Db操作
  • 新增DB連線
    $db = Zend_Db::factory('Pdo_Mysql', array(
    'host'     => '127.0.0.1',
    'username' => 'webuser',
    'password' => 'xxxxxxxx',
    'dbname'   => 'course'
    ));
  • 下sql語法
    $stmt = $db->query('SELECT * FROM course');
    
    //Zend_Db提供fecth(),可抓出row object
    while($row = $stat->fetch()){
        echo $row['name'];
    }
  • 替換sql語法裡的參數
    $sql = 'SELECT * FROM course WHERE nam = ? AND status = ?';
    $stmt = new Zend_Db_Statement_Mysqli($db, $sql); //mysql就用mysqli
    $stmt->execute(array('demo course','display'));

宣告多個DB
  • 宣告(configs/application.ini)
    //db1
    resources.multidb.course.adapter = "PDO_MYSQL"
    resources.multidb.course.host = "localhost"
    resources.multidb.course.username = "root"
    resources.multidb.course.password = "ok1234"
    resources.multidb.course.dbname = "course"
    resources.multidb.course.driver_options.1002 = "SET NAMES utf8"
    resources.multidb.teegle.default = true
    
    //db2
    resources.multidb.admin.adapter = "PDO_MYSQL"
    resources.multidb.admin.host = "localhost"
    resources.multidb.admin.username = "root"
    resources.multidb.admin.password = "ok1234"
    resources.multidb.admin.dbname = "admin"
    resources.multidb.admin.driver_options.1002 = "SET NAMES utf8"
  • 選擇db
    $resource = $this->PluginResource('multidb');
    $resource->init();
    $db = $resource->getDb('course'); //取得course db
    $db->select()
        ->from( ... ) //多個from
        ->where( ... );

對Zend_Db_Table下指令
  • 設定table
    Zend_Db_Table::setDefaultAdapter($db);
    $courseTable = new Zend_Db_Table('course');
  • 在fetchAll裡加參數
    $resultSet  = $table->fetchAll(
            $table->select()
               ->where('status = ?', 'NEW') //有多個where就再下一次where(xx)
               ->order('id ASC')
               ->limit(10, 0)
    );
    
    //塞進array
    $entries   = array();
    foreach ($resultSet as $row) {   
        $object = row->id; // or row['id'];
        $entries[] = $object;
    }
  • 讓DbTable物件 讀非預設DB
    DbTable會預設讀config裡設定的"db"
    如果要讀一個db怎麼辦咧?
    1.註冊db
    在Bootstrap.php裡,註冊想要讀的db
    //application/Bootstrap.php
    class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
    {
        $resource = $this->getPluginResource('multidb'); //假設存放在multidb裡,參考如何設定多個db
        $resource->init(); //初始化,不然不會動
    
        //註冊要讀取的DB - admin
        $admin = $resource->getDb('admin');
        Zend_Registry::set("admin", $admin);
    }
  • 2.改寫DbTable的建構子 方法一 就在DbTable的class下,override construct 把要給DbTable的物件參數中的'db'改成目前要讀的db
    class Application_Model_DbTable_User extends Zend_Db_Table_Abstract { 
        protected $_name = 'user'; 
        //方法一     
        public function __construct($config=array()){
            $this->read  = Zend_Registry::get('admin');
            $this->write = Zend_Registry::get('admin');
            $config['db'] = Zend_Registry::get('admin');                       
            return parent::__construct($config);
        }  
    
        //方法二  
        protected function __setupDatabaseAdapter(){ 
        } 
    }
    join
    //Build this query: 
    //  Select p."product_id",p."product_name", l.* 
    //  From "products" AS p JOIN "line_items" AS l 
    // ON p.product_id = l.product_id  
    $select = $db->select()->from (array('p'=> 'products'), 
    array('product_id','product_name'))->join(array('l' => 'line_items'), 'p.produt_id = l.product_id');
References
Zend Framework Certification Study Guide

星期五, 6月 04, 2010

jqueryui button

原來disable不是改tag屬性... (會失敗)
試了好久才發現要丟參數
利用.button( "disable" ), enable就一樣囉

星期二, 6月 01, 2010