20 กุมภาพันธ์ 2552

subdomain บน localhost

subdomain คืออะไร? subdomain คือ domain name ย่อยๆของเว็บไซต์หลักอีกทีครับเช่น http://www.goragod.com หรือ http://goragod.com อาจมี subdomain เป็น http://chat.goragod.com ซึ่งหมายถึง url ของ chat หรือ http://blog.goragod.com ซึ่งหมายถึง url ของ blog ครับ โดยทั่วๆไปเรามักกำหนดให้ subdomain เป็นไดเร็คทอรี่หนึ่งๆของเว็บไซต์ เช่นอาจเป็น http://www.goragod.com/chat แต่เพื่อให้เรียกใช้ง่ายขึ้นก็เลยทำเป็น subdomain ในชื่อ http://chat.goragod.com แทน ซึ่งก็จะทำให้ url จดจำได้ง่ายขึ้นครับ และก็ไม่ต้องเสียตั้งจดทะเบียนหลายๆโดเมนด้วย

การสร้าง subdomain บน server สร้างยังไงผมคงไม่พูดถึงแหละครับ แต่ละ server ก็คงมีการสร้างแตกต่างกันออกไป แต่สำหรับผู้ใช้ Appserver สิครับ อยากทดสอบเว็บในรูปของ subdomain จะทำไงดีหนอ ?

ปกติ บน localhost เมื่อติดตั้ง Appserver เราจะได้ server ในชื่อ http://localhost หากเราจะเพิ่ม subdomain เป็น http://blog.localhost โดยที่เมื่อเรียก url นี้แล้วจะไปทำการเปิดเว็บที่ C:/AppServ/www/blog ขึ้นมาทำงาน ทำได้ดังนี้ครับ

1.เปิดไฟล์ C:\windows\system32\drivers\etc\hosts ด้วย text editor ทั่วไปครับ ในนั้นจะพบข้อความประมาณนี้

# Copyright (c) 1993-1999 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
#102.54.94.97 rhino.acme.com # source server
#38.25.63.10 x.acme.com # x client host
127.0.0.1 localhost

 

ให้แทรก

127.0.0.1 blog.localhost


ลงในข้อความบรรทัดต่อจาก

127.0.0.1 localhost


ครับจะได้เป็นประมาณว่า

# 102.54.94.97 rhino.acme.com # source server
# 38.25.63.10 x.acme.com # x client host
127.0.0.1 localhost
127.0.0.1 blog.localhost


แล้วก็ save

บรรทัดที่เพิ่มขึ้นมาเป็นการกำหนด host ที่เราต้องการครับ อยากเปลี่ยนเป็นชื่ออื่นก็ตามใจ หรือหากต้องการหลายๆ subdomain ก็เขียนเพิ่มเติมเข้าไปแต่ละบรรทัดครับ

2.ทำให้ Appserver รู้จัก host ที่สร้างขึ้นและรู้ว่าต้องไปที่ไหนครับ

เปิดไฟล์ httpd.conf ของ Appserver ครับไม่รู้ว่าอยู่ที่ไหนดูในเมนูของ Appserver ก็ได้ครับ คลิกที่ Apache Edit the httpd.conf Configuration File เพิ่มเติม

<VirtualHost *:80>
ServerName localhost
DocumentRoot C:/AppServ/www
</VirtualHost>

<VirtualHost *:80>
ServerName blog.localhost
DocumentRoot C:/AppServ/www/blog
</VirtualHost>


ลงบนส่วนต้นๆของไฟล์ก็ได้ครับ

ส่วนแรก เป็นการบอกให้ Appserver รู้จัก localhost ตามปกติแหละครับ
ServerName localhost <== ชื่อ host http://localhost
DocumentRoot C:/AppServ/www <== ไดเร็คทอรี่ที่เก็บไฟล์

ส่วนที่ 2 ก็สำหรับ blog ที่สร้างขึ้นใหม่ครับ

เสร็จแล้ว save แล้วก็ Restart Appserver ใหม่ครับ ทดสอบโดยการพิมพ์ http://localhost จะต้องไปเปิดเพจตามปกติ แต่ถ้าพิมพ์ http://blog.localhost จะต้องไปเปิด blog ครับ เราสามารถเพิ่มเติมได้หลาย subdomain ตามที่กำหนดไว้ในข้อ 1 โดยเพิ่มแต่ละ section ลงไปนะครับ

 

สร้างหลายโดเมน บน localhost (APACHE)

ปกติแล้วเมื่อเราติดตั้ง Appserver เราจะได้โดเมนเนมเป็น http://localhost หากเราต้องการเปลี่ยนเป็นชื่ออื่น เช่น http://project หรือเมื่อต้องการมีหลายๆ โดเมน เพื่อใช้กับหลายโปรเจ็ค จะทำไงดี

ยกตัวอย่างเช่น http://project1 เก็บไฟล์ไว้ที่ ไดเร็คทอรี่ project1 และ http://project2 เก็บไฟล์ไว้ใน project2 การจัดการหรือทดสอบคงง่ายขึ้นเยอะ ยิ่งถ้ามีหลายๆโปรเจ็คด้วยแล้วละก็งานคงง่ายขึ้นเยอะ

หลักการเบื้องต้นก็คล้ายๆกับ การทำ subdomain บน localhost คือ

1.เปิดไฟล์ C:\windows\system32\drivers\etc\hosts ด้วย text editor ทั่วไปครับ แล้วเพิ่ม โดเมนที่ต้องการลงไป เช่น

127.0.0.1    project1
127.0.0.1    project2


แล้วก็ save ครับ

สามารถเพิ่มได้ตามจำนวนโปรเจ็คที่ต้องการ และชื่อที่ต้องการ (รวมถึงสามารถทำ subdomain ได้ด้วยครับ)

2.เปิดไฟล์ httpd.conf ของ Appserver ครับไม่รู้ว่าอยู่ที่ไหนดูในเมนูของ Appserver ก็ได้ครับ คลิกที่ Apache Edit the httpd.conf Configuration File 

กำหนด ServerName ซึ่งปกติจะถูกกำหนดเป็น localhost ให้เป็น IP Address ครับ

ServerName localhost:80

เปลี่ยนเป็น

ServerName 127.0.0.1:80


3.กำหนด ไดเร็คทอรี่ให้กับ domain ที่สร้างขึ้นด้วย VirtualHost ซึ่งก่อนอื่นเราต้องกำหนด NameVirtualHost ก่อนที่จะกำหนด VirtualHost นะครับ

NameVirtualHost *:80

<VirtualHost *:80>

ServerName localhost

DocumentRoot "C:/AppServ/www"

</VirtualHost>

 

<VirtualHost *:80>

ServerName project

DocumentRoot "C:/AppServ/www/project1"

</VirtualHost>

 

<VirtualHost *:80>

ServerName project2

DocumentRoot "C:/AppServ/www/project2"
</VirtualHost>

เราสามารถแทรกโค้ดนี้ไว้ตั้งแต่บรรทัดแรกของไฟล์ที่เปิดขึ้นมาได้เลยครับ

ความสำคัญของการกำหนดไดเร็คทอรี่ คือ ไดเร็คทอรี่ที่ต้องการต้องอยู่ภายใต้ DocumentRoot ของ Appserver เช่นปกติ มันจะถูกกำหนดไว้ที่ C:/AppServ/www เราก็ต้องกำหนด sub directory ภายใต้โฟลเดอร์นี้เท่านั้นเช่น C:/AppServ/www/project1


4.หลังจากนั้นก็ทำการสร้างไดเร็คทอรี่ที่จะใช้เก็บไฟล์ต่างๆ แล้วก็ Restart Apache ใหม่เป็นอันเสร็จครับ

ทีนี้การทดสอบก็ง่ายขึ้นแล้วครับ

 

ปัญหาการส่งเมล์ แล้วเป็นภาษาขอม UTF8

หากเว็บไซต์ของท่านทำการส่งเมล์ ด้วย UTF-8 อาจพบกับปัญหาภาษาขอม อันเนื่องมาจากภาษาหลักของเว็บที่อ่าน อีเมล์ก็ได้ครับ ยกตัวอย่างการส่งเมล์ที่เป็น UTF-8 ไปยัง hotmail มักเกิดเป็น ภาษาขอมเสมอ

แต่กับเจ้าอื่นอย่าง yahoo ไม่เป็นปัญหาครับ มันสามารถอ่าน email ที่เป็นภาษาไทยได้ถูกต้อง แต่โดยปกติแล้ว ปัญหานี้จะเกิดกับหน้า Inbox เท่านั้น ในส่วนของหน้า อ่านอีเมล์ มักจะไม่เป็นปัญหา แต่ถ้าในหน้าอ่านอีเมล์ของคุณก็อ่านไม่ออกเช่นกันให้ลองส่งเมล์เป็น HTML ครับ

ปัญหานี้ ถ้าแก้ที่ปลายเหตุ ก็คงต้องอาศัยการเปลี่ยน encoding ของ Browser เอาเอง เปลี่ยนให้เป็น UTF-8 ซะมันก็อ่านออก สำหรับ user บางคนที่ไม่รู้วิธีนี้ ก็อาจใช้วิธี มีข้อความภาษาอังกฤษ แจ้งให้ user ทำการเปลี่ยนภาษา

if you cannot read this email, please change your browser encoding to UTF-8

อันนี้เป็นการแก้ที่ปลายเหตุครับ

ส่วนถ้าจะแก้กันที่ต้นเหตุ ก็คงต้องไปเปลี่ยนการเข้ารหัสเมล์ ให้เป็น Ansi แทน UTF-8 ด้วยการใช้ ฟังก์ชั่นแปลงให้เป็น TIS-620 ก่อนส่ง

mail( $mailto , iconv( 'UTF-8' , 'TIS-620' , $subject ) , iconv( 'UTF-8' , 'TIS-620' , $msg ) , $Headers );


แปลงทั้ง 2 ส่วนนะครับ ทั้ง subject และ msg โดยใช้ร่วมกับเมล์แบบ HTML ที่ผมกล่าวถึงข้างบน นอกจากนี้ วิธีเหล่านี้จะทำให้ email ของคุณหลุดจาก ถังขยะ ได้อีกด้วย

class Timer สำหรับการทำ Bench Mark

class Timer เป็น class สำหรับอ่านค่าเวลาเป็น ไมโครวินาที เพื่อการตรวจสอบหรือการทำ Bench Mark โค้ด PHP ด้วยฟังก์ชั่น getMicrotime()

<?php
class Timer{
    private $elapsedTime;

   
// start timer
    public function start()
    {
        if( !$this->elapsedTime = $this->getMicrotime() )
        {
            throw new Exception( 'Error obtaining start time!' );
        };
    }

   
// stop timer
    public function stop()
    {
        if( !$this->elapsedTime = round( $this->getMicrotime() - $this->elapsedTime , 10 ) )
        {
            throw new Exception( 'Error obtaining stop time!' );
        };
        return $this->elapsedTime;
    }

   
// define private 'getMicrotime()' method
    private function getMicrotime()
    {
        list( $useg , $seg ) = explode( ' ' , microtime() );
        return ( (float)$useg + (float)$seg );
    }
};
?>


ตัวอย่างการใช้งาน

<?php
$val = range( '0' , '1000' );
// แอเรย์ที่กำหนด

$a = '';
$bm = new Timer;
// เรียกใช้งาน class
$bm->start();
// เริ่มต้นจับเวลา
// ประมวลผลการทดสอบ
for( $i = 0 ; $i < count($val) ; $i++ )
{
    $a .= $val[$i];
}
echo $bm->stop();
// แสดงเวลาที่ใช้ไป
?>

 

File Directory

มีตัวอย่างทดสอบการระบุ Path หรือ Root ให้ถูกต้อง รวมทั้งแสดงค่าระบบที่เกี่ยวกับ Path ด้วยครับ

<html>
<head>
<meta http-equiv="Content-Type"content="text/html;charset=windows-847">
<title>โปรแกรม ทดสอบค่าต่างๆของ Server</title>
<style>
 
<!--
    A:link {color: "black"; text-decoration: none; font-weight: bolder; font-size: x-small}
    A:visited {color: "black"; text-decoration: none; font-weight: bolder; font-size: x-small}
    A:hover {color: "blue"; text-decoration: none; font-size: x-small}
    table {color: black; font-family: Tahoma; font-size: x-small}
    body {color: black; font-family: Tahoma; font-size: x-small}
    input {color: black; font-family: Tahoma; font-size: x-small}
    img {border: none}
    pre {font-family: Tahoma; font-size: x-small}
  -->

</style>

</head>
<font face="Tahoma" size="2" color="black"><div align="center"><b>โปรแกรมทดสอบเว็บเพจ <font color="red">PHP</font></b></div>
<?
     echo "
<br><b><font color=green>ตัวแปรแสดงค่าต่างๆของระบบ</font></b>";
     echo "
<br><b>".'$_SERVER[DOCUMENT_ROOT] = '."</b>".$_SERVER[DOCUMENT_ROOT];
     echo "
<br><b>".'$_SERVER[PATH_TRANSLATED] = '."</b>".$_SERVER[PATH_TRANSLATED];
     echo "
<br><b>".'$_SERVER[SCRIPT_NAME] = '."</b>".$_SERVER[SCRIPT_NAME];
     echo "
<br><b>".'$_SERVER[SERVER_NAME] = '."</b>".$_SERVER[SERVER_NAME];
     echo "
<br><b>".'$_SERVER[HTTP_HOST] = '."</b>".$_SERVER[HTTP_HOST];
     echo "
<br><b>".'$_SERVER[PHP_SELF] = '."</b>".$_SERVER[PHP_SELF];
     echo "
<br><b>".'$_SERVER[HTTP_REFERER] = '."</b>".$_SERVER[HTTP_REFERER];
     echo "
<br><b>".'$_SERVER[REMOTE_ADDR] = '."</b>".$_SERVER[REMOTE_ADDR];
     $root=$_POST["root"];
     $dirs=$_POST["dirs"];
     $dirsep=$_POST["dirsep"];
     if (empty($root)) $root=$_SERVER[DOCUMENT_ROOT];
     if (empty($dirsep)) $dirsep='/';
     else if ($dirsep!='/') $dirsep='\';
     else $dirsep='/';
     $root=ereg_replace("/$", "", $root)."/";
?>

<form method="post" action="test.php">
<b><font color="gray">Root :</font></b> <input type="text" name="root" size=51 maxlength=50 value="<?=$root?>">&nbsp;&nbsp;<input type="submit" value="กำหนด root" name="submit">
<br><input type="checkbox" name="dirsep" value='\' <?if ($dirsep=='\') echo checked?>><b><font color="gray"> : ใช้ \ ในการแบ่งไดเร็คทอรี่</font></b>
<br><input type="checkbox" name="dirs" value='/' <?if ($dirs=='/') echo checked?>><b><font color="gray"> : มีเครื่องหมาย / ปิดไดเ็คทอรี่สุดท้าย</font></b>
<br><br>
<?
    
//ทดสอบสร้างไฟล์บน root
     $filer=$root."_temp.php";
     $filer=ereg_replace("/", $dirsep, $filer);
     echo "
<br>".'fopen('.$filer.", \"w\") ";
     $fr=fopen($filer, "w");
     if (!$fr) {
          echo "
<font color=red> ไม่สามารถสร้างไฟล์บน <b>$root</b> ได้</font> ";
     } else {
          echo "
<font color=green> สร้างไฟล์บน <b>$root</b> ได้</font> ";
          fwrite($fr, "
<font color=green>นี่คือไฟล์ $filer ที่สร้างขึ้น ด้วย ".'fopen'."</font><br><a href=newlink.php>ลิงค์</a> <a href=/newlink.php>/ลิงค์</a> <a href=./newlink.php>./ลิงค์</a> <a href=../newlink.php>../ลิงค์</a>");
          fclose($fr);
          echo "
<br>".'include('.$filer.') '; if (!include($filer)) echo "<font color=red> ไม่สามารถอ่านไฟล์ในไดเร็คทอรี่ root ได้</font> ";
     }
    
    
//ทดสอบสร้างไดเร็คทอรี่บน root
     $makedir=$root."testdir".$dirs;
     $makedir=ereg_replace("/", $dirsep, $makedir);
     echo '
<br><br>is_dir('.$makedir.')';
     $direxists=is_dir($makedir);
     if ($direxists) {
          echo "
<font color=gray> มีไดเร็คทอรี่ <b>$makedir</b> อยู่แล้ว</font> ";
          $dirok=true;
     } else {
          echo "
<font color=gray> ไม่มีไดเร็คทอรี่ <b>$makedir</b></font> ";
          echo  '
<br>mkdir('.$makedir.', 0777)';
          $dirok=mkdir($makedir, 0777);
          if (!$dirok) echo "
<font color=red> ไม่สา่มารถสร้างไดเร็คทอรี่บน <b>$root</b> ได้</font> ";
          else echo "
<font color=green> สา่มารถสร้างไดเร็คทอรี่บน <b>$root</b> ได้</font> ";
     }
    
     if ($dirok) {
         
//ทดสอบสร้างไฟล์บนไดเร็คทอรี่ที่สร้างใหม่
          $filen=$root."testdir/_temp.php";
          $filen=ereg_replace("/", $dirsep, $filen);
          echo "
<br><br>".'fopen('.$filen.", \"w\") ";
          $fn=fopen($filen, "w");
          if (!$fn) {
               echo "
<font color=red> ไดเร็คทอรี่ <b>$makedir</b> อ่านได้อย่างเดียว</font> ";
          } else {
               echo "
<font color=green> สร้างไฟล์บนไดเร็คทอรี่ที่สร้างได้</font> ";
               fwrite($fn, "
<font color=green>นี่คือไฟล์ $filen ที่สร้างขึ้น ด้วย ".'fopen'."</font><br><a href=newlink.php>ลิงค์</a> <a href=/newlink.php>/ลิงค์</a> <a href=./newlink.php>./ลิงค์</a> <a href=../newlink.php>../ลิงค์</a>");
               fclose($fn);
               echo "
<br>".'include('.$filen.') '; if (!include($filen)) echo "<font color=red> ไม่สามารถอ่านไฟล์ในไดเร็คทอรี่ที่สร้างได้</font> ";
          }
     }

     //อ่านไดเร็คทอรี่ root
     $root=ereg_replace("/", $dirsep, $root);
     $DIR = opendir($root);
     if (!$DIR) echo "
<br><br><font color=red>ไม่สามารถอ่านไดเร็คทอรี่ $root ได้</font>";
     echo "
<br>";
     while ($text = readdir($DIR)) {
          $readdir=$root.$text;
          $text="
<br><font color=gray><b>$readdir</font>";
          if (is_dir($readdir)) {
               $text.="
<font color=maroon> ไดเร็คทอรี่";
               if (!is_writeable($readdir)) $text.="อ่านอย่างเีดียว";
               $text.="
</font>";
          }
          $text.="
</b> ";
          echo $text;
     }
     closedir($DIR);
    
     echo "
<br> ";
     if ($fr) {echo "
<br>".'unlink('.$filer.')'; if (!unlink($filer)) echo "<font color=red> ลบไฟล์ในไดเร็คทอรี่ root ไม่สำเร็จ</font>";};
     if ($fn) {echo "
<br>".'unlink('.$filen.')'; if (!unlink($filen)) echo "<font color=red> ลบไฟล์ในไดเร็คทอรี่ย่อยไม่สำเร็จ</font>";};
     if (!$direxists) {echo "
<br>".'rmdir('.$makedir.')'; if (!rmdir($makedir)) echo "<font color=red> ลบไดเร็คทอรี่ย่อยไม่สำเร็จ</font>";};
?>

</form>


</font>
</body>
</html>

 

การตรวจสอบการอัปโหลดครั้งละหลายๆไฟล์

โค้ดนี้จะรวมเอาการตรวจสอบชนิดของไฟล์อัปโหลด และตัวอย่างการอัปโหลด ไว้ด้วยกัน โดยการใช้ input ชนิด file ในแบบ แอเรย์

ส่วนแรกเป็นฟอร์มสำหรับอัปโหลดครับ เมื่อคลิก Submit จะส่งไปยัง upload.php

<form method="post" action="upload.php" enctype="multipart/form-data">
<input type="file" name="file[]" size="40"><br>
<input type="file" name="file[]"  size="40"><br>
<input type="file" name="file[]"  size="40"><br>
<input type="file" name="file[]" size="40"><br>
<input type="file" name="file[]" size="40"><br>
<input type="submit" name="Submit" value="upload"
</form>

upload.php ไฟล์สำหรับรับการอัปโหลดที่ส่งมา ผมใช้วิธีการวน loop ด้วย foreach นะครับ เพื่อให้เห็นความแตกต่างจากการใช้ for ธรรมดาที่คุ้นเคย การใช้ foreach จะทำให้เราไม่ต้องกังวลว่าจะมี input ส่งมาทั้งหมดกี่ตัว เหมาะสำหรับการทำฟอร์มแบบที่สามารถเปลี่ยนแปลง input ได้

<?
// แอเรย์ของ mmie ที่ต้องการ
$typies = array(  "image/pjpeg" , "image/jpg" , "image/gif" );
// ตรวจสอบการอัปโหลด
foreach( $_FILES[file][type] as $i => $type )
{
     if ( $type != ''  && in_array( $type , $typies ) )
     {
         
// อัปโหลด
         
echo 'อัปโหลด '.$_FILES[file][tmp_name][$i].'<br />';
     }
     else if ( $type != '' )
     {
         
// error
          echo 'ชนิดของไฟล์  '.$_FILES[file][name][$i].' ไม่ถูกต้อง<br />';
     };
};
 ?>

การอัปโหลดจะเกิดขึ้นในกรอบข้อความสีแดงครับ ให้เขียนการอัปโหลดขึ้นที่นั้น ตัวแปร $i ใช้สำหรับบอกว่าเป็น input ตัวที่เท่าไร ครับ ถ้าสังเกตุให้ดี จะเห็นว่า ระหว่างการอัปโหลดสำเร็จหรือไม่สำเร็จผมใช้ตัวแปรที่รับมาจาก input ต่างกัน เพื่อให้สามารถเทียบเคียงการใช้งานเอาได้ครับ

 

การตัดข้อความตามความยาวที่กำหนด สำหรับ UTF-8

การตัดข้อความตามความยาวที่กำหนดบน PHP ปกติแล้วเราใช้ฟังก์ชั่น substr ของ PHP ครับ แต่ฟังก์ชั่นนี้มันทำงานกับ Ansi เท่านั้น ไม่สามารถทำงานกับ UTF-8 ได้ ถ้านำมาใช้กับ UTF-8 ภาษาอังกฤษจะถูกต้องดี แต่ถ้าเป็นภาษาไทยแล้วอาจเหลือตัวสี่เหลี่ยมแถมกลับมาได้

ให้ใช้ฟังกชั่น  substr_utf8 แทนครับ

function substr_utf8( $str, $from , $len )
{
 return preg_replace( '#^(?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,'.$from.'}'.
  '((?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,'.$len.'}).*#s',
  '$1' , $str );
};


ฟังก์ชั่นนี้มีรูปแบบและวิธีการใช้เหมือนกับ substr ทุกประการครับ

การหาความยาวของข้อความบน UTF-8

ความยาวของข้อความก็เป็นอีกปัญหาหนึ่งของ UTF-8 ที่ไม่สามารถใช้ strlen ในการอ่านความยาวที่ถูกต้องได้ เนื่องจาก UTF-8 มีการเก็บตัวอักษรที่กว้างกว่า Ansi ทำให้การหาความยาวโดยเฉพาะภาษาไทยผิดพลาด

ให้ใช้ strlen_utf8 แทนครับ

function strlen_utf8( $str )
{
 $i = 0;
 $count = 0;
 $len = strlen( $str );
 while ( $i < $len )
 {
  $chr = ord( $str[$i] );
  $count++;
  $i++;
  if ( $i >= $len )
  {
   break;
  };
  if ( $chr & 0x80 )
  {
   $chr <<= 1;
   while ( $chr & 0x80 )
   {
    $i++;
    $chr <<= 1;
   };
  };
 };
 return $count;
};


ฟังก์ชั่นนี้มีการใช้งานเหมือนกับ strlen ทุกประการครับ

 

การสร้างเว็บไซต์แบบ AJAX (ตอนที่ 1)

เว็บเพจแบบ AJAX ก็คล้ายๆ IFRAME ในการโหลดการแสดงผลในบางส่วน ในตัวอย่างจะเป็นการใช้ AJAX เพื่อโหลดส่วน rightmodule มาแสดงด้วยฟังก์ชั่น loaddoc โดยการคลิกที่ลิงค์ ก็จะเป็นการโหลดหน้านั้นๆมาแสดง เช่น

<a href="javascript:loaddoc('page1.php')">Page1</a>

page1.php ถ้าไม่ได้อยู่ไดเรคทอรี่เดียวกันกับหน้าหลัก ให้ระบุ path ให้ถูกต้องด้วย

function loaddoc(module) {
var req=Inint_AJAX();
  //แสดง icon คอยการ load ก่อนเลยถ้ามีการเรียกใช้ AJAX
  document.getElementById("rightmodule").innerHTML='<div id="wait"><img src="../images/wait.gif" alt="" /><br /><br />กำลังโหลด...</div>';
  req.onreadystatechange = function () {
    if (req.readyState==4) {
      if (req.status==200) {
        var data=req.responseText; //รับค่ากลับมา
        document.getElementById("rightmodule").innerHTML=data; //แสดงผล แทนรูปรอโหลด
      }
    }
  };
  req.open("GET", module, true);
  req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); // set Header
  req.send(null); //ส่งค่า
}


ส่วนที่อยากให้ดูก็คือส่วนที่เป็นสีแดง ส่วนแรก

document.getElementById("rightmodule").innerHTML='<div id="wait"><img src="../images/wait.gif" alt="" /><br /><br />กำลังโหลด...</div>';

โค้ดนี้เป็นการแสดงรูปรอโหลดเมื่อมีการเรียกฟังก์ชั่น loaddoc (ด้วยการคลิกเมนู) 

req.open("GET", module, true);

module ก็คือชื่อเพจที่จะให้ AJAX เรียกมาแสดงที่ส่งมากับการเรียกฟังก์ชั่น loaddoc

นอกจากนี้เรายังสามารถให้เพจโหลดหน้าใดหน้าหนึ่งมาแสดงตอนโหลดครั้งได้โดยการแทรกโค้ด onload ใน body

<body onload="loaddoc('page1.php')"> 

ซึ่งจะเป็นการเรียก page1.php มาแสดงตอนโหลดครั้งแรก

สำหรับส่วนอื่นๆที่น่าสนใจในเพจนี้ ก็คือการใช้ CSS เพื่อจัด Layout ให้กับเพจ ให้คลิกขวาเพื่อ View Source ได้เลย

AJAX กับ JSON (ตอนที่ 1)

JSON (JavaScript Object Notation) เป็นวิิธีหนึ่งที่จะทำให้ AJAX แลกเปลี่ยนข้อมูลกับ Server ได้อย่างง่ายๆ ซึ่งถ้าใช้ XML ส่งข้อมูลกลับมาเราก็ยังต้องมี parser เพื่อจัดการแยกข้อมูลออก เพื่อไปจัดการแสดงผลอีกที(หรือแม้กระทั่งส่งข้อมูลมาในแบบ Text เช่นกัน) แต่ JSON จะใช้เพียงคำสั่ง eval() ก็จะได้ข้อมูลกลับมาเป็น Array เพื่อให้ไปทำการจัดการแสดงผลได้อย่างง่ายๆ โดยไม่ต้องผ่านขั้นตอนการ parser

สมมุติให้มีข้อมูลเป็นดัง Array นี้

members[0][firstname]="สมชาย"
members[0][lastname]="สายเสมอ"
members[1][firstname]="ไมรู้"
members[1][lastname]="ไม่ทราบ"


JSON จะ ใช้ [ ] แทน Array และ { } แทน Hash (หรือ Associative array) จากตัวอย่างถ้าแปลงเป็น JSON จะได้ข้อมูลในรูปของ JSON ดังนี้

[
  {"firstname":"สมชาย", "lastname":"สายเสมอ"},
  {"firstname":"ไม่รู้", "lastname":"ไม่ทราบ"}
]


สำหรับการแปลงกลับเป็นข้อมูล ก็ใช้เพียงคำสั่ง eval() เท่านั้นข้อมูลก็จะกลับมาเป็น Array เช่น

// สมมุติว่า members_data เป็นไปตามตัวอย่างข้างบน
var members = eval('(' +members_data+')');
// เราก็จะได้ members เป็น Array ของข้อมูล
alert(members[0].firstname); //สมชาย



นอกจากนี้ JSON ยังใช้งานกับภาษาอื่นๆ ได้อีกมากมายนะครับ เช่น
    Libraly JSON สำหรับ ภาษา C
    Libraly JSON สำหรับ ภาษา PHP
    หรือ ภาษา อื่นๆ

โค้ดตัวอย่างการใช้งาน JSON

<br />คลิกเพื่อดูข้อมูล ลำดับที่<br />
<input type="button" value="0" onclick="getData(this.value)" />
<br /><input type="button" value="1" onclick="getData(this.value)" />
<script language="Javascript">
var members_data='[{"firstname":"สมชาย", "lastname":"สายเสมอ"},{"firstname":"ไม่รู้", "lastname":"ไม่ทราบ"}]'
function getData(id) {
  
// สมมุติว่า members_data เป็นไปตามตัวอย่างข้างบน
  var members = eval('('+members_data+')');
  
// เราก็จะได้ members เป็น Array ของข้อมูล
  alert("ชื่อ : "+members[id].firstname+" นามสกุล : "+members[id].lastname);
}
</script>

 

AJAX กับปัญหาการ Refresh หน้า

การรีเฟรชหน้า เป็นปัญหาหนึ่งของ AJAX ที AJAX มันไม่สามารถโหลดหน้าเดิมกลับมาได้หากมีการ Refresh หน้าใหม่ พอกด Refresh ทีก็ต้องกลับไปเริ่มต้นที่หน้าแรกที

การแก้ไขก็ทำได้ครับ โดยที่เมื่อไรก็ตามที่มีการเรียกใช้ AJAX เพื่ิอโหลดหน้าใดๆมาแสดง ก็ให้บันทึกหน้านั้นไว้ลง Cookie หรือ Session แล้วแต่ถนัด และอย่าลืมบันทึก query ต่างๆลงไปด้วย หากมีการส่ง parameter ใดๆไปยังเพจที่ถูกเรียก

เมื่อไรก็ตามที่มีการ Refresh หรือ โหลดหน้า ก็เอา ค่าที่เก็บไว้ ส่งให้ AJAX ในครั้งแรกที่โหลด ก็จะทำให้ AJAX ทำการโหลดหน้าเดิมครั้งสุดท้ายที่ปิดไปขึ้นมาตลอดเวลา ดู ตัวอย่าง ลองคลิกเลือกหน้าให้แสดง แล้วลอง Refresh ดูครับ

ผมจะขอ อธิบายเฉพาะส่วนที่เพิ่มเติมจากบทที่แล้วนะครับ โดยอธิบาย เฉพาะส่วนที่เพิ่มเข้ามา คือการเรียกใช้ Javascript ที่เกี่ยวกับ cookie ใครไม่มีก็ตามไป view source เอา หรือไม่ก็ save page ไปเลยก็ได้

function loaddoc(module) {
  var req=Inint_AJAX();
  //แสดง icon คอยการ load ก่อนเลยถ้ามีการเรียกใช้ AJAX
  document.getElementById("rightmodule").innerHTML='<div id="wait"><img src="../images/wait3.gif" alt="" /><br /><br />กำลังโหลด...</div>';
  req.onreadystatechange = function () {
    if (req.readyState==4) {
      if (req.status==200) {
        var data=req.responseText; //รับค่ากลับมา
        document.getElementById("rightmodule").innerHTML=data; //แสดงผล แทนรูปรอโหลด
       
Set_Cookie( 'module' , module ); //บันทึก module ที่เรียก ลง cookie สำหรับการ refresh หน้า


ดูที่ฟังก์ชั่นนี้เลย เมื่อมีการคลิกเลือกเพจ ก็จะไปเรียกฟังก์ชั่น loaddoc มาทำงาน โดยมีการส่ง parameter module มาให้เพื่อจะบอกว่าจะเรียกเพจไหน พร้อมทั้งอาจส่ง query มาด้วยก็ได้ถ้าต้องการ

ในส่วนสีแดง คือการบันทึก module ที่เรียก ลง cookie แบบที่ผมบอก

<body onload="loaddoc('<?php echo ( isset( $_COOKIE[module] ) ) ? $_COOKIE[module] : 'page1.php'?>')"><!-- สำหรับการ refresh หน้า -->


เมื่อทำการโหลดเพจ จะทำการตรวจสอบว่ามีค่าที่บันทึกใน Cookie หรือไม่ ถ้ามี จะไปแสดงหน้าที่เลือกไว้ ( $_COOKIE[module]  ) แต่ถ้าไม่มี ก็จะไปทำการเรียกหน้าหลัก ซึ่งก็คือ page1.php มาแสดง โดยการส่งชื่อหน้าให้กับฟังก์ชั่น loaddoc ตอนโหลดเพจครั้งแรก

โ้ค้ดเต็มๆ คลิกขวาเพื่อ View Source ที่ตัวอย่างเอานะครับ

 

นาฬิกา ด้วย AJAX

การใช้งาน Auto Refresh ของ AJAX โดยการแสดงเวลาจาก Server ครับ เป็นตัวอย่างเพื่อให้เห็นภาพการร้องขอข้อมูลจาก Server ตลอดเวลา

นาฬิกานี้จะเดินแบบ Real Time โดยใช้เวลาจากฝั่ง Server ครับ ในขณะที่ นาฬิกาโดยทั่วไป จะใช้เวลาบนเครื่องของเรา โค้ดแบ่งออกเป็น 2 ไฟล์นะครับ คือ time.php และ index.php เวลาเรียกก็เรียกที่ index.php ครับ

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>นาฬิกา ด้วย AJAX</title>
<meta http-equiv='content-type' content='text/html' charset='windows-874'>
<script language=JavaScript>

var xmlhttp

function Inint_AJAX () {
  var xmlhttp = false;
  try {
    xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
  } catch(e) {
    try {
      xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    } catch(e) {
      xmlhttp = false;
    }
  }

  if(!xmlhttp && document.createElement){
    xmlhttp = new XMLHttpRequest();
  }
  return xmlhttp;
}

function startCallback() {
  if (xmlhttp.readyState == 4) {
    if (xmlhttp.status == 200) {
      document.getElementById("time").innerHTML=xmlhttp.responseText;
//รับค่ากลับมา
      
      delete xmlhttp;
      setTimeout("doStart()", 1000);
    }
  }
}

function doStart() {
  xmlhttp = Inint_AJAX();
  var url = "time.php";
  xmlhttp.open("GET", url, true);
  xmlhttp.onreadystatechange = startCallback;
  xmlhttp.send(null);
}
</script>

</head>
<body>
<div id="time"> </div>
<script language=JavaScript>doStart();</script>
</body>
</html>


หน้า index.php หน้าหลัก และ Javascript สำหรับเรียกใช้ AJAX ไม่มีอะไรมากครับ แค่มีพื้นที่ ที่จะแสดงผลข้อมูลที่ร้องจอมาเท่านั้น

<?
  $hour = +0;
//ปรับให้ตรงตามต้องการ เช่น เป็นค่าบวก หรือค่าลบ เพื่อให้เวลาของ server ตรงกับเวลาจริง
  $min = 0;
//ปรับให้ตรงตามต้องการ
  $Year = date("Y")+543;
  $thaimonth=array("มค.","กพ.","มีค.","เมย.","พค.","มิย.","กค.","สค.","กย.","ตค.", "พย.","ธค.");

  
//วันที่
  $mtoday=date("d ",mktime( date("H")+$hour, date("i")+$min ));
  
//12:36
  $mtime=date("H:i",mktime( date("H")+$hour, date("i")+$min ));
  
//03 ส.ค. 2544
  $mdate=$mtoday. $thaimonth[date("m")-1]." ".$Year;
  
  
//Bust cache in the head
  header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
// Date in the past
  header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
  
//always modified
  header ("Cache-Control: no-cache, must-revalidate");
// HTTP/1.1
  header ("Pragma: no-cache");
// HTTP/1.0
  header("content-type: application/x-javascript; charset=tis-620");
  echo "$mdate $mtime";
?>


หน้า time.php ที่ถูก AJAX เรียก จะอ่านเวลามาแสดงครับ ในทางปฏิบัติ เราสามารถร้องขอข้อมูลอะไรจาก Server ก็ได้ครับ โดยการเปลี่ยนหน้านี้เป็นสิ่งที่ต้องการส่งมาแทน เช่นการ query ข้อมูลออกมาจากฐานข้อมูล

 

clean URL ด้วย mod_rewrite

ข้อมูลสรุปนี้ไม่พร้อมใช้งาน โปรด คลิกที่นี่เพื่อดูโพสต์

การกำหนดอายุของ session

ปกติแล้ว session จะมีระยะเวลาการคงอยู่ช่วงเวลาหนึ่งตามที่กำหนดใน session_cache_expire ที่ php.ini ซึ่งมีค่าปกติเป็น 180 นาที ในบางครั้ง เราอาจต้องการกำหนด อายุของ session ด้วยตัวเอง เช่น การกำหนด ช่วงเวลาการ login ให้สามารถอยู่บนระบบได้แค่ช่วงเวลาหนึ่ง (สั้นๆ) หรือบางครั้งเราอาจต้องการเปิดเพจทิ้งไว้เป็นเวลานานๆ เพื่อไม่ให้ session หมดอายุไปก่อนที่เราจะปิดถึงแม้เราจะม่ทำอะไรก็ตาม เช่น การเฝ้าดูตลาดหุ้น หรือ โปรแกรม chat เป็นต้น

การกำหนดอายุของ session สามารถทำได้หลายวิธีคือ
1. แก้ไขค่านี้ใน php.ini ประมาณนี้

[Session]

; Document expires after n minutes.
session.cache_expire = 180


2. กำหนดค่าใน htaccess

php_value session.cache_expire 3000000


ถ้ายังไม่มีไฟล์ htaccess ให้สร้างไฟล์นี้เปล่าๆ บน server ที่ root ของ website แล้ว ใส่ข้อความด้านบนลงในไฟล์ การกำหนดแบบนี้ จะมีผลเหมือนกับการกำหนด ใน php.ini คือมีผลกับทั้ง Server

3. กำหนดเมือต้องการ ใน php

<?php

/* set the cache limiter to 'private' */

session_cache_limiter('private');
$cache_limiter = session_cache_limiter();

/* set the cache expire to 30 minutes */
session_cache_expire(
30);
$cache_expire = session_cache_expire();

/* start the session */

session_start();

echo "The cache limiter is now set to $cache_limiter<br />";
echo "The cached session pages expire after $cache_expire minutes";
?>

 

Virtual Sub Directory mod_rewrite

Virtual Sub Directory ก็คือการสร้างหรือใช้งาน ไดเร็คทอรี่ แบบที่ไม่ต้องมี (หรือมี) ไดเร็คทอรี่ที่ต้องการก็ได้ ถ้ายังนึกภาพไม่ออก ผมยกตัวอย่างการสร้าง blog โดยมี URL ของ User เป็น http://ez-find.co.cc/user/ ซึ่งวิธีนี้จะเป็นวิธีที่ค่อนข้างง่ายกว่าการใช้งาน Virtual Sub Domain ครับ เนื่องจากไม่ต้องไปยุ่งยากกันกับ Server และสามารถทำได้เอง เพียงแค่ Server สามารถใช้ htaccess ได้

หลักการก็คือ การใช้งาน mod_rewrite ในการแปลง URL จาก

http://ez-find.co.cc/user/

ให้เป็น

http://ez-find.co.cc/index.php?user=user

ซึ่งในกรณีนี้คุณต้องสามารถใช้งาน URL ในรูป http://ez-find.co.cc/index.php?user=user เป็นปกติอยู่ก่อนแล้วนะครับ โดยในขั้นตอนการออกแบบ คุณสามารถออกแบบโดยใช้ URL แบบนี้ในการออกแบบ แล้วค่อยทำการแปลงตอนเสร็จแล้วก็ได้

Options +FollowSymlinks
RewriteEngine on

RewriteBase /

RewriteCond %{HTTP_HOST} ^xxx\.com$
RewriteRule ^([a-z]+)\/(.*)?$ index.php?user= [L,QSA]


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

คุณจะไม่สามารถเรียกใช้ http://ez-find.co.cc/member/ ได้ เนื่องจากมันจะถูกแปลงเป็น http://ez-find.co.cc/index.php?user=member ซึ่งมันจะหากันไม่เจอ การแก้ไข ให้สร้างไฟล์ htaccess เพื่อปิดการทำงาน mod_rewrite ภายใน directory ที่ไม่ต้องการให้มันทำงานนะครับ

Options +FollowSymlinks
RewriteEngine off