แสดงบทความที่มีป้ายกำกับ php แสดงบทความทั้งหมด
แสดงบทความที่มีป้ายกำกับ php แสดงบทความทั้งหมด

วันจันทร์ที่ 2 ธันวาคม พ.ศ. 2556

Zend certified engineer PHP 5.3


My Zend Certified Engineer Directory Page


ในที่สุดก็สอบผ่านเสียทีครับ กับการเตรียมสอบมาอย่างยาวนาน ใช้เวลาเตรียมตัวสอบมาเรื่อยๆ อาศัยช่วงว่างจากงานพิเศษบ้าง ช่วงดึกของวันจันทร์ถึงศุกร์ เป็นเวลา 3 เดือนเต็มๆ หลักก็มีอ่าน ebook ของ PHP-5-3-Study-Guide-v1 ของ Zend.com, Tutorial ตามเว็บไซต์ต่างๆ ที่คนที่สอบผ่านแล้วแนะนำ และอ่าน PHP Manual เนื้อหาหลักๆ ทั้งหมด

ในระหว่างการอ่านพบว่าตัวเองไม่ถนัดเขียนปากกาจดบันทึกซะแล้ว สมัยก่อนจดแล้วลบแล้วบางทีกลับมาดูอีกทีอ่านไม่ออก ผมเลยต้องหาตัวช่วยมาใช้เป็นโปรแกรมสร้าง Mind Map ตัวหนึ่งชื่อว่า FreeMind โปรแกรมตัวนี้จะสร้างข้อมูลเหมือน Tree/Directory สามารถจัดกลุ่มเพิ่มลบแก้ไขข้อมูลได้สะดวกมาก http://freemind.sourceforge.net

ในช่วงวันก่อนวันสอบก็ยังไม่แน่ใจในระดับความยากของข้อสอบ เพราะจากที่ทำตัวอย่างข้อสอบที่ผ่านๆ มาอยู่ในระดับยากมาก (ข้อสอบตัวอย่างมักจะถาม parameter ตัวที่ 3-4 ของ function ต่างๆ แบบสุ่มชื่อ function หรือถามผลลัพธ์ของการของโปรแกรมที่มีตัวแปร 3-5 ตัวแปร) วันเสาร์อาทิตย์ก่อนสอบก็ไม่สบายเสียอีกเวลาอ่านทบทวนที่จดไว้ใน Mind Map ได้ไม่มาก จะสอบผ่านไม่ผ่านไม่รู้แต่เสียดายที่เตรียมมาเยอะมาก ถ้าอ่านไม่จบแล้วสอบตกคงเสียใจมาก ถ้าอ่านจบที่เตรียมแล้วไม่ผ่านก็จะได้ทำใจว่าทำดีที่สุดแล้ว วันจันทร์ตอนเช้าเลยต้องตั้งตาอ่านให้ครบตั้งแต่ช่วงตี 2 ถึง 7 โมงกว่า อ่านจบค่อยสบายใจหน่อย :D

วันที่สอบก็หวั่นๆ อยู่หน่อย เพราะเป็นช่วงที่เกิดการชุมนุมและมีการประกาศหยุดงานในหลายๆ แห่ง ไม่รู้ว่าศูนย์สอบจะเปิดให้ผมเข้าไปสอบหรือเปล่า ผมสอบที่ศูนย์ CTT Center เลือกสอบที่นี่เนื่องจากตั้งใจจะสอบช่วงธันวาคมแต่ศูนย์สอบหลายแห่งไม่เปิดช่วงธันวาคมแต่ที่นี่เปิดอยู่เกือบทั้งเดือน การเดินทางก็สะดวกโดยลงที่สถานีไฟฟ้าใต้ดินเพชรบุรี เดินต่อไปอีก 300 เมตรก็ถึงครับ ก่อนสอบก็ต้องเก็บของในล็อคเกอร์ก่อน เพราะเค้าจะไม่อนุญาตให้เอาของส่วนตัวกระเป๋า โทรศัพท์มือถือ ฯลฯ เข้าสอบครับ

การสอบจะเป็นการสอบในระบบ online ก็จะมีเจ้าหน้าที่มาเซ็ตระบบให้เรียบร้อย โดยเริ่มต้นเค้าจะให้กระดาษทดมา ปรากฎว่าปากกาเขียนไม่ติด ผมเลยตะโกนขอปากกาใหม่ ตอนหลังสอบเจ้าหน้าที่คงงง ว่าเขียนทดอะไรหว่า ด้วยลายมือที่อ่านยากและที่ทดเขียนไว้ว่า 1+1 (จะเขียนทำไมเนี่ย 555)

ข้อสอบไม่สามารถเปิดเผยได้เพราะเป็นกฎของ Zend ครับ แต่หลักๆ แล้วไม่ยากอย่างที่คิด ระบบข้อสอบเค้าเป็นระบบที่ดีมาก คือทำแล้วสามารถตั้ง flag เพื่อให้กับมาตรวจทานเปลี่ยนแปลงข้อสอบได้สะดวกรวดเร็ว เนื่องจากทำข้อสอบเสร็จค่อนข้างเร็ว ผมจึงมีเวลาตรวจทานซ้ำได้พอสมควร หลักสำคัญก็คือควรจะอ่านข้อสอบให้ละเอียด บางคำตอบเหมือนจะถูกแต่ถ้าอ่านคำถามให้ดีและเช็คคำตอบอื่นจะพบว่าคำตอบที่ถูกต้องจะเป็นอีกข้อหนึ่ง ดังนั้นควรทำเสร็จให้เร็วจะได้กลับมา review ข้อสอบต่างๆ ที่ยังไม่มั่นใจ 100% อีกครั้ง ก่อนกดปุ่มยุติการสอบครับ

ถ้าเป็นการสอบผมจะใช้เวลาคุ้มตลอด  มีเวลาเหลือผมก็ review รอบสองจนครบ 90 นาที พอครบ 90 นาทีปุ๊บ ระบบแจ้งผลให้ทราบในทันที  Congratulation!!  สอบผ่านแล้ว เย้ๆๆ


ปล. ในการสอบครั้งนี้ผมไม่ได้เสียค่าใช้จ่ายในการเข้าสอบเอง ต้องขอขอบคุณพี่วี (webofficedesign.com) ที่สนับสนุนและเคี่ยวเข็ญทำให้ได้ไปสอบในครั้งนี้ด้วยครับ :)

วันศุกร์ที่ 15 พฤศจิกายน พ.ศ. 2556

php function return refernce

function return reference ก็คือ function ที่จะคืนค่าเป็น reference ของตัวแปรนั่นเองครับ

<?php
function &f(&$a,&$b,$status){
    if ($status == 1)
         return $a;
    else
         return $b;
}

$a=100;
$b=200;
$v1 = &f($a,$b,1); //reference $a
$v2 = &f($a,$b,0); //reference $b

$v1 = 11111;
$v2 = 22222;
var_dump($a); //เปลี่ยนตาม $v1
var_dump($b); //เปลี่ยนตาม $v2




วันพุธที่ 30 ตุลาคม พ.ศ. 2556

fairly_rand function

faily_rand function เป็น random function รูปแบบหนึ่ง ที่จะสุ่มตัวเลขขึ้นมาแบบไม่ซ้ำครับ

function fairly_rand($start,$end,$return=1){
//function นี้ $start และ $end ควรจะห่างกันมากๆ
$a = array();
$distance = ($end-$start)/$return;
$a[]=$start;
for($i=$start+$distance;$i<$end-($distance/2);$i+=$distance){
      $a[]=($a[]=floor($i))+1;
}
$a[]=$end;
$results = array();
for($i=0;$i<$return*2;$i+=2){
      $results[] = rand($a[$i],$a[$i+1]);
}
return $results;
}

$numbers = fairly_rand(1,500,5);
var_dump($numbers);

วันเสาร์ที่ 2 มีนาคม พ.ศ. 2556

XML Printer Class

<?php

$printer = new XMLPrinter('$data',array('path','value'));
$printer->write('111222222');

class XMLPrinter{
    public $columns = array();
    public $onlyFirstElement = false;
    public $rootName = '$root';
    public function __construct($rootName='$root',$columns=array('type','path','value'),$onlyFirstElement=false){
        $this->rootName = $rootName;
        $this->columns = $columns;
        $this->onlyFirstElement = $onlyFirstElement;
    }
    public function write($data){
        if (!$data instanceof SimpleXMLElement)
            $data = simplexml_load_string($data);
        $this->writeHeader();
        $this->_write($data,$this->rootName,0);
        $this->writeFooter();
    }
    public function _write(SimpleXMLElement $data,$name){
        $children = array();
        foreach($data as $item)
            $children[] = $item->getName();
        $children = array_unique($children);
        foreach($children as $child){
            $item = $data->$child;
            $isArray = isset($item[1]);
            $i = -1;
            while(isset($item[++$i])){
                $arrayPat = $isArray ? "[$i]" : '';
                $elementPat = $name.'->'.$item[$i]->getName().$arrayPat;
                if (count($item[$i]->attributes())>0)
                    foreach($item[$i]->attributes() as $attr=>$value)
                        $this->writeRow('attribute', $elementPat."['$attr']", $value);
                if (count($item[$i]->children())>0)
                    $this->_write($item[$i]->children(),$elementPat);
                else
                    $this->writeRow('element', $elementPat, $item[$i]);
                if ($this->onlyFirstElement)
                    break;
            }
        }
    }
    public function writeHeader(){
        echo '<style>';
        echo "nobr{max-width:600px;overflow:hidden;display:block;}";
        echo '</style>';
        echo '<table border="0" cellspacing="0"><tr>';
        foreach($this->columns as $column)
            echo '<th>'.$column.'</th>';
        echo '</tr>';
    }
    public function writeRow($type,$path,$value){
        if (strlen(trim($value)) > 0){
            echo '<tr>';
                foreach($this->columns as $column)
                    echo '<td><nobr>'.htmlspecialchars($$column).'</nobr></td>';
                //echo '<td><nobr>echo \'&lt;br&gt;'.str_replace("'",'\\\'',htmlspecialchars($$column)).'=\','.htmlspecialchars($$column).';</nobr></td>';
            echo '</tr>';
        }
    }
    public function writeFooter(){
        echo "</table>";
    }
}

วันอาทิตย์ที่ 25 พฤศจิกายน พ.ศ. 2555

php excel class

<?php
$a = array('A','B','C');
$fs = array('field1','field2','field3');
$cs = array(
    array('aaa1','bbb1','ccc1ทดสอบ'),
    array('aaa2','bbb2','ccc2'),
    array('aaa3','bbb3','ccc3'),
);
require_once './excel/PHPExcel.php';
$e = new PHPExcel();
$e->getProperties()->setCreator("num")
        ->setLastModifiedBy("num")
        ->setTitle("Report")
        ->setSubject("Report")
        ->setDescription("Report")
        ->setKeywords("report")
        ->setCategory("report");

$default_border = array(
    'style' => PHPExcel_Style_Border::BORDER_THIN,
    'color' => array('rgb'=>'1006A3')
);
$style_header = array(
    'borders' => array(
        'bottom' => $default_border,
        'left' => $default_border,
        'top' => $default_border,
        'right' => $default_border,
    ),
    'fill' => array(
        'type' => PHPExcel_Style_Fill::FILL_SOLID,
        'color' => array('rgb'=>'E1E0F7'),
    ),
    'font' => array(
        'bold' => true,
        'name' => 'CordiaUPC',
        'size' => 30,
    )
);
$sh = $e->setActiveSheetIndex(0);
$sh->getStyle('A1:C4')->applyFromArray( $style_header );
$sh->getColumnDimension('C')->setWidth(20);
foreach($fs as $i=>$f)
        $sh->setCellValue($a[$i].'1', $f);
$row = 2;
foreach($cs as $c){
        $vals = array_values($c);
        foreach($fs as $i=>$f)
                $sh->setCellValue($a[$i].$row, $vals[$i]);
        $row++;
}
$e->getActiveSheet()->setTitle('Report');
$e->setActiveSheetIndex(0);
$writer = PHPExcel_IOFactory::createWriter($e, 'Excel5');
$writer->save('test.xls');
?>



PHPExcel.php ดาวนโหลดได้ที่ http://phpexcel.codeplex.com/

วันอาทิตย์ที่ 9 กันยายน พ.ศ. 2555

php pdo

วิธีการใช้งาน php pdo แบบง่ายๆ ครับ php pdo class จะมีคำสั่งช่วยในการป้องกัน sql injection และคำสั่งการดึงข้อมูลที่หลากหลาย ช่วยให้สะดวกในการเขียนโปรแกรมติดต่อกับ database ครับ
/*
CREATE TABLE `tbcontact` (
        `id` INT(4) NOT NULL AUTO_INCREMENT,
        `name` VARCHAR(50) NULL DEFAULT NULL,
        PRIMARY KEY (`id`)
)
ENGINE=MyISAM
*/

//configuration
$dbname = 'test';
$user = 'root';
$pass = '';

try{
    //connect    
    $db = new PDO("mysql:host=localhost;dbname=$dbname;", $user, $pass, array(
        PDO::MYSQL_ATTR_INIT_COMMAND=>'SET NAMES UTF8'
    ));
}catch (Exception $e){
    echo 'error:'.$e->getMessage();
}

//insert
$stmt = $db->prepare('insert into tbcontact(name) values(:name)');    
$stmt->bindValue(':name','nobita');
$stmt->execute();

$info = $stmt->errorInfo();
if ($info[0]=='0000')
    echo 'no error';
else
    echo 'error: '.$info[2];

//select
echo '<hr /><h1>FETCH TO OBJECT</h1>';
$stmt = $db->query('SELECT id,name from tbcontact',PDO::FETCH_OBJ);
foreach($stmt as $row) {
    echo $row->id,'...',$row->name,'<br','>';
}

echo '<hr /><h1>FETCH TO ARRAY</h1>';
$stmt = $db->query('SELECT id,name from tbcontact',PDO::FETCH_ASSOC);
while($row = $stmt->fetch()) {
    echo $row['id'],'...',$row['name'],'<br','>';
}

echo '<hr /><h1>FETCH TO VARIABLE</h1>';
$stmt = $db->query('SELECT id,name from tbcontact',PDO::FETCH_BOUND);
$stmt->bindColumn('id',$id);
$stmt->bindColumn('name',$name);
while($row = $stmt->fetch()) {
    echo $id,'...',$name,'<br','>';
}

echo "column count = {$stmt->columnCount()}, row count= {$stmt->rowCount()}";

วันศุกร์ที่ 7 กันยายน พ.ศ. 2555

PHP Calendar Class

class Calendar{
    protected $time;
    protected $timezone;
    public $isLeapYear;
    public function __construct($year) {
        $this->timezone = new DateTimeZone('Asia/Bangkok');
        $this->time = DateTime::createFromFormat('Y-n-j', $year.'-1-1', $this->timezone);
        $this->isLeapYear = checkdate(2, 29, $this->time->format('Y'));
    }
    protected function getMonthFirstDay($month){
        $format = sprintf('%d-%d-1',$this->time->format('Y'),$month);
        return DateTime::createFromFormat('Y-n-j', $format, $this->timezone);
    }
    public function getMonthDays($month){
        $interval = DateInterval::createFromDateString('+1day');
        $time = $this->getMonthFirstDay($month);
        $a = array();
        while($time->format('n') == $month){
            $a[] = clone $time;
            $time->add($interval);
        }
        return $a;
    }
    public static function monthName($month){
        $a = array(1=>'มกราคม','กุมภาพันธ์','มีนาคม','เมษายน',
            'พฤษภาคม','มิถุนายน','กรกฎาคม','สิงหาคม','กันยายน'
            ,'ตุลาคม','พฤศจิกายน','ธันวาคม');
        return $a[$month];
    }
    public static function dayName(DateTime $date){
        $a = array('อาทิตย์','จันทร์','อังคาร','พุธ','พฤหัสบดี','ศุกร์','เสาร์');
        return $a[$date->format('w')];
    }
}

header('Content-type:text/html;charset=utf-8');
#header('Content-type:text/html;charset=tis-620');
$c = new Calendar(2012);
echo '<h1>Calendar 2012</h1>';
foreach(range(1,12) as $month){    
    echo '<h2>',Calendar::monthName($month),'</h2>';
    foreach($c->getMonthDays($month) as $d){
        echo Calendar::dayName($d),' ',$d->format('j'),'<','br/>';
    }
}

วันอังคารที่ 11 ตุลาคม พ.ศ. 2554

curl proxy

<?php

$ch = curl_init("http://www.google.com");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_PROXY, "192.168.0.1");
curl_setopt($ch, CURLOPT_PROXYPORT, 808);
$x = curl_exec($ch);
curl_close($ch); 

echo $x;
?> 
ถ้าเล่นเน็ตต่อผ่าน proxy จะดึงข้อมูลจากเว็บอื่นโดยตรงไม่ได้ แต่ก็ทำได้โดยต่อผ่าน proxy เช่นเดียวกันครับ

วันพฤหัสบดีที่ 5 พฤษภาคม พ.ศ. 2554

php sorting head builder class by num


<?php
/**
* Sorting Head Builder For Dynamic Table
*
* @author Num
* @link http://web-programming-bookmark.blogspot.com
*/
class SortHead
{
protected $ccol = '';
protected $cdir = '';
protected $ncol = '';
protected $ndir = '';
protected $dfcol = '';
protected $dfdir = '';
protected $cols = array();
public $col = '';
public $dir = '';
public function __construct(array $cols,$cname,$dname,$dfcol,$dfdir){
$this->cols = $cols;
$this->dfcol = $dfcol;
$this->dfdir = $dfdir;
$this->ncol = $cname;
$this->ndir = $dname;
$this->ccol = $this->current_col();
$this->cdir = $this->current_dir($this->ccol,$dfdir);
$this->col = $this->ccol;
$this->dir = $this->cdir;
}
public function current_col(){
$ccol = empty($_GET[$this->ncol]) ? $this->dfcol : $_GET[$this->ncol];
$k = array_search($ccol,$this->cols,true);
return ($k === false) ?$this->dfcol :$this->cols[$k];
}
public function current_dir($col,$dfdir='desc'){
$odir = $dfdir == 'desc' ?'asc' :'desc';
if ($this->ccol == $col){
$dir = empty($_GET[$this->ndir]) ?$dfdir :$_GET[$this->ndir];
if ($dir != 'asc' && $dir != 'desc') $dir = 'desc';
$dir = $dir == 'desc' ?'desc' :'asc';
}else{
$dir = $dfdir;
}
return $dir;
}
public function next_dir($col,$dfdir='desc'){
$odir = $dfdir == 'desc' ?'asc' :'desc';
if ($this->ccol == $col){
$dir = empty($_GET[$this->ndir]) ?$dfdir :$_GET[$this->ndir];
if ($dir != 'asc' && $dir != 'desc') $dir = 'desc';
$dir = $dir == 'desc' ?'asc' :'desc';
}else{
$dir = $dfdir;
}
return $dir;
}
public function link($col,$dfdir='desc'){
$dir = $this->next_dir($col,$dfdir);
return '?'.$this->ncol.'='.$col.'&'.$this->ndir.'='.$dir;
}
public function dir($col,$dfdir='desc'){
return $this->current_dir($col,$dfdir);
}
}

$sh = new SortHead(array('name','title','id'),'st','sd','id','desc');

//safe for query
echo ', field=',$sh->col;
echo ', dir=',$sh->dir;
echo ', select * from tb order by '.$sh->col.' '.$sh->dir;

?>

<table border="1" cellpadding="10" cellspacing="0">
<tr>
<td>
<a href="<?php echo $sh->link('name','asc') ?>">name <?php echo $sh->dir('name','asc') ?></a>

</td>
<td>
<a href="<?php echo $sh->link('title') ?>">title <?php echo $sh->dir('title') ?></a>
</td>
<td>
<a href="<?php echo $sh->link('id') ?>">id <?php echo $sh->dir('id') ?></a>

</td>
</tr>
</table>

วันจันทร์ที่ 11 เมษายน พ.ศ. 2554

try catch

ภาษาโปรแกรมซึ่งค่อนข้างใหม่มักจะมีคำสั่ง try catch

คำสั่งนี้ถ้าจะเรียกตรงๆ อาจจะเรียกว่าคำสั่ง
try ... catch ....
ลองทำ .... ถ้าเจอปัญหาก็ให้ทำ .... ด้วย

คุณสมบัติของคำสั่งนี้ก็เพื่อดัก error แปลกๆ ที่ดักโดยใช้คำสั่งตรวจสอบเงื่อนไขธรรมดาได้ยากหรือไม่ได้เลย
และหาวิธีจัดการกับ error ครับเช่น

ในการเขียน embedded database query ในภาษาโปรแกรม
มักจะเกิด database integrity error อย่างเช่น key ซ้ำ, รูปแบบข้อมูลไม่ตรงกับ field ซึ่งคำสั่ง try catch ก็จะช่วยให้เราจัดการกับ error นี้ได้เหมาะสมเช่นถ้า key ซ้ำเราอาจจะสร้าง key ขึ้นมาใหม่และทำการ insert อีกครั้ง

parse error ข้อมูลรูปแบบไม่ถูกต้องเช่น string แปลงเป็นวันที่ไม่ได้ ฯลฯ
ถ้าเกิด error เราก็อาจจะกำหนดค่าของตัวแปรเป็นค่า default ที่เราตั้งขึ้น

divide by zero การคำนวณที่เกิดข้อผิดพลาดจะทำอย่างไรเมื่อเกิดปัญหานี้ บางครั้งตัวเลขที่มาคำนวณอาจมีหลายตัว
การดักการหารด้วยศูนย์จะต้องเขียนซับซ้อน การใช้ try catch จะทำได้สะดวกกว่า

try
{
$i = 1/$x;
}catch(Exception $e){
//จัดการกับ error ด้วยวิธีต่างๆ
$i = -1;
}

วันพฤหัสบดีที่ 10 มีนาคม พ.ศ. 2554

adodb class tutorial

adodb class เป็นคลาสที่ช่วยให้เขียนโปรแกรมติดต่อ database ง่ายขึ้นครับ
นอกจากนี้แล้วยังช่วย escape input เพื่อป้องกัน sql injection
และเป็น database layer ถ้าเขียนติดต่อ database ใน adodb ก็จะช่วยให้ย้ายไป database อื่นได้ง่ายขึ้นแก้ไขน้อยกว่าครับ

เริ่มต้นให้ download adodb มีหลายเวอร์ชั่นครับเลือกเอาเวอร์ชั่นที่ต้องการมาไฟล์ไฟล์เดียวครับ
http://sourceforge.net/projects/adodb/files/

<?php

//config
$conf = array();
$conf['username'] = 'root';
$conf['password'] = '12345';
$conf['host'] = 'localhost';
$conf['db'] = 'test';
$conf['driver'] = 'mysqli'; //เลือกเป็น mysqli เพื่อจะได้ใช้งาน transaction ใน adodb class ได้

//setup and connect to db
require 'adodb/adodb.inc.php'; //เปลี่ยน path ไปยังไฟล์ adodb.inc.php ให้ถูกต้อง
$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
$db = ADONewConnection($conf['driver']);
$db->Connect($conf['host'], $conf['username'], $conf['password'], $conf['db']);
$rs = $db->Execute('SET NAMES UTF8');

//create test data
$row = $db->GetRow("SHOW TABLES LIKE 'guestbook_test2'");
if (empty($row)){
$db->Execute(
'CREATE TABLE guestbook_test2 ('.
'id int(10) unsigned NOT NULL AUTO_INCREMENT,'.
'name varchar(20) NOT NULL,'.
'detail text NOT NULL,'.
'PRIMARY KEY (id)'.
')'
);
if ($db->ErrorNo()){
die($db->ErrorMsg());
}
echo 'create table successfully.<br>';
srand();
foreach(range(1,100) as $a){
$id = null; //insert id=null, update $id = id value
$name = md5(rand(1,10000));
$detail = sha1(rand(1,10000));
$db->Replace('guestbook_test2',compact('name','detail','id'),'id',true);
}
echo 'insert data successfully.<br>';
}

//pagination
$limit = 10;
$page = empty($_GET['page']) ? 1 : (int)$_GET['page'];

$rs = $db->PageExecute("SELECT * FROM guestbook_test2", $limit, $page);
$page_row_count = $rs->RowCount();
$row_count = $rs->MaxRecordCount();
$page_count = $rs->LastPageNo();
$rows = $rs->GetRows();
$rs->Close();

//test Execute and FetchRow
$select_id = 11;
$select_id2 = 15;
$rs = $db->Execute("SELECT * FROM guestbook_test2 WHERE id=? OR id=?", array($select_id,$select_id2));
$data = array();
while($row = $rs->FetchRow()){
$data[] = $row;
}

//test GetAssoc
$data2 = $db->GetAssoc("SELECT id,name FROM guestbook_test2 WHERE id BETWEEN ? AND ?",array(51,52));

//close connection
$db->Close();

?>
<!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=tis-620" />
<title>adodb tutorial</title>
</head>
<body>

<!-- records of this page -->
<?php foreach($rows as $row):?>
<?php echo $row['id'],': ',$row['detail'],' ...... by <b>',$row['name'],'</b>';?>
<hr />
<?php endforeach;?>

<!-- page links -->
<?php for($i=1; $i<=$page_count; $i++):?>
<a href="?page=<?php echo $i;?>"><?php echo $i;?></a>
<?php endfor;?>

<hr />
<!-- records of select_id1, select_id2 -->
<?php foreach($data as $row):?>
<?php echo $row['id'],': ',$row['detail'],' ...... by <b>',$row['name'],'</b>';?>
<hr />
<?php endforeach;?>

<!-- records of 51 to 52 -->
<?php foreach($data2 as $id=>$value):?>
<?php echo $id,': ',$value,'</b>';?>
<hr />
<?php endforeach;?>

</body>
</html>

วันพุธที่ 22 ธันวาคม พ.ศ. 2553

update multiple record


<?php

if ($_SERVER['REQUEST_METHOD'] == 'POST'){
echo 'doraemon,nobita,pokemon,id<br','>';
foreach((array)$_POST['data'] as $pk=>$d){
echo $d['doraemon'],',',$d['nobita'],',',$d['pokemon'],',',$pk,'<br','>';
//เอาข้อมูลนี้ไปสร้างคำสั่ง update ...
}
die('save');
}

?>
<!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=windows-874" />
<title>update multiple record</title>
</head>

<body>

<form id="form1" name="form1" method="post" action="">
<?php foreach(range(1,2) as $i):?>
<input type="text" name="data[<?php echo $i;?>][doraemon]" />
<input type="text" name="data[<?php echo $i;?>][nobita]" />
<input type="text" name="data[<?php echo $i;?>][pokemon]" />
<?php echo '<br','>'; endforeach;?>
<input type="submit" name="button" id="button" value="Submit" />
</form>

</body>
</html>

วันอาทิตย์ที่ 19 ธันวาคม พ.ศ. 2553

layout-views or master-contents page

master-page.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=windows-874" />
<link type="text/css" rel="stylesheet" href="style.css"/>
<title>{$title}</title>
{$head}
</head>

<body>
<h1>Welcome to my site</h1>
<table width="800" border="2"><tr><td bgcolor="#FFCC00">
{$content1}
</td><td bgcolor="#FFFFCC">
{$content2}
</td></tr>
</table>
<hr/>
easy master page by num |
<a href="normal-page.php">page1</a> |
<a href="normal-page2.php">page2</a>
</body>
</html>


normal-page.php

<?php require 'util.php'; $MasterPage = 'master-page.php';?>
<?php if (0):?><meta http-equiv="Content-Type" content="text/html; charset=windows-874" />
<link type="text/css" rel="stylesheet" href="style.css"/><?php endif;?>

<?php sb('title'); echo 'test-title'; eb();?>

<?php sb('head');?>
<script type="text/javascript">
window.onload = function(){
document.getElementById('test').innerHTML = 'javascript text';
}
</script>
<?php eb();?>

<?php sb('content1');?>
<b>hello world</b>
<div id="test"></div>
<?php eb();?>

<?php sb('content2');?>
lksldfjksjdklfjk lsjdlkfj s dfjsldkjfks jdklfjkljsdl fklsjdklfjlksd
<?php eb();?>


<?php render();?>


normal-page2.php

<?php require 'util.php'; $MasterPage = 'master-page.php';?>
<?php if (0):?><meta http-equiv="Content-Type" content="text/html; charset=windows-874" />
<link type="text/css" rel="stylesheet" href="style.css"/><?php endif;?>

<?php sb('title'); echo 'สวัสดีครับ'; eb();?>

<?php sb('head');?>
<?php eb();?>


<?php sb('content1');?>
page2
<?php eb();?>

<?php sb('content2');?>
this is page 2.
<?php eb();?>



<?php render();?>


util.php

<?php

$_vars = array();
function sb($name){
static $sName;
if (empty($name)) return $sName;
$sName = $name;
ob_start();
}
function eb(){
global $_vars;
$name = sb(0);
$_vars[$name] = ob_get_clean();
}
function render(){
global $_vars;
ob_start();
require ($GLOBALS['MasterPage']);
$page = ob_get_clean();
foreach($_vars as $name=>$var)
$page = str_replace('{$'.$name.'}',$var,$page);
echo $page;
}

?>



/* CSS Document */

*{margin:0;padding:0;}
body {background-color:#ccc;}

วันพุธที่ 15 ธันวาคม พ.ศ. 2553

ส่งเมล์ให้เป็นภาษาไทยโดยใช้ php send mail UTF-8

โปรแกรมนี้เป็นโปรแกรมที่ส่ง mail แบบ multipart โดยส่งทั้ง format text/plain และ text/html ไปพร้อมๆ กันครับ จึงไม่ต้องกังวลว่าผู้รับเมล์จะอ่าน html หรือ text อย่างใดอย่างหนึ่งไม่ได้
ผ่านการทดสอบจาก webisite email ดังต่อไปนี้ hotmail.com, yahoo.com, gmail.com และ fastmail.fm

( ต้องบันทึกโค้ดนี้เป็น utf8 ครับถึงจะได้ค่าภาษาไทยที่ถูกต้อง )

<?php

//define('DEBUG',true);

function ct($ct,$a){
$s = "Content-Type: $ct";
foreach($a as $k=>$v){
$s .= ";\r\n\t$k=\"$v\"";
}
return "$s\r\n";
}
function cte($cte){
return "Content-Transfer-Encoding: $cte\r\n";
}
function enc($s){
return '=?UTF-8?B?'.base64_encode($s).'?=';
}

function mail_utf8($to,$from,$subject,$text,$html)
{
$hash = md5(date('r', time()));
$b1 = 'b1_'.$hash; $bb1 = "\r\n--$b1\r\n"; $bb1e = "\r\n--$b1--\r\n";
$b2 = 'b2_'.$hash; $bb2 = "\r\n--$b2\r\n"; $bb2e = "\r\n--$b2--\r\n";
if (strpos($from,'<')){
list($name,$email)=explode('<',$from);
$from = enc($name).' <'.$email;
}
if (strpos($to,'<')){
list($name,$email)=explode('<',$to);
$to = enc($name).' <'.$email;
}
$h = "From: $from\r\n";
$h .= "Reply-To: $from\r\n";
$h .= "MIME-Version: 1.0\r\n";
$h .= ct('multipart/related',array(
'type'=>'text/html',
'boundary'=>$b1
));
$m = $bb1;
$m .= ct('multipart/alternative',array('boundary'=>$b2));
$m .= $bb2;
$m .= ct('text/plain',array('charset'=>'UTF-8'));
$m .= cte('8bit');
$m .= "\r\n$text\r\n";
$m .= $bb2;
$m .= ct('text/html',array('charset'=>'UTF-8'));
$m .= cte('8bit');
$m .= "\r\n$html\r\n";
$m .= $bb2e;
$m .= $bb1e;
$subject = enc($subject);

if (defined('DEBUG')){
echo "<pre>\r\n";
echo "$to\r\n$subject\r\n$h\r\n$m";
echo '</pre>';
} else {
return @mail( $to, $subject, $m, $h );
}
}

mail_utf8
(
'คุณสวัสดีครับ <sendto@sendtodomainname.com>',
'คุณสวัสดีค่ะ <myemail@mydomainname.com>',
'หัวข้อ',
'text ครับ',
'<body><b>html</b>ครับ</body>'
);

?>

วันจันทร์ที่ 13 ธันวาคม พ.ศ. 2553

the change calcuation


<?php
function return_money($m){
$debug = 1;
$m *= 100;
$x100 = array(
'50000'=>'แบ้งค์500',
'10000'=>'แบ้งค์100',
'5000'=>'แบ้งค์50',
'2000'=>'แบ้งค์20',
'1000'=>'เหรียญ10',
'500'=>'เหรียญ5',
'200'=>'เหรียญ2',
'100'=>'เหรียญบาท',
'50'=>'เหรียญ50สตางค์',
'25'=>'เหรียญ25สตางค์',
);
$n = array();
if ($debug) echo 'จำนวนเงิน '. ($m/100) . ' จะต้องทอน <br'.'>';
foreach($x100 as $x=>$name){
$r = $m % $x;
$idx = (string)($x/100);
$n[$idx] = ($m - $r)/$x;
$m = $r;
if($debug) if (!empty($n[$idx])) echo $name . ' จำนวน ' .$n[$idx]. '<br'.'>';
}
return $n;
}

$exchange = '451.75';
$moneys = return_money($exchange);
print_r($moneys);

?>

วันอังคารที่ 7 ธันวาคม พ.ศ. 2553

การใช้ preg_replace_callback

สำหรับโค้ดตัวนี้สำหรับแปลงข้อมูล bbcode จาก [code][/code] เป็นโค้ดสำหรับแสดงใน
syntax highlighter ครับ

function _hilighter($m){
return '<pre name="code" class="php">'.htmlspecialchars($m[1]).'</pre>';
}
$s=<<<html
[code]
<?php
echo 'hello php.';
?>
[/code]
html;
$s = preg_replace_callback('/\[code\](.+?)\[\/code\]/s','_hilighter',$s);

function ภาษาไทย ที่จัดเก็บเป็น utf8 ใน php

สำหรับคนที่ใช้ภาษาไทย utf8 จะต้องเปลี่ยนจาก substr หรือ strpos ฯลฯ เป็น mb_??? ดังนี้ครับ


<?php
header('content-type:text/html;charset=utf-8');
mb_internal_encoding('UTF-8');
$s = 'ทดสอบ';
$d = 'ลองทดสอบ';
$pos = mb_strpos($d,$s);
echo mb_substr($d,0,$pos);
?>

php coding standard

ผมอาจจะแปลผิดมั่งถูกมั่ง ถ้าอ่านแล้วไม่รู้เรื่องให้ไปอ่านต้นฉบับที่นี่ครับ :D
http://www.dagbladet.no/development/phpcodingstandard/

ชื่อ Class


- ตั้งชื่อให้ตามสิ่งที่มันเป็น
- ชื่อผสมที่มากกว่า 3 คำอาจจะทำให้สับสน, ตรวจสอบการออกแบบว่า object ของคุณมีหน้าที่รับผิดชอบมากเกินไปหรือเปล่า
- อย่าพยายามที่จะนำชื่อ class แม่ มาผสมในคลาสที่ได้รับการสืบทอด ชื่อคลาสควรจะเป็นชื่อที่อธิบายถึงตัวมันเอง
- อาจจะใช้ suffix เพื่อระบุหน้าที่ของ class

ชื่อ method และชื่อ function


- ปกติ method และ function จะทำงานบางอย่าง, ชื่อของมันจึงควรบอกได้ชัดเจนว่ามันทำอะไร
- ใช้ suffix เพื่อระบุข้อมูลที่คืนมาจาก function
--- Max - ค่าสูงสุด
--- Cnt - จำนวนข้อมูล
--- Key - ค่า key
--- ตัวอย่างเช่น pageMax, pageCnt,
- ใช้ prefix เพื่อระบุถึงหน้าที่ของ function
--- is - เพื่อบอกคำตอบของคำถาม
--- get - นำค่าออกมาใช้
--- set - นำค่าไปบันทึก
--- ตัวอย่างเช่น isEmail, setBackgroundColor

ถ้าพบคำย่อซึ่งเป็น uppercase ทั้งหมด
ให้เขียน uppercase เฉพาะตัวแรกเท่านั้น
อย่างเช่น UserID ให้เปลี่ยนเป็น UserId แทน

รูปแบบชื่อคลาส


- ใช้ uppercase เป็นตัวแบ่งคำในชื่อคลาส
- ตัวอักษรตัวแรกเป็น uppercase
- ไม่ใช่ _


รูปแบบชื่อของคลาสไลบรารี่


- ใช้แทน namepsace
- เป็นตัวอักษรสองตัวเพื่อแบ่งแยกกลุ่ม class ที่มาจากที่ต่างๆ กันเช่น คนที่ชื่อ Somchai Jaidee
SjInputValidation


รูปแบบชื่อ method


- ใช้กฎแบบเดียวกับชื่อคลาส
- ** ในบาง standard จะยกเว้นตัวอักษรตัวแรกเป็นตัวเล็ก และอาจจะ _ นำหน้าชื่อ method สำหรับ private หรือ protected method


ชื่อ member attribute


- ควรจะ (ไม่บังคับ) ขึ้นต้นด้วยตัวอักษร m เพื่อให้สามารถแยกชื่อ method กับชื่อ attribute ในกรณีที่มีชื่อซ้ำกัน
- หลังจากตัวอักษร m ให้ใช้กฎเดียวกับการตั้งชื่อ class
- ใช้ r ตามหลัง m เพื่อแทนตัวแปร reference


ชื่อ parameter ของ method


- ตัวอักษรตัวแรกควรจะเป็นตัวเล็ก
- คำต่อไปจะมีวิธีตั้งชื่อเหมือนชื่อ class


ชื่อตัวแปร


- ใช้ตัวอักษรตัวเล็กเสมอ
- ใช้ _ เป็นตัวแบ่งคำ

ชื่อ element ของ array


- ใช้ _ เป็นตัวแบ่งคำ
- ไม่ใช่ - เป็นตัวแบ่งคำ
- จะต้องมี ' ใน key ของ array element
$_POST[name] ผิด
$_POST['name'] ถูก


ตัวแปร reference และ function return reference


- ควรจะนำหน้าด้วยตัวอักษร r


ตัวแปร global


- ควรจะขึ้นต้นด้วยตัวอักษร g

constant


- เป็น uppercase หมด และแบ่งคำด้วย _


ตัวแปร static


- อาจจะขึ้นต้นด้วย s


ชื่อ function


- เป็น lower case หมด และแบ่งคำด้วย _


นโยบายการตรวจสอบค่า error ที่ return จาก function


- ตรวจสอบ error จากค่าที่ return ทุกครั้ง ยกเว้นต้องการเพิกเฉยกับ error
- แทรกการแสดงคำอธิบาย error  ทุกๆ error ที่อาจเกิดขึ้น

นโยบายการใช้ {}


if ($condtion)
{
}
และ
if ($condtion){
}
ตามความเห็นของผมถ้าความซับซ้อนสูงควรจะใช้แบบแรก
เพราะเวลาใช้ editro จะหา { } ที่คู่กันได้ง่าย
แต่แบบหลังจะดีกว่าถ้าเป็นคำสั่งง่ายๆ ทำให้จำนวนบรรทัด sourcecode ไม่ยาวมาก

นโยบายการใช้ identation/tabs และ space


-ในแต่ละ indent จะเท่ากับ space 4 ช่องในแต่ละระดับ
-อย่าใช้ tabs, ใช้ space แทน. editor ส่วนใหญ่สามารถปรับ tab ให้เป็น space
-ใช้ indent เท่าที่จำเป็นอย่ามากเกินไป


นโยบาย การใช้ parens () กับ Keywords และ Functions


- อย่าใช้ parens ถัดจาก keywords. ให้เว้นช่องว่างไว้
- ใช้ parens ติดกับชื่อฟังชั่น
- อย่าใช้ parens ใน return statements ถ้าไม่จำเป็น
    if (condition)
    {
    }
    strcmp($s, $s1);
    return 1;


อย่าเขียนคำสั่งปฎิบัติการจริงใน object constructor


ภายใน constructor จะมีเฉพาะการกำหนดค่าเริ่มต้นให้กับตัวแปรและ/หรือประมวลผลคำสั่งที่ไม่มีทางที่จะเกิดข้อผิดพลาด

   class Device
   {
      function Device()    { /* initialize and other stuff */ }
      function Open()  { return FAIL; }
   };

   $dev = new Device;
   if (FAIL == $dev->Open()) exit(1);


ทำให้ฟังค์ชั่นเรียกใช้เหมือนเดิมได้หลายครั้ง


function ไม่ควรมีตัวแปร static ที่จะทำให้ไม่สามารถใช้งานเหมือเดิม


ใช้ block ในโครงสร้าง switch


switch (){
  case 1:
  case 2:
  {

  }
  break;
}


การใช้ ?:


เพื่อให้อ่านได้ง่ายให้ นำ condition ไว้ใน parens
ถ้าเป็นไปได้ตัวทดสอบควรจะเป็น function ง่ายๆ
วาง action ของ then และ else ไว้แยกบรรทัด ยกเว้นมันสามารถเขียนให้อ่านได้ง่ายในบรรทัดเดียว


การจัดเรียงส่วนประกาศตัวแปร


- ทำให้อ่านได้ง่าย
- กลุ่มของการกำหนดค่าเริ่มต้นควรจัดให้เป็นกล่องซี่เหลี่ยม
- & ควรจะอยุ่ติดกับ type ไม่ใช่ name


ควรจะมี เพียงแค่ statement เดียวในแต่ละบรรทัด


ยกเว้น statement มีความสัมพันธ์กันมาก


method สั้นๆ


- จำนวนบรรทัดควรจะจำกัดอยู่ภายใน 1 หน้า


ให้คำอธิบาย Null Statement


- เพื่อให้แสดงถึงว่าโค้ดทำงานถูกต้อง และ statement แยกออกจาก statment ที่ตามมาชัดเจน


อย่าใช้ค่าที่ไม่ใช่ 0 มาแทนค่าที่เป็นเท็จ


เช่น
if (false != f())
ถ้า function คืนค่า -1 แทน 0 จะทำให้คำสั่งเดิมทำงานเพี้ยนไป
ดังนั้นควรใช้ return ค่าเฉพาะ 0 เท่านั้น
if (f()) แทนเพื่อกันปัญหาที่อาจจะเกิดขึ้น
และไม่ควรใช้กับเงื่อนไข boolean ที่คืนค่าตัวเลข
if (!f()) ควรเขียนเป็น if (0 == f()) แทนจะเหมาะสมกว่า
ในการตั้งชื่อ function boolean ควรจะใช้ IsValid แทน checkValid

หลีกเลี่ยงการแนบ assignment ใน statement อื่นๆ


ถ้ามันทำให้อ่านยากขึ้น ยกเว้นแต่มันช่วยให้เขียนได้ง่ายขึ้นและเป็นส่วนที่ใช้เป็นประจำ
   while ($a != ($c = getchar()))
   {
      process the character
   }


comment


คำอธิบายของบอกเรื่องราว
- อธิบายถึงระบบ, โดยคาดว่ามันจะถูก robot ดึงแปลงไปอยู่ในรูป manual.
คำอธิบายคลาสเป็นส่วนหนึ่งของเนื้อเรื่อง, คำอธิบาย ลายเซ็นของ method (ชื่อ method และจำนวน parameter)
ก็เป็นส่วนหนึ่งของเนื้อเรื่อง, argument ก็เป็นอีกส่วนหนึง และส่วน implement ก็เป็นอีกส่วนหนึ่ง
ทุกๆ ส่วนควรจะถูกนำมาแสดงเพื่อบอกข้อมูลให้กับผู้อื่น เพื่อให้ทราบว่าคุณกำลังทำอะไร และเพราะอะไรจึงทำเช่นนั้น

อธิบายถึงการตัดสินใจ
ทุกๆ จุดซึ่งคุณตัดสินใจที่จะทำอะไรให้เขียนคำอธิบายว่าคุณเลือกวิธีไหนและเพราะอะไร

ใช้ headers
ใช้ระบบดึงเอกสาร อย่างเช่น ccdoc.
ส่วนถัดไปจะอธิบายถึงการใช้ cdoc เพื่ออธิบาย class และ method
headers ถูก structure ในทางที่พวกเขาสามารถ

ทุกๆ ส่วนของโปรเจคจะมี คำอธิบายภาพรวม

Gotcha Keyword แสดงคำอธิบายที่มีลักษณะเฉพาะตัว เพื่อช่วยในการดูแลรักษาและพัฒนาระบบ
:TODO: topic
หมายความว่ามีสิ่งที่ต้องทำที่นี่อีกอย่าลืม

:BUG: [bugid] topic
หมายถึงมี bug ที่รู้ที่นี่อีก, อธิบายมันและอาจจะกำหนดค่า bug ID.

:KLUDGE:
ถ้าคุณได้บางสิ่งที่แย่ไป อธิบายว่าควรจะทำอย่างไรในครั้งถัดไป ถ้าคุณมีเวลามากกว่านี้

:TRICKY:
บอกว่าโค้ดส่วนนี้เป็นเทคนิคพิเศษ ดังนั้นอย่าพยายามเปลี่ยนหากยังไม่ได้พิจารณาขั้นตอนทำงานโดยละเอียด

:WARNING:
แจ้งให้ระวังบางสิ่ง

:PARSER:
บางครั้งกำลังมีปัญหากับการ parse อธิบายว่าตอนนี้ได้ตรวจสอบอะไรไปแล้วบ้าง เพื่อจะใช้วิธีอื่นๆ ในการหาพยายามหาจุดที่เป็นปัญหาแทน

:ATTRIBUTE: value
คุณสามารถกำหนด attribue ที่คุณสร้างขึ้นเองได้

การจัดระเบียบ
ให้ Gotcha keyword เป็นสัญลักษณ์แรกใน comment
คำอธิบายอาจจะมีหลายบรรทัดแต่บรรทัดแรกควรจะเป็นข้อสรุปที่มีความหมายสมบูรณ์ในตัวเอง
ชื่อของผู้เขียน และวันที่ควรจะเป็นส่วนหนึ่งของคำอธิบาย.
แม้ว่าระบบ repository สามารถไล่ตามได้ว่าใครเป็นคนเขียนคำอธิบายนี้แต่ก็ต้องใช้เวลาในการหาว่าใครเป็นคน
เพิ่มข้อมูลนี้เข้าไป. บ่อยครั้งที่ gotcha อยู่นานเกินไปกว่าที่มันควรจะเป้น. การแทรกวันที่ช่วยให้โปรแกรมเมอร์คนอื่น
สามารถตัดสินใจได้ว่าจะทำอย่างไรกับ comment นี้ .การแทรก comment นี้ช่วยให้เรารู้ว่าจะสามารถสอบถามข้อมูลเพิ่มได้จากใคร
   // :TODO: tmh 960810: possible performance problem
   // We should really use a hash table here but for now we'll
   // use a linear search.

   // :KLUDGE: tmh 960810: possible unsafe type cast
   // We need a cast here to recover the derived type. It should
   // probably use a virtual method or template.


ผู้อ่าน document สองกลุ่ม


- Class Users
  ต้องการข้อมูลเกี่ยวกับ class interface วิธีการใช้ method และประกาศ object ฯลฯ ซึ่งจะสามารถอ่านได้จากส่วน header ของไฟล์
  โดยไม่ต้องการข้อมูลรายละเอียดเกี่ยวกับ algorithm ที่ใช้ใน function
- Class Implementors
  ผู้ผลิต class จำเป็นต้องรู้ว่า class ถูกสร้างขึ้นอย่างไร. comment ชนิดนี้จะอยู่ใน souce file ที่สร้าง class
  จะอธิบาย algorithm และการตัดสินใจออกแบบ. และบล้อก comment ใน method ควรจะมีคำอธิบายเพิ่มขึ้นอีก

เอกสารของ directory


ทุกๆ directory ควรจะมีไฟล์ README ซึ่งอธิบาย
- จุดประสงค์ของ directory และอะไรที่มันบรรจุอยู่ข้างในมัน
- คำอธิบาย 1 บรรทัดสำหรับแต่ละไฟล์
- ผู้ที่เกี่ยวข้องกับแหล่งที่มาต่างๆ
--- directory, เอกสารออนไล์, เอกสารกระดาษ, เอกสารการออกแบบ
- อื่นๆ
เอกสารสร้างนี้จช่วยผู้ที่จะแก้ไขโค้ดไม่ต้องไล่อ่านโค้ดในทุกๆ ไฟล์เพื่อหาข้อสรุป


สถานะ open/closed


การระบุสถานะ class ว่า open หรือ close
- open หมายถึงว่า class นั้นสามารถที่จะขยายเพิ่มเติมได้
- closed หมายถึงปิดการแก้ไข แต่ไม่ได้หมายถึงปิดการ extension.
เมื่อคลาสถูกทดสอบ และตรวจสอบว่ามีประสิทธิภาพดีแล้ว, คุณไม่จำเป็นต้องแก้ไข class นั้นมากให้ extend แทน
การตั้งสถานะให้ open/closed ระบบที่ขยายขึ้นมาจะไม่แก้ไขโค้ดที่ทำงานอยู่ก่อนหน้านี้.


อย่าใช้ floating point ในที่ๆ จำเป็นต้องใช้ค่า discrete


อย่างเช่นใน loop for
อย่าใช้ == และ != กับค่า float ให้ใช้ >= และ <= แทน

ใช้ if (0) แทน comment


จะเขียนง่ายกว่า

Accessor Styles


Get/Set
   class X
   {
      function GetAge()        { return $this->mAge; }
      function SetAge($age)    { $this->mAge = $age; }
      var $mAge;
   };

Attributes as Objects
   class X
   {
      function         Age()          { return $this->mAge; }
      function         Name()         { return $this->mName; }

      var              $mAge;
      var              $mName;
   }

   $x = new X;

   // Example 1
   $age = $x->Age();
   $r_age = &$x->Age(); // Reference

   // Example 2
   $name = $x->Name();
   $r_name = &$x->Name(); // Reference


ใช้ tag  <?php ?>


tag รูปแบบอื่นอาจถูกระงับการใช้งานในบาง server


No Magic Numbers


ไม่ใช่ตัวเลข แต่กำหนดค่าตัวเลขเป็น CONSTANT แทน

ช่องว่างระหว่าง token


ในแต่ละคู่อันแรกจะแทนแบบที่ผิดอันที่สองจะแทนแบบที่ถูกต้อง

<?php

$i=0;
$i = 0;

if(( $i<2 )||( $i>5 ))
if ( ($i < 2) || ($i > 5) )

foo ( $a,$b,$c )
foo($a, $b, $c)

$i=($j<5)?$j:5
$i = ($j < 5) ? $j : 5

?>


โครงสร้างควบคุม




if ($a != 2) {
$a = 2;
} else {
$a = 7;
}

if ($a != 2) {
$a = 2;
} elseif ($a == 3) {
$a = 4;
} else {
$a = 7;
}

if (($a == $b)
&& ($b == $c)
|| (Foo::CONST == $d)
) {
$a = $d;
} elseif (($a != $b)
|| ($b != $c)
) {
$a = $c;
} else {
$a = $b;
}



Ref:
http://www.dagbladet.no/development/phpcodingstandard/
http://www.evolt.org/node/60247
http://framework.zend.com/manual/en/coding-standard.coding-style.html

รายชื่อ Zend Framework Components

Zend_Acl


เป็น access controll list ( ACL ) แบบขนาดย่อมแต่มีความยืดหยุ่นสูง สำหรับการกำหนดสิทธิ.
โดยทั่วไป โปรแกรมจะใช้ประโยชน์จาก ACL เพื่อป้องกัน protected objects จาก requesting objects.
ในเอกสารของ ZF จะให้
resource - แทน object ที่จะถูกควบคุมการเข้าถึง
role - จะหมายถึง object ซึ่งจะร้องขอการเข้าถึง resource

Zend_Application


ช่วยให้บรรจุ configuration เริ่มต้นของโปรแกรมได้สะดวก จัดหาทรัพยากรที่นำกลับมาใช้ได้ใหม่
คลาสที่เรียบง่ายและมีความเป็นโมดูล และช่วยในการตรวจสอบ dependency. มันเอาใจใส่กับการสร้าง
environment ของ PHP และตั้งค่าช่วยในการทำให้โปรแกรม autoloding โดย default

Zend_Amf


ช่วยในการเชื่อมต่อกับ Adobe's Action Message Format (AMF)
, เพื่อให้ Flash Player ติดต่อกับ PHP ได้.
มันจัดสรรส่วนการทำงานส่วน gateway server สำหรับควบคุมการ request จาก Flash Player ไปยัง server
และเทียบเคียง request เหล่านั้นไปยัง object และ method ของ class และ callback function ที่ผู้เขียนโปรแกรมสร้างขึ้นมาเอง
การใช้งาน AMFPHP กับ ActionScript 2.0

AMF3 sepecification มีให้อ่านได้ฟรี, ซึ่งช่วยอธิบายให้ทราบว่ามีชนิดของ message อะไรซึ่งสามารถจะส่งไปมาระหว่าง
Flash Player และ server

Zend_Captcha


CAPTCHA เป็นคำย่อของ "Completely Automated Public Turing test to tell Computers and Humans Apart";
มันถูกใช้เป็นเป็นตัวตรวจสอบความสิทธิรูปแบบหนึ่ง เพื่อให้แน่ใจว่าผู้ที่ป้อนข้อมูลเข้ามาแต่ละครั้งเป็นมนุษย์ไม่ใช้โปรแกรมส่งข้อมูลอัตโนมัติ.
โดยทั่วไป, captcha จะถูกใช้พร้อม form กรอกข้อมูลซึ่งอนุญาตให้ใช้งานโดยไม่จำเป็นต้อง login เข้าสู่ระบบสมาชิก แต่คุณต้องการป้องการการส่งข้อมูลจาก spam

โค้ดตัวอย่าง captcha ที่เป็น text ธรรมดาๆ ครับ :)
จริงๆ ควรจะใช้ร่วมกับ Zend_Form นะครับ แต่เนื่องจากผมอยากให้มันดูธรรมดาๆ อันไหนเขียนแบบธรรมดาๆ ได้ก็เขียนแบบธรรมดาๆ ไปเลย

<?php
ini_set('include_path','.'.PATH_SEPARATOR.'c:\mydoc\testweb\zend\library');
require_once 'Zend/View.php';
require_once 'Zend/Captcha/Figlet.php';
require_once 'Zend/Session.php';
$view = new Zend_View();
$captcha = new Zend_Captcha_Figlet(array(
'name' => 'code',
'wordLen' => 6,
'timeout' => 30000
));
if (isset($_POST['captcha'])){
if ($captcha->isValid($_POST['captcha'])) {
echo 'correct!';
}else{
$msg=$captcha->getMessages();
echo current($msg);
}
}
$id = $captcha->generate();
echo '<span style="font-family:fixedsys">';
echo $captcha->render($view);
echo '</span>';
?>
<form action="?" method="post">
<input type="hidden" name="captcha[id]" value="<?php echo $id;?>" id="captcha-id" />
<input type="text" name="captcha[input]" id="captcha-input" value="" />
<input type="submit" value="test">
</form>


Zend_Pdf



<?php
header("Content-type: application/pdf");
ini_set('include_path','.'.PATH_SEPARATOR.'c:\mydoc\testweb\zend\library');
require_once 'Zend/Pdf.php';

$pdf1 = new Zend_Pdf();
$pdfPage = new Zend_Pdf_Page(Zend_Pdf_Page::SIZE_A4);
$pdfPage->setFont(Zend_Pdf_Font::fontWithPath('2005_iannnnnMTV.ttf'), 36);
$pdfPage->drawText('สวัสดีครับท่าน', 50, 842-50, 'UTF-8');
$pdf1->pages[]=$pdfPage;
echo $pdf1->render();


Zend_Soap_Client


อันนี้เป็นตัวอย่างการใช้งาน Zend_Soap_Client คนที่เคยใช้ dotnet xml จะทราบว่า xml ของ dotnet มันไม่ค่อย standard เท่าไหร่
คือ ' หรือ " มันจะไม่ถูกแปลงข้อมูลไปเป็น &quot; อะไรพวกเนี้ยลืมแระ และคิดว่า soap ของ dotnet ก็คงจะไม่ standard อีกเช่นเคย
Zend Framework ก็เลยสร้าง class Zend_Soap_Client_DotNet เสริมขึ้นมาจาก Zend_Soap_Client ธรรมดาเพื่อจัดการ xml format ของ dotnet โดยเฉพาะ ครับ :)
โปรแกรมนี้เรียกใช้ webservice จากเว็บ http://www.webservicex.com ครับ โดยอันนี้จะเป็น service แปลงอัตราแลกเปลี่ยนค่าเงินบาทกับเงินยูเอสดอลล่าครับ

<?php
ini_set('include_path','.'.PATH_SEPARATOR.'c:\mydoc\testweb\zend\library');
$wsdl = 'http://www.webservicex.com/CurrencyConvertor.asmx?wsdl';
require_once 'Zend/Soap/Client/DotNet.php';
$client = new Zend_Soap_Client_DotNet($wsdl);
$result = $client->__call('ConversionRate',array(
'FromCurrency'=>'USD',
'ToCurrency'=>'THB'
));
var_dump($result);
?>

โครงสร้าง MVC ของ Zend Framework

MVC


M (Model) คือเนื้อหาที่อยู่ใน application เช่น data, web service, rss feed
V (View) คือส่วนแสดงผลที่แสดงต่อผู้ใช้
C (Controller) คือส่วนจัดการกับการ request และควบคุมการทำงาน

Controller สามารถบอกให้ View แสดงผลต่างๆ ในแบบต่างๆ
View สามารถส่งข้อมูลไปให้กับ Controller

Controller สามารถดึงเอาข้อมูลจาก Model มาใช้ในการตัดสินใจต่างๆ
และสามารถส่งข้อมูลไปให้ Model เพื่อให้บันทึกข้อมูล

View สามารถเข้าถึง Model เพื่อดึงเอาข้อมูลมาใช้ แต่ไม่สามารถส่งข้อมูลเพื่อให้ Model บันทึกข้อมูล


Front Controller


จัดการกับการ requests
ส่งต่อการควบคุมให้กับ Action Controller
คืนค่า response

Zend_Controller


เกี่ยวกับ Controller
ในการสร้าง Action Controller เราจะสร้าง class ซึ่ง extends Zend_Controller_Action
ในการตั้งชื่อ class เราจะตั้งชื่อให้ลงท้ายว่า Controller ยกตัวอย่างเช่น IndexController
ตัวอักษร _ ในชื่อ class จะแทน subdirectory อย่างเช่น Test_MyController จะหมายถึง Test/MyController.php
URL ของ DoraemonNobitaController คือ /doraemon-nobita หรือ /doraemon.nobita หรือ /doraemonIndex

เกี่ยวกับ Action
คือ method ที่ controller นำมาใช้งาน
โดยจะต้องเป็น public method ที่มีชื่อลงท้ายว่า Action เช่น indexAction(), viewAction()
URL ของ magicItemAction() คือ /doraemon-nobita/magic-item หรือ /doraemon-nobita/magic.item หรือ /doraemon-nobita/magic_item

เกี่ยวกับ Modules
คือกลุ่มของ action controllers, models และ views ที่สัมพันธ์กัน
โครงสร้าง directory จะสัมพันธ์กับโครงสร้าง application directory
ชื่อคลาสของ Controller ควรจะนำหน้าด้วยชื่อ Module
  ยกตัวอย่างเช่น Cartoon_DoraemonController.php ซึ่งจะมีโครงสร้าง directory เป็น Cartoon/controller/DoraemonController.php
ชื่อของ Module จะต้องเป็น camel case เช่นเดียวกับชื่อของ Controller

Request Object  จะบรรจุข้อมูลเกี่ยวกับการ request เอาไว้ทั้งหมด
Router จะแยกข้อมูลจากการ request เช่น url ออกเป็น token ที่แสดงถึง action, controller และ module ของการ request
Dispatcher นำเอา token ที่ได้จากการ routing มาเป็นข้อมูลในการเลือก คลาส metod ของ action controller, จากนั้นจึงสั่งให้มันทำงาน
Response Object จะบรรจุข้อมูล response ที่สมบูรณ์ และมีความสามารถในการส่งข้อมูลกลับไปให้ user

Dispatch Loop

  1. Zend_Controller_Front::getInstance()->dispatch(); จัดการกับ request ที่เข้ามา

  2. สร้าง ออปเจค request และ ออปเจค response ถ้ายังไม่ได้ถูกสร้างขึ้น

  3. ทำการ route request

  4. เข้าสู่ dispatch loop

    • ในการ dispatch action ประกอบด้วยการสร้างออปเจค controller และการเรียก method ของ controller

    • ซึ่งจะทำการ dispatch ไปเรื่อยๆ จนกว่าออปเจค request จะรายงานกลับมาว่าไม่มี action ที่จะต้อง dispatch อีก



  5. คืนค่า response



Routing
default routing ได้แก่
/controller/action/key1/value1/key2/value2
/module/controller/action/key1/value1/key2/value2

การแก้ไข routing เรียกว่า Rewrite Router
Zend_Controller_Router_Rewrite คือส่วนการทำงานของ router ปกติ
อนุญาตให้เพิ่ม named route ได้มากเท่าที่ต้องการ
named route จะช่วยให้สามารถทำงานเกี่ยวกับการ route ได้ในภายหลัง การรวมกันเป็น URL
และการวิเคราะห์หาว่ามีข้อมูลอะไรบ้างที่อยู่ใน URL
การ Route ถูกประมวลผลแบบ LIFO (route ที่นิยามทีหลังสุดจะถูกประมวลผลเป็นอันดับแรก)
Route interface ช่วยให้คุณสามารถสร้างชนิดของการ route ที่จะใช้กับ application ของคุณได้เอง


ชนิดของ Route ที่ได้เตรียมไว้ให้
static: เทียงเคียงอย่างตรงไปตรงมา, ส่งต่อการทำงานสอดคล้องกับการ default route
standard: เทียงเคียงกับส่วนประกอบใน named URL, ยืดหยุ่นและอ่านได้ง่าย แต่ว่าแต่ะละส่วนประกอบจะต้องใช้ regexp ในการเทียบเคียงจึงทำงานค่อนข้างช้า
regex: เทียบเคียงโดยใช้ PCRE, มีความยืดหยุ่นสูงและเร็วกว่าแบบ standard แต่สร้างยากกว่าแบบ standard

ลองดูตัวอย่างการ route นะครับ อันนี้เป็น standard route
เมื่อเพิ่มโค้ดนี้ลงใน c:/www/quick/application/bootstrap.php นะครับ
(ก่อนคำสั่ง unset($frontController, $view, $configuration, $dbAdapter, $registry);)
ก็จะทำให้ http://localhost/quick/public/homepage ชี้ไปที่ controller index, action index ครับผม
หรือ http://localhost/quick/public/homepage ชี้ไปที่เดียวกับ http://localhost/quick/public ครับ

// Create a router
$router = $frontController->getRouter(); // returns a rewrite router by default
$router->addRoute(
'myRouteName',
new Zend_Controller_Router_Route('homepage',
array('controller' => 'index',
'action' => 'index'))
);

Action Controllers


คือคลาสที่ extends จาก Zend_Controller_Action
ใช้กำหนด public action (method ที่ลงท้ายด้วย Action) ที่ต้องการให้ controller ควบคุม
สร้าง public method ถ้าต้องการจะนำกลับมาใช้ใหม่ หรือหากต้องการให้ทดสอบโปรแกรมได้สะดวก

ใน Action Controller เราสามารถสร้าง method เพื่อ listen และแทรกคำสั่งใน event ต่อไปนี้
init(): method ที่จะถูกเรียกเมื่อ object ของ Action Controller ถูกสร้างขึ้น
preDispatch(): method ที่จะถูกเรียกก่อนการ dispatch action
postDispatch(): method ที่จะถูกเรียกหลังการ dispatch action

Utility Methods
_forward : ใช้เพื่อย้ายไปยัง action อื่น
_redirect : ใช้เพื่อย้ายไปยัง url อื่น
render : ใช้เพื่อเปลี่ยนไปใช้ view อื่นแทน default view
__call : สามารถ override method นี้เพื่อควบคุมการทำงาน undefined action ว่าจะให้ forward ไปยัง action ไหน

ViewRenderer


เป็น action helper ตัวนึงที่ ZF จะสร้าง object ขึ้นมาให้โดยอัตโนมัติ
property view ($this->view) ของ controller คือออปเจค view
เราสามารถกำหนดค่าตัวแปรให้ view โดยใช้คำสั่ง
$this->view->varname = $varname;

View Script จะถูกนำมาแสดงผลโดยอัตโนมัติหลังจาก event postDispatch()
view script จะมีชื่อตาม controller และ action
ตัวอย่างเช่น DoraemonController::showItemsAction จะมีไฟล์ view script คือ /view/scripts/doraemon/show-items.phtml
เราสามารถใช้คำสั่ง setNoRender() เพื่อบอกให้ controler ไม่นำ view script มาแสดงผลโดยอัตโนมัติ

คำสั่งเกี่ยวกับ ViewRenderer
setView
setViewSuffix
setView(Base|Script)PathSpec()
setResponseSegment()


Plugins


plugin จะถูกเรียกใน event ของ front controller
มีการแทรก event ในทุกๆ ขบวนการหลักของ front controller
ช่วยให้สามารถสร้าง action แบบ global (แทรกคำสั่งเพิ่มเข้าไปในทุกๆ action)

event
routeStartup(): ทำงานก่อนการ route
routeShutdown(): ทำงานหลังการ route
dispatchLoopStartup(): ทำงานก่อน รอบแรกของ dispatch loop
preDispatch(): ทำงานก่อนการ dispatch action
postDispatch(): ทำงานหลัง dispatch action
dispatchLoopShutdown(): ทำงานหลังจากที่ dispatch loop วนซ้ำจบ

การสร้าง plugins
ให้สร้างคลาส extends Zend_Controller_Plugin_Abstract
เขียน override event ลงใน คลาสดังกล่าว โดยอาจจะเขียนเพียง event เดียวหรือหลาย event ก็ได้


Action Helpers


Action Helper คือคลาสที่รวมเอา function ที่นำกลับมาใช้ได้ใหม่ในหลายๆ controller

การสร้าง Action Helper
สร้างคลาส extends Zend_Controller_Action_Helper_Abstract
ส่วนสุดท้ายของชื่อคลาสคือชื่อของ helper
ตัวอย่างเช่น My_Helper_SuperMan 'SuperMan' คือชื่อของ helper
สร้าง method direct() เพื่อให้ helper ถูกเรียกราวกับว่าเป็น mehod ของ helper broker

การใช้ Action Helper เป็น Action Controller Event Listener

init(): เมื่อ action controller ถูกสร้างขึ้น
preDispatch(): ทำงานหลังจาก preDispatch() ของ front controller plugins แต่ทำงานก่อน preDispatch() ของ action controller
postDispatch(): ทำงานหลังจาก postDispatch() ของ action controller แต่ทำงานก่อน postDispatch() ของ front controller plugins

โน๊ต : event listener ของ helper จะถูก trigger ก็ต่อเมื่อได้ทำการลงทะเบียนกับ broker


Zend_View


สร้างคลาสจาก Zend_View_Interface เพื่อสร้าง template engine ของคุณเอง
default คลาส Zend_View ใช้ ภาษา PHP เป็น template language
สามารถกำหนดค่าตัวแปร view ราวกับว่ามันเป็นสมาชิกของ object อย่างเช่น $view->varname = $varname;
ใช้งานตัวแปร view ใน view script ได้จากออปเจค $this ตัวอย่างเช่น <?= $this->varname ?>


View Helper


เป็นคลาสซึ่ง ขยายความสามารถให้กับ Zend_View
ตัวอย่างเช่นช่วย นำเข้า rss feed มายังเว็บเพจ
จัดรูปแบบ text ให้อยู่ในรูปแบบ xhtml
ช่วยแสดงผลตามเงื่อนไขที่ตั้งไว้อย่างเช่นแสดงผลปุ่ม login ถ้ายังไม่ได้ login
ส่วนแสดงผลที่สามารถนำกลับมาใช้หลายๆ ครั้ง เช่นกล่อง serach

การใช้ View Helper
เรียกใช้งาน Vew Helper ราวกับว่ามันเป็น method ของออปเจค View
<?= $this->formText('username') ?>

การสร้างและใช้งาน View Helper
ชื่อคลาส My_View_Helper_Coffee จะมีชื่อ helper เป็น coffee
ลงทะเบียน helper paths กับออปเจค Zend_View

จะต้องมีชื่อ method ชื่อเดียวกับ helper ดังนี้

<?php
class My_View_Helper_Coffee
{
  function coffee(){
  }
}
?>


View Filter


ช่วยในการกรอง content ก่อนจะนำไปแสดงผลจริงๆ
เหมือนกับ View Helper คือจะต้องสร้างคลาสซึ่งมี 1 method ต่อ 1 class
ประโยชน์ของ Filter เช่นแปลง HTML เป็น PDF, JSON, ลบแท็ก script ออกไปจาก content

Zend_Model


ตัวอย่างของ Model ได้แก่ Database, Web Service, RSS Feeds, FileSystem, Images

Zend Framework ระบุถึง Model ได้อย่างไร
ZF ยังไม่ได้สร้าง Model ที่เป็นแบบทั่วไปขึ้นมา
แต่ ZF สนับสนุน Model ที่มีความเฉพาะเจาะจงตัวอย่างเช่น Zend_Db_Table, Zend_Service, Zend_Feed


reference
Ophinney_Matthew_2007-ZendCon-MVC.pdf