Thứ Sáu, 4 tháng 12, 2009

How to Use Flash with PHP

Đây là bài viết chuẩn bị cho topic cùng tên trong PHPDAY .

Có rất nhiều cách giúp Flash client và PHP có thể giao tiếp được với nhau .

Về nguyên tắc flash client có thể sử dụng giao thức TCP/IP  ( và mới đây là Peer-to-Peer )  . Tuy nhiên thông dụng nhất vẫn là qua HTTP . Như vậy mọi mọi kết nối HTTP đều có thể dùng flash để giao tiếp ngon lành :D .

1. Dùng plain text

Tôi sẽ cố gắng load nội dung một file text trên i-php.net ( url của file : http://i-php.net/phpday/example.txt)

Ở đây  tôi minh họa bằng action script 3
var request:URLRequest = new URLRequest("http://i-php.net/phpday/example.txt");
var loader:URLLoader = new URLLoader(request);

// Handler when Loader complete
loader.addEventListener(Event.COMPLETE, completeHandler);

function completeHandler(event:Event):void
{
var loader:URLLoader = URLLoader(event.target);
trace("loaded content: " + loader.data);
}

// output  loaded content: Hello Flash client

Tất nhiên là flash client chẳng quan tâm đến file plain text ( ở đây là http://i-php.net/phpday/example.txt) là file tĩnh hay output của một server side process - server side script cả . Bạn có thể thay thế bằng việc gọi tới một file php script bằng cách thay URL .
var request:URLRequest = new URLRequest("http://i-php.net/about/");

Như vậy đối với flash việc đọc một file trên http server là dễ dàng . Từ việc đọc được một text file ta có thể dùng nhiều cách để giao tiếp với server ( load variable , Json, XML-RPC, SOAP , REST , ...)

2. Dùng load variable

Dùng kỹ thuật này đề load các dữ liệu có định dạng name=value .

Ở actionscript 2 thì chỉ cần gọi hàm loadVariables
Ở actionscript 3 ta sửa đoạn code trên .
var request:URLRequest = new URLRequest("http://i-php.net/phpday/loadme.php");
var loader:URLLoader = new URLLoader(request);
// format result as VARIABLES
loader.dataFormat = URLLoaderDataFormat.VARIABLES


// Handler when Loader complete
loader.addEventListener(Event.COMPLETE, completeHandler);

function completeHandler(event:Event):void
{
var loader:URLLoader = URLLoader(event.target);

if(loader.data is URLVariables)
{
trace(loader.data.user+":"+loader.data.message);

}
}

File loadme.php chỉ đơn giản là echo ra nội dung :

echo 'message=Hello&user=system';
?>

Như vậy loadvar thực chất là định dạng nội dung theo định dang name=value pairs .

Với những dữ liệu đơn giản thì chỉ cần các cách 1 và 2 là đủ . Tuy nhiên với các dạng dữ liệu phức tạp như Object hay Array thì cần những phương pháp serialization . Vậy serialization là gì và tại sao phải serialization ?

Trong các ứng dụng client-server ta muốn send các object qua mạng , mà bản thân các giao thức mạng ( tầng thấp ) đều không hiểu object là gì hết nó chỉ hiểu các bit ( 1001100111 ... ) hoặc cao cấp cỡ HTTP cũng chỉ hiểu text và text . Nên chúng ta cần đưa các object về các dạng nhị phân hoặc text , truyền chúng qua mạng rồi về đến client sẽ dựng lại thành các object . Công việc như vậy gọi là serialization và deserialization .

Như vậy mỗi phương pháp serialization - deserialization khác nhau sẽ tạo ra một giao thức khác nhau SOAP,XML-RPC dùng XML , Json,Yaml dùng các nested text block ,...

Các Text based serialization như SOAP,XML-RPC , Json,Yaml tôi sẽ không đi sâu trong bài viết này .
Mà chỉ chỉ ra nhược điểm lớn nhất của chúng là vấn đề tốc độ truyền tải sẽ rất chậm .
Chậm vì các xml tag của SOAP,XML-RPC vừa thừa, vừa tốn thời gian serialization - deserialization.

Chính vì nhu cầu cần có giao thức có tốc độ truyền và serialization - deserialization nhanh hơn , và tốt hơn cả là binary thay vì text base nên với mỗi ngôn ngữ - công nghệ có các giải pháp khác nhau .
Như Java có RMI
Như .Net có .Net remoting
Python có RPyC
Flash có AMF

Vậy AMF là công nghệ RPC giúp client là Flash/AIR player giao tiếp với server .
Server của AMF có thể là :

Java - BlazeDS, RED 5, Cinnamon, OpenAMF, Pimento, Granite
.NET - WebORB, FluorineFx, AMF.NET
PHP - AMFPHP, SabreAMF, WebORB
Python - PyAMF, Flashticle, amfast, Plasma
Perl - AMF::Perl
Ruby - RubyAMF, WebORB

Nếu kết hợp với các framework phía server thì có các thư viện

Ruby on Rails - RubyAMF
Zend Framework - Zend_AMF
OSGi Framework - AMF3 for OSGi
Django - Django AMF
CakePHP - CakeAMFPHP

3. PHPAMF .
Như vậy PHPAMF chẳng qua chỉ là một thư viện giúp flash client có thể gửi và nhận dữ liệu với server side là php .
PHPAMF có một số đặc điểm
.... ( lười list)
Cụ thể các công việc mà PHPAMF sẽ làm khi nhận được flash client yêu cầu :

* Deserializes the request
* Finds the corresponding remote class
* Instantiates the class
* Performs security checks
* Calls the remote method using the specified arguments
* Serializes the returned data
( Lười dịch -> cần sơ đồ )

4. Cài đặt và Demo .
Only demo , nothing here :D

Thứ Tư, 25 tháng 11, 2009

Tự tạo captcha đơn giản cho ứng dụng của bạn

Bài viết này bao gồm các phần:

- captcha là gì

- captcha được tạo như thế nào

- tiến hành code

- viết thành thư viện để sử dụng lại

1. Captcha là gì?

Một CAPTCHA (ˈkæptʃə, đọc giống như "capture") là một loại kiểm thử dạng hỏi đáp được dùng trong máy tính để xác định xem người dùng có phải là con người hay không. "CAPTCHA" là một dạng sắp đặt chữ đầu của "Completely Automated Public Turing test to tell Computers and Humans Apart" (Phép thử Turing công cộng hoàn toàn tự động để phân biệt máy tính với người), được trường Đại học Carnegie Mellon cố gắng đăng kí thương hiệu nhưng đã bị bác bỏ. Đây là một quá trình một máy tính (máy chủ) yêu cầu một người dùng hoàn tất một kiểm tra đơn giản mà máy tính có thể dễ dàng tạo ra và đánh giá, nhưng không thể tự giải nó được. Vì máy tính không thể giải quyết CAPTCHA, bất kỳ người dùng nào nhập vào lời giải đúng sẽ được xem là con người.

Thuật ngữ CAPTCHA được Luis von Ahn, Manuel Blum, Nicholas J. Hopper (tất cả đều thuộc Đại học Carnegie Mellon), và John Langford (khi đó thuộc IBM) đặt ra vào năm 2000. Một loại CAPTCHA phổ biến yêu cầu người dùng phải nhập các chữ cái trong một tấm hình méo mó, đôi khi cùng với một dãy số hoặc chữ lờ mờ xuất hiện trên màn hình.

Một CAPTCHA đôi khi được mô tả như một phép thử Turing ngược, vì nó được một máy tạo ra và nhắm vào con người, ngược lại với phép thử Turing chuẩn do con người tạo ra và nhắm vào máy.

<nguồn wikipedia>

2. captcha được tạo như thế nào

Đầu tiên ta cần phải ghi ra file ảnhtừ các chuỗi random.

Lưu chuỗi random này vào session.

So sánh chuỗi random trong session với request được gửi lên

Nếu chính xác thì thự hiện tiến trình

Nếu không thì trả về lỗi.

3. code nào

Đầu tiên để có thể ghi 1 string lên image file, tôi đi tìm đọc về thư viện image của php:

http://www.php.net/manual/en/ref.image.php

Có rất nhiều, keyword tôi quan tâm là draw - string - images

Lúc này có 2 sự lựa chọn tôi tìm thấy.1 là có file ảnh sẵn, đọc và ghi và file đó.2 sử dụng 1 file php, gen ra ảnh khi có parameter.

Cách 1 xem chừng khá đơn giản, nhưng chỉ chạy được khi có 1 request. còn nhiều req thì chịu

Cách thứ 2 tôi đã chọn, truyền chuỗi vào nó tự gen ra ngay trên phía client 1 file có header dạng image.

Như vậy tôi có 2 file:

- gen_image.php

- test.php

---> GEN_IMAGE.PHP --->

<?php

// thông báo đây là image type

header ("Content-type: image/png");

$img=ImageCreate(80,30); // quy định kích cỡ của ảnh
$bgcolor=ImageColorAllocate($img,255,255,255); // cho màu nền là màu trắng
$red=ImagecolorAllocate($img,255,0,0); // quy định chữ màu đỏ cho nổi

ImageString($img,10,10,10, $_REQUEST['text'],$red); // add cái text lấy được từ request vào obj image

ImageSetPixel($img,50,50,$red);
ImagePNG($img);
ImageDestroy($img);
?>

Như vậy là xong file gen_image.php. Nếu bạn gõ địa chỉ gen_image.php?text="abcabc", nó sẽ gen ra ảnh png với text trong ảnh là abcabc

Giờ tạo file test nào:

- chúng ta cần 1 hàm cho ra chuỗi random, ở đây tôi mượn hàn gen ra chuỗi mã màu random

function get_random_color()
{
$c='';
for ($i = 0; $i<6; $i++)
{
$c .=  dechex(rand(0,15));
}
return "$c";
}

Giờ đến phần phân tích xem user gõ cái gì vào hay không và so sánh với chuỗi k tự trong session

$captcha = get_random_color();
$captcha_url = '';

if( !isset($_SESSION['dCaptchaContentb']) || !isset($_REQUEST['captcha']))
{
$_SESSION['dCaptchaContentb'] = $captcha;
$captcha_url = '/gen.php?text='.$captcha;
}
else if(isset($_REQUEST['captcha']))
{
if($_SESSION['dCaptchaContentb'] == $_REQUEST['captcha'])
{
//proccess
}
else
{
//noproccess

}
unsset($_SESSION['dCaptchaContentb']);
}

Tạo form ở bên dưới test

<form method='post'>
<img src='<?php echo $captcha_url ?>' />
<input type='text' name='captcha' />
<input type='submit' value='submit' />
</form>

Giờ là lúc test thử xem ok không

4. viết thành thư viện để sử dụng lại

phần này mọi người thực hành xem sao nhé :D

Thứ Tư, 4 tháng 11, 2009

Gởi email text, HTML và tiếng Việt Unicode

HAM MAIL() C?A PHP


Send email trong PHP r?t don gi?n, ta ch? c?n dung duy nh?t 1 ham mail() du?c PHP cung c?p s?n la d?. Cu phap c?a ham mail() nhu sau:


bool mail(string to, string subject, string message[, string additional_headers])


Cac tham s? c?a ham mail() co y nghia nhu sau:



  • to - d?a ch? ngu?i nh?n email, la 1 string. Cac gia tr? h?p l? c?a tham s? to co d?ng nhu sau:
    'user@domain.com'
    'user1@domain.com, user2@domain.com'
    'User Name <user@example.com>'
    'User Name 1 <user1@example.com>, User Name 2 <user2@example.com>'
    'User Name 1 <user@example.com>, user2@domain.com, User Name 3 <user3@example.com>'

  • subject - tieu d? c?a email, la 1 string. Tieu d? c?a email khong du?c ch?a ky t? xu?ng dong (\r ho?c \n).

  • message - n?i dung email, la 1 string. N?i dung email co th? do nhi?u dong ghep l?i v?i nhau, m?i dong du?c phan cach b?ng ky t? \n.

  • additional_headers - (tu? ch?n) dung d? chen them cac header vao email. Cac header nay khong n?m trong ph?n n?i dung c?a email ma dung d? qu?n ly vi?c g?i email (vi d? chen them cac tru?ng CC, BCC khi g?i email). Nhi?u header co th? cung ghep l?i thanh 1 string trong additional_headers, cac header du?c phan cach nhau b?ng chu?i \r\n.

 


Ham mail() s? tr? v? gia tr? TRUE n?u nhu email du?c ch?p nh?n g?i di va FALSE trong tru?ng h?p ngu?c l?i.
Luu y: Ham mail() tr? v? gia tr? TRUE khong co nghia la email s? du?c g?i d?n noi nh?n thanh cong. Gia tr? TRUE du?c tr? v? ch? co y nghia la email du?c server ch?p nh?n g?i di, con khi nao thi email th?c s? du?c g?i, g?i co t?i noi hay khong thi chuong trinh khong bi?t du?c (nhu v?y n?u b?n nh?p sau d?a ch? ngu?i nh?n ? tham s? To thi s? khong co cach nao chuong trinh bi?t du?c d?a ch? To co dung ho?c t?n t?i hay khong!).


M?T VI D? G?I EMAIL V?I HAM MAIL()


Ta hay t?o 1 chuong trinh PHP nh? d? g?i email nhu sau:

//n?i dung file example1.php
<?php
$from = 'from@domain.com';
$to = 'to@domain.com';
$subject = 'Example 1: Send simple text email';
$message = 'A plain text email.';
$header = "From: $from\r\nReply-to: $from";
 
if ( mail($to, $subject, $message, $header) ) {
echo "Email sent to $to!";
} else {
echo "Error occured while sending email to $to!";
} //end if
?>

 


Luu chuong trinh vao file example1.php va ch?y th?. N?u qua trinh g?i email thanh cong, b?n s? nh?n du?c cau thong bao "Email sent to to@domain.com!", n?u co l?i b?n s? nh?n du?c cau thong bao "Error occured while sending email to to@domain.com!"


Luu y:



  • Nh? thay to@domain.com va from@domain.com thanh d?a ch? email c?a b?n tru?c khi ch?y th? chuong trinh!

  • Co th? ph?i m?t t?i 5-10 phut email m?i t?i noi, va b?n nh? ki?m tra thu m?c Bulk email vi nhi?u khi email g?i t?i b? d? trong m?c Bulk.

 


Trong cu phap c?a ham mail(), tham s? additional_headers la tu? ch?n, t?c la b? qua cung du?c. Tuy nhien, tren th?c t? b?n nen cung c?p tham s? additional_headers cho ham mail() v?i it nh?t 2 header From va Reply-to. Ly do thi co nhi?u, m?t trong s? cac ly do ph?i cung c?p header From va Reply-to la vi n?u ph?n d?a ch? ngu?i g?i (From) la r?ng, cac chuong trinh l?c email co th? cho r?ng day la emai spam va th? la email du?c t? d?ng chuy?n sang "Thung rac"!.


G?I HTML EMAIL V?I HAM MAIL()


Chung ta da g?i du?c email text v?i ham mail(), nhung nhi?u luc ta c?n "trang di?m" mau me cho n?i dung email du?c b?t m?t hon. Th? vi?t 1 chuong trinh nh? g?i email HTML:

//n?i dung file example2.php
<?php
$from = 'from@domain.com';
$to = 'to@domain.com';
$subject = 'Example 2: Try a simple HTML email';
$message = 'A HTML email: <b>bold</b>, <i>italic</i>, <u>underline</u>.';
$header = "From: $from\r\nReply-to: $from";
 
if ( mail($to, $subject, $message, $header) ) {
echo "Email sent to $to!";
} else {
echo "Error occured while sending email to $to!";
} //end if
?>

 


Luu chuong trinh vao file example2.php va ch?y th?. Email g?i thanh cong, t?i noi an toan, nhung khi m? ra xem thi n?i dung email l?i nhu v?y:
A HTML email: <b>bold</b>, <i>italic</i>, <u>underline</u>.
Th? co t?c khong?


Th?c ra b?n ch? c?n s?a l?i chuong trinh "1 chut xiu" la dau vao d?y ngay:

//n?i dung file example3.php
<?php
$from = 'from@domain.com';
$to = 'to@domain.com';
$subject = 'Example 3: Send HTML email';
$message = 'A HTML email: <b>bold</b>, <i>italic</i>, <u>underline</u>.';
$header = "Content-type: text/html\r\nFrom: $from\r\nReply-to: $from";
 
if ( mail($to, $subject, $message, $header) ) {
echo "Email sent to $to!";
} else {
echo "Error occured while sending email to $to!";
} //end if
?>

 


Luu chuong trinh vao file example3.php va ch?y th?. L?n nay thi n?i dung email nh?n du?c nhu mong mu?n:
A HTML email: bold, italic, underline..


Nhu v?y b?n s? nh?n th?y r?ng g?i HTML email cung don gi?n khong khac gi g?i text email thong thu?ng. Ch? c?n them 1 header Content-type: text/html la n?i dung email s? du?c hi?u la HTML ngay.


Luu y: Rieng ph?n tieu d? (subject) c?a email v?n ph?i la text thong thu?ng! B?n khong th? s? d?ng ma HTML trong ph?n tieu d? (subject) c?a email du?c. Vi th?c ch?t ph?n tieu d? c?a email cung la 1 header d?t bi?c ch? khong n?m trong ph?n n?i dung chinh c?a email.


G?I EMAIL V?I TI?NG VI?T UNICODE


G?i email ti?ng Vi?t Unicode cung y chang nhu g?i email HTML vi b?n than HTML da h? tr? Unicode r?i, ta ch? c?n chu y d?t charset c?a email cho dung la du?c:

//n?i dung file example3.php
<?php
$from = 'from@domain.com';
$to = 'to@domain.com';
$subject = 'Example 4: Send Unicode email';
$message = 'Email ti?ng Vi?t Unicode: <b>in d?m</b>, <i>in nghieng</i>, <u>g?ch chan</u>.';
$header = "Content-type: text/html; charset=utf-8\r\nFrom: $from\r\nReply-to: $from";
 
if ( mail($to, $subject, $message, $header) ) {
echo "Email sent to $to!";
} else {
echo "Error occured while sending email to $to!";
} //end if
?>

 


Luu chuong trinh vao file example4.php va ch?y th?: email g?i thanh cong, t?i noi an toan va khi d?c thi hi?n th?...ti?ng ?-r?p!!! Co gi sai ? day chang?


Th?c ra khong co gi ph?i lo l?ng c?. Khi g?i email ti?ng Vi?t Unicode b?n c?n chu y m?t s? di?m sau:



  • D?t charset cho email. Charset nay ph?i nen trung v?i charset c?a file ma ngu?n PHP va website c?a b?n. Trong vi d? ? tren, ta d?t charset cho email la utf-8 thi b?n cung ph?i luu file example4.php len dia v?i charset la utf-8. B?n xem m?c "LUU FILE V?I TI?NG VI?T UNICODE" ? bai vi?t Gi?i thi?u - Cac bu?c chu?n b? c?n thi?t d? tim hi?u them v? luu file ma ngu?n PHP len dia v?i charset utf-8.

  • Cho du b?n da d?t charset dung r?i, v?n co th? email khong hi?n th? dung ti?ng Vi?t khi d?c! Vi quy?n hi?n th? email nhu th? nao la do chuong trinh email client quy?t d?nh. N?u b?n d?c email b?ng Outlook ch?ng h?n, thi Outlook s? t? d?ng nh?n bi?t charset c?a email va hi?n th? dung ti?ng Vi?t. N?u b?n d?c email tren web (nhu Yahoo, Hotmail...) thi co th? b?n ph?i t? tay ch?n l?i Encoding la utf-8 tren trinh duy?t vi cac web email nhu Yahoo, Hotmail s? dung charset m?c d?nh c?a minh va b? qua charset du?c thi?t l?p trong email.

Va tuong t? nhu khi g?i HTML email, b?n d?ng nen ghi ti?ng Vi?t vao ph?n tieu d? (subject) c?a email! Vi nhu da noi ? ph?n tru?c, tieu d? (subject) c?a email cung la 1 header d?t bi?c ch? khong n?m trong ph?n n?i dung chinh c?a email.


 


M?T S? L?I HAY G?P V?I HAM MAIL()


Email g?i khong t?i noi
Ham mail() tr? v? gia tr? TRUE, d?a ch? dung, n?i dung dung, noi chung m?i th? d?u dung nhung email ch? hoai khong th?y t?i! Ki?m tra Bulk email cung khong th?y luon! L?i ? dau he? Nguyen nhan co th? x?y ra ? 3 ch?:



  • mail server - server c?a b?n khong cho phep account c?a b?n g?i email, ho?c gi?i h?n ch? cho phep g?i s? lu?ng gi?i h?n email trong 1 kho?ng th?i gian nao do. B?n c?n h?i ngu?i qu?n ly server c?a b?n v? quy?n g?i email v?i PHP tren server.
    N?u v?n d? khong ph?i n?m ? ch? server khong cho phep b?n g?i email, ho?c chinh b?n la ngu?i qu?n ly server thi b?n ki?m tra ti?p 1 trong 2 nguyen nhan sau:

  • *NIX server (server ch?y cac h? di?u hanh UNIX ho?c Linux) - PHP m?c d?nh s? s? d?ng l?nh sendmail co s?n tren h? th?ng d? g?i email (v?i tham s? -t -i). M?c d?nh l?nh sendmail s? n?m trong /usr/sbin/sendmail ho?c trong 1 thu m?c nao do trong PATH c?a h? th?ng. N?u tren server c?a b?n l?nh sendmail n?m ? ch? khac v?i thu m?c m?c d?nh (vi d? tren server c?a b?n sendmail n?m ? /usr/local/secretbin/sendmail) thi b?n co th? lam nhu sau:
    - Tim va m? file php.ini ra.
    - Tim chu?i "sendmail", b?n s? th?y 2 dong tuong t? nhu sau:
    ; For Unix only. You may supply arguments as well (default: "sendmail -t -i").
    ;sendmail_path =

    - B?n s?a l?i 2 dong do nhu sau:
    ; For Unix only. You may supply arguments as well (default: "sendmail -t -i").
    sendmail_path = /usr/local/secretbin/sendmail -t -i

    Nh? b? ky t? ch?m ph?y (;) ? d?u dong sendmail_path =!
    Luu y: C?u hinh c?a PHP t?i day da dung va d? d? g?i email tren server *NIX. Tuy nhien v?n co th? server khong g?i email du?c! L?i luc nay la do b?n than c?u hinh c?a server ho?c qua trinh cai d?t va c?u hinh chuong trinh sendmail b? l?i. Cach ki?m tra nguyen nhan va s?a l?i n?m ngoai ph?m vi c?a PHP, b?n co th? d?t cau h?i len di?n dan CLB ngu?i s? d?ng Linux d? du?c giup d?!

  • Windows server - Tren Windows, PHP c?n ph?i dung 1 SMTP server d? g?i email. B?n tim va m? file php.ini ra, tim chu?i sendmail, g?n do b?n s? th?y vai dong nhu sau:
    [mail function]
    ; For Win32 only.
    SMTP = localhost
    smtp_port = 25;

    Cac dong tren cho ta bi?t PHP s? dung SMTP server localhost tren port 25 d? g?i email. R?t co th? b?n chua cai d?t va c?u hinh dung 1 SMTP tren localhost d? PHP co th? s? d?ng va g?i email. B?n hay tham kh?o bai vi?t nay d? cai d?t 1 SMTP server tren localhost va dung no d? g?i email v?i PHP.

 


N?i dung email b? d?t do?n
N?u b?n nh?n du?c email nhung n?i dung b? d?t do?n khong d?y d? thi co th? do 2 nguyen nhan sau:



  • Ma HTML trong email b? sai - N?u b?n g?i email HTML thi b?n nen chu y ki?m tra cu phap HTML c?a n?i dung email. Gi? s? b?n d?nh g?i email v?i n?i dung:
    <b>in d?m</b>
    Nhung ch?ng may b?n ghi sai thanh <b in d?m</b>
    thi khi d?c, email s? hi?n th? b? sai (co th? la m?t ch?, d?t do?n, v.v...).

  • Co 1 dong ch?a 1 d?u ch?m (.) ? d?u - Khi b?n g?i email tren Windows dung SMTP server, n?u n?i dung email co 1 dong nao do ch?a 1 d?u ch?m (ky t? .) ? d?u dong thi ky t? do s? b? b? qua, dong do s? b? b? qua, ho?c toan b? n?i dung email t? dong do tr? di s? b? b? qua. Ly do la vi dong ch?a 1 d?u ch?m ? d?u chinh la d?u hi?u bao cho SMTP server bi?t da k?t thuc n?i dung c?a email. D? kh?c ph?c, tru?c khi g?i email, ta thay th? d?u ch?m ? d?u dong b?ng 2 d?u ch?m:
    $message = str_replace("\n.", "\n..", $message);

 


CAC HAM PHP DU?C DUNG TRONG VI D?



TAI LI?U THAM KH?O



( Trich t?i diendantinhoc.net. Tham kh?o bai g?c  G?i email text, HTML va ti?ng Vi?t Unicode )

men who want to have a babyplanning for baby How do you get pregnant can you get pregnant right after having a babyhaving a baby at 16

Kinh nghiệm Rewrite URL ( PHP + Apache + Unix - linux host)

Rewrite URL như thế nào ?

Có bạn hỏi làm sao tạo được các đường dẫn đẹp (URL Rewrite) như các trang trên mạng. Mình cũng tìm hiểu qua và xung phong viết 1 bài về nó vậy. Trước tiên chúng ta tìm hiểu cơ chế rewite:Rewrite Engine là một phần dịch vụ của Webserver được dùng để thay đổi URL(đường dẫn trên trình duyệt) sang một dạng khác với nhiều mục đích khác nhau.

Kỹ thuật được nói đến là URL rewriting và nó đem lại những tiện lợi sau:- Làm cho URL trở nên thân thiện với người dùng cũng như dễ dàng với các Search Engine (bộ máy tìm kiếm)- Tránh lộ các đường link quan trọng- Tránh lộ các công việc bên trong trước người dùng

Bản chất của việc rewrite này các bạn có thể hình dung như sau: khi bạn gõ 1 đường link lên trình duyệt như sau: http://diachitrangweb.com/news/2007/13/01 thì đây là đường dẫn ảo, và khi request đến Webserver nó sẽ đổi lại thành đường dẫn thật như sau: http://diachitrangweb.com/index.php?...ay=13&month=01 << có thể là như thế này vì có nhiều cách rewrite.

Đối với Server Apache: để thực hiện được URL Rewriting bạn làm các bước sau:

1. Kích hoạt mod mod_rewrite có sẵn trong Apache bẳng cách sửa trong file httpd.conf, bạn Find đến dòng chưa rewrite_module rồi bỏ dấu # (nếu có) ở đầu đi. Sau đó restart Apache. Nếu bạn dùng các host trên internet thì có thể đã có sẵn rồi.

2. Tạo 1 file .htacces có nội dung như sau:
Đầu tiên bật Rewrite Engine:
RewriteEngine on
Options +FollowSymlinks
RewriteBase /

Tiếp đến là viết cú pháp RewriteRule:
RewriteRule ^Virtual_Path Real_Path

Ví dụ:
RewriteRule ^topic_([0-9]*).html index.php?topic=$1
ví dụ: topic_1.html thành index.php?topic=1

RewriteRule ^article/([0-9]*)/page/([0-9]*) index.php?article=$1&page=$2
ví dụ: article/1/page/2 thành index.php?article=1&page=2

Cú pháp để viết các Rule này giống như cách viết của biểu thức chính quy Regular Expression. ví dụ như sau:

(.*) nhận tất cả các giá trị.
([0-9]*) chỉ nhận các giá trị là số, từ 0-9.
([a-zA-Z]*) chỉ nhận các giá trị là chữ cái, từ a-z và A-Z.

3. Sau khi tạo được file htaccess bạn copy nó vào thư mục gốc của web của bạn là có thể chạy được.

Đối với Server IIS: các bạn download gói cần thiết về để có thể thực hiện được việc rewrite, các bạn có thể download từ 1 số trang sau:

http://www.micronovae.com/ModRewrite/ModRewrite.html
http://www.qwerksoft.com/products/iisrewrite/
http://www.isapirewrite.com/
http://www.motobit.com/help/url-repl...od-rewrite.asp

Ngoài việc sử dụng mod url_rewrite như trên thì nếu host của bạn ko có kích hoạt mod này hoặc bạn ko có quyền để cấu hình nó như trên. Để đơn giản các bạn có thể tạo ra những cách khác nhau để làm cho URL trở nên đẹp và thân thiện hơn. Dưới đây là 1 số cách khác nhau.
c1 dạng như sau: http://vidu.com/index.php/news/2007/13/01 << Trông rất giống với kiểu rewrite ở trên nhưng nó khác ở chỗ nó là đường dẫn thật còn url rewrite là đường dẫn ảo. Đường dân này hiểu như là 1 request đến file index.php với Query String (Xâu truy vấn) là /news/2007/13/01, các bạn tách xâu này ra rồi sử dụng theo mục đích của mình. Cách này đang được trang web 24h.com.vn sử dụng.
c2 dạng như sau: http://vidu.com/index.php/news_2007_13_01.html << Gần giống cách 1 ở trên nhưng đường dẫn khác thân thiện với đuôi html, dễ dàng cho các search engine (máy tìm kiếm như Google, Yahoo) tìm kiếm nội dung.
c3 có thể viết như sau: http://vidu.com/index.php?q=news/2007/13/01 << cũng gần giống cách 1 nhưng nó rõ ràng hơn, nó được dùng trong FrameWork Drupal của PHP.
Và có thể có nhiều cách khác nhau các bạn có thể tự nghĩ ra. Hoặc có thể dùng cách mã hoá xâu truy vấn chẳng hạn.

Xem bài gốc tại http://diendan.thegioiwebsite.net/showthread.php?t=41

Thứ Năm, 29 tháng 10, 2009

7 khả năng phát sinh lỗi bảo mật khi code PHP

PHP đem đến sự linh động, tiện dụng và đôi khi là tùy tiện. Điều đó dẫn đến một số các quy tắc bảo mật căn bản sau có thể bị bỏ qua

Kiểm tra dữ liệu đầu vào

Đây là vấn đề cơ bản của căn bản, tránh việc chèn mã độc và giảm tải kha khá cho server khi không phải xử lý dữ liệu không mong muốn.

Hạn chế truy cập

Đối với các trang cho phép những thao tác can thiệp vào website ở các khía cạnh giao diện, hệ thống, db hay bất cứ cấu hình nào thì luôn phải được đảm bảo mức độ an toàn cao nhất. Cơ bản của căn bản nữa là phải kiểm tra bất cứ request nào của người dùng, thay vì chỉ phân quyền đơn giản.

Hạn chế sử dụng session ID đối với các dữ liệu nhạy cảm

Ví dụ như số thẻ tín dụng hay các thông tin cá nhân, đổi mật khẩu ... việc chỉ kiểm tra sessionID mới là xác thực vòng ngoài thôi. Không nên đặt niềm tin quá vào nó.

SQL injections

Sự tiện lợi của PHP đem đến cho người phát triển khả năng tương tác database nhanh chóng, dễ dàng. Do đó, sự cẩu thả của người viết code khi để lạc các ký tự 'không sạch' vào câu query sẽ dẫn đến hậu quả khôn lường. Các framework hầu hết loại bỏ khả năng này, và nó cũng không còn phổ biến, nhưng vẫn xuất hiện nhiều nếu không cẩn thận.

Thông báo lỗi hệ thống

Nếu vì lý do gì đó mà website của bạn dừng hoạt động, hãy đảm bảo là các thông báo cho người dùng sẽ không thể hiện những thông tin nhạy cảm như connection error, db, webserver hay nặng nhất là câu query db. Hãy chắc chắn có một câu thông báo chuẩn cho toàn bộ website khi đi vào vận hành.

Xử lý dữ liệu nhận từ phía người dùng

Hãy đảm bảo đó là những dữ liệu 'sạch' và có ý nghĩa, nếu không sẽ dẫn đến nhiều vấn đề ở trên.

Cấu hình

Nếu có quyền truy cập, hãy xác lập các thông số của PHP & webserver đảm bảo an toàn, hiệu quả & tối ưu.

nguồn: http://articles.sitepoint.com/article/php-security-blunders/2    (nhớ vào đọc cho có cả vd rõ ràng)

Thứ Tư, 28 tháng 10, 2009

Sử dụng plugin chat trong cakephp 1.2

Xin chào các bạn!

Đây là môt plugin do tôi tự viết dựa trên các tính năng chat của livechat. Chương trình livechat tôi tham khảo được viết bằng php, để có thể quản trị được các chức năng tôi thấy có nhiều cái thừa  không cần thiết trong trường hợp của tôi. Tôi đã dựa vào livechat để viết plugin với tính năng tương tự. Plugin này có sử dụng jquery.

Các chức năng chính:

1)  Hiển thị danh sách người chat và danh sách người quản trị đang chat. Tôi tạm gọi là guests và operators.

2) Guest chỉ việc nhập tên và email, sau đó sẽ hiển thị màn hình chat. Operators sẽ thấy trạng thái chát của guest và bắt đầu chat. Một guest có thể do nhiều operators chat.

3) Operators sử dụng luôn bảng users.

3) Các chức năng hoặc động trong cửa sổ window riêng biệt (popup window).

Để sử dụng các bạn download plugin tại đây. (Để hểu rõ hơn về plugin bạn có thể tham khảo tại đây)

Cài đặt:

1) Đưa toàn bộ nội dung của plugin chat vào trong app/plugin

2) Bạn chạy file sqlChat trong thu mục app/plugins/chat/config/sql .

3) Copy file chat.ctp trong thu muc app/plugins/chat/views/layout vào trong thu mục app/views/layout.

Sử dụng:

Do các chức năng chat đểu hiển thị ra các cửa sổ riêng biệt. Do vậy ta chỉ việc tạo ra link gọi đến là ok.

Ví dụ:
<?php
//Hiển thị link để guest mở cửa sổ chat với admin
echo $html->link('Chat with Amdmin', '/chat/chats/form_guest', array('onclick' => "window.open('{$html->url('/chat/chats/form_guest')}','mywin','left=20,top=20,width=460,height=440,toolbar=0,resizable=0'); return false;"));
echo '<br />';
//Hiển thị link quản trị chat
echo $html->link('Manager chatting', '/chat/chats/chat_users', array('onclick' => "window.open('{$html->url('/chat/chats/chat_users')}','mywin','left=20,top=20,width=460,height=440,toolbar=0,resizable=0'); return false;"));
?>

Vậy là xong, chúc các bạn vui vẻ :D

Chủ Nhật, 18 tháng 10, 2009

Upload ảnh có đóng dấu bản quyền - cakephp 1.2

Đóng dấu cho ảnh thật sự cần thiết khi chúng ta muốn giữ bản quyền cho ảnh đó. Bài viết này sẽ hướng dẫn mọi người làm việc đó một cách dễ dàng. Bắt dầu nào :
Đầu tiên là tạo cơ sở dữ liệu :

CREATE TABLE `images` (
`id` INT( 4 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`images` VARCHAR( 255 ) NOT NULL
)

Vậy là xong bước đầu tiên. Tiếp đến chúng ta sẽ tạo controller / model / views

Đầu tiên là controller : app/controllers/images_controller.php:

<?php
class ImagesController extends AppController
{
var $name = 'Images';
var $components = array('Upload');

function add()
{
if(! empty ($this->data))
{
$this->Image->create ();
if($this->Upload->upload ($this->data['Image']['image'], WWW_ROOT . 'img' . DS))
{
$this->data['Image']['images'] = $this->data['Image']['image']['name'];
}
if($this->Image->save ($this->data))
{
$this->Session->setFlash (__ ('The Image has been saved', true));
$this->redirect ($this->referer());
}else
{
$this->Session->setFlash (__ ('The Image could not be saved. Please, try again.', true));
}
}
}
}
?>

Tiếp đến là model : app/models/image.php

<?php
class Image extends AppModel {
var $name = 'Image';
}
?>

Cuối cùng là views : app/views/images/add.ctp

<div class="images form">
<?php $session->flash();?>
<?php echo $form->create('Image', array('type' => 'file')); ?>
<fieldset>
<legend><?php __('Add image');?></legend>
<div class="group">
<div><?php __('Image');?></div>
<div><?php echo $form->file('image',array('label'=>'',)); ?></div>
</div>
</fieldset>
<?php echo $form->end('add');?>
</div>

Để có thể upload được ảnh ta sẽ sử dụng components. Ở đây ta sẽ tạo 1 file có tên là upload.php trong components

app/controllers/components/upload.php

<?php
class UploadComponent extends Object {
function upload(&$file, $dir) {
$return = false;
// current time in miliseconds
$time = microtime ( 1 ) * 1000;
$file['name']=md5($time).$file['name'];

if(@move_uploaded_file($file['tmp_name'],$dir.$file['name']))
{
//Dòng này là ảnh sẽ được upload
$main_img         = $dir.$file['name']; // main big photo / picture

//Dòng này là ảnh sẽ đóng dấu lên ảnh được upload
$watermark_img    = "watermark.gif"; // use GIF or PNG, JPEG has no tranparency support
$padding         = 3; // distance to border in pixels for watermark image
$opacity        = 100;    // image opacity for transparent watermark

$watermark     = imagecreatefromgif($dir.$watermark_img); // create watermark
$image         = imagecreatefromjpeg($main_img); // create main graphic

if(!$image || !$watermark) die("Error: main image or watermark could not be loaded!");

$watermark_size     = getimagesize($dir.$watermark_img);
$watermark_width     = $watermark_size[0];
$watermark_height     = $watermark_size[1];

$image_size     = getimagesize($main_img);
$dest_x         = $image_size[0] - $watermark_width - $padding;
$dest_y         = $image_size[1] - $watermark_height - $padding;

// copy watermark on main image
imagecopymerge($image, $watermark, $dest_x, $dest_y, 0, 0, $watermark_width, $watermark_height, $opacity);

// print image to screen
header("content-type: image/jpeg");
imagejpeg($image);
imagedestroy($image);
imagedestroy($watermark);
$return = true;
}
return $return;
}
}
?>


file ảnh watemark.gif được đặt trong thư mục : app/webroot/img/watermark.gif.

Muốn cho ảnh watermark.gif mờ đi thì ta chỉ việc chỉnh độ opacity là được.

Bạn có thể download file ảnh watermark.gif tại đây

Thứ Bảy, 17 tháng 10, 2009

Sử dụng plugin Paypal IPN trong CakePHP

Xin chào mọi người!

Plugin paypal IPN này thật sự cần thiết cho những ai muốn sử dụng Paypal IPN trong cakephp. Tôi đã tìm kiếm trên mạng và sử dụng plugin này, thấy thật sự mang lại tiện ích rất lớn. Helper trong plugin sẽ giúp ta dẽ dàng tạo ra các nút Checkout, Add to Cart, Subscribe, và Donate một cách dễ dàng. Chức năng chính của plugin này là tạo ra các nút add to cart, subscribe ... trong paypal để gửi thông tin lên paypal, thực hiện giao dịch và lưu trữ dữ liệu giao dịch trả về vào trong log và CSDL. (Cách sử dụng plugin bạn tham khảo tại đây).

Paypal IPN plugin. (Paypal Instant Payment Notification)
Version 1.4
Tác giả: Nick Baker (nick@webtechnick.com)

Website: http://www.webtechnick.com

Browse, Download, hoặc  Checkout Plugin.
Browse: http://projects.webtechnick.com/paypal_ipn
Download: http://projects.webtechnick.com/paypal_ipn.tar.gz
SVN: https://svn2.xp-dev.com/svn/nurvzy-paypal-ipn

Các bước cài đặt như sau:

1) Copy plugin vào trong project /app/plugins/paypal_ipn.

2) Import file /plugins/paypal_ipn/paypal_ipn.sql vào trong cơ sở dữ liệu.

3) Thêm những dòng dưới đây vào router: /app/config/routes.php fil
<?php
/* Paypal IPN plugin */
Router::connect('/paypal_ipn/process', array('plugin' => 'paypal_ipn', 'controller' => 'instant_payment_notifications', 'action' => 'process'));

/* Optional Routes, but nice for administration */
Router::connect('/paypal_ipn/edit/:id', array('admin' => true, 'plugin' => 'paypal_ipn', 'controller' => 'instant_payment_notifications', 'action' => 'edit'), array('id' => '[a-zA-Z0-9\-]+', 'pass' => array('id')));
Router::connect('/paypal_ipn/view/:id', array('admin' => true, 'plugin' => 'paypal_ipn', 'controller' => 'instant_payment_notifications', 'action' => 'view'), array('id' => '[a-zA-Z0-9\-]+', 'pass' => array('id')));
Router::connect('/paypal_ipn/delete/:id', array('admin' => true, 'plugin' => 'paypal_ipn', 'controller' => 'instant_payment_notifications', 'action' => 'delete'), array('id' => '[a-zA-Z0-9\-]+', 'pass' => array('id')));
Router::connect('/paypal_ipn/add', array('admin' => true, 'plugin' => 'paypal_ipn', 'controller' => 'instant_payment_notifications', 'action' => 'edit'));
Router::connect('/paypal_ipn', array('admin' => true, 'plugin' => 'paypal_ipn', 'controller' => 'instant_payment_notifications', 'action' => 'index'));/*
/* End Paypal IPN plugin */
?>

Router này sẽ chuyển cách gọi các controller và action trong plugin này về cách gọi thông thường. (nhìn code bạn sẽ hiểu ngay !^_^! )

Tạo tài khoản paypal:

Để sự dụng được plugin này bạn phải có một tài khoản paypal (tham khảo cách tạo tài khoản paypal tại đây). Với các lập trình viên, paypal có hỗ trợ cho việc tạo tài khoản ảo để test, địa chỉ https://developer.paypal.com. Khi tạo xong tài khoản, bật (enable) IPN trong tài khoản của bạn.

Sử dụng trong administator (tùy chọn): đây là trường hợp bạn thêm và lưu thông tin thông qua giao diện admin

1) Bạn phải đăng nhập vào trong phần quản trị với tài khoản administrator thông qua component Auth.

2) Sử dụng plugin tại http://www.yoursite.com/paypal_ipn

Sự dụng helper paypal (tùy chọn): Trong trường hợp bạn muốn sử dụng helper hoặc các button trong helper.

1) Cấu hình lại với thông tin của bạn tại /paypal_ipn/config/paypal_ipn_config.php

2) Thêm 'PaypalIpn.Paypal' vào trong danh sách helper của app_controller.php:
<?php
var $helpers = array('Html','Form','PaypalIpn.Paypal');
?>

3) cách sử dụng (tham khảo thêm tại /paypal_ipn/views/helpers/paypal.php)

$paypal->button(String tittle, Options array);

ví dụ:
<?php
//Pay Now Button
echo $paypal->button('Pay Now', array('amount' => '12.00', 'item_name' => 'test item'));
//Pay Now Button with Image
echo $paypal->button('pay_now.jpg', array('amount' => '12.00', 'item_name' => 'test item'));

//Subscribe Button
echo $paypal->button('Subscribe', array('type' => 'subscribe', 'amount' => '60.00', 'term' => 'month', 'period' => '2'));

//Donate Button
echo $paypal->button('Donate', array('type' => 'donate', 'amount' => '60.00'));

//Add To Cart
echo $paypal->button('Add To Cart', array('type' => 'addtocart', 'amount' => '15.00'));
?>

Ta cũng có thể thêm một số thuộc tính Paypal hợp lệ vào trong options của button.

Ví dụ :
<?php echo $paypal->button('Pay Now', array('amount' => '12.00', 'item_name' => 'Stuff', 'return' => 'http://www.yoursite.com/thankyou')); ?>

Ngoài việc sử dụng các helper button đẻ tạo ra các button paypal ta còn có thể tạo ra thông các các thẻ html. Khi sử dụng thẻ form html ta phải sử dụng notify_url để gán tới http://www.yoursite.com/paypal_ipn/process
ví dụ:
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
...
...
<input type="hidden" name="notify_url" value="http://www.yoursite.com/paypal_ipn/process" />
...
</form>

Khi thông tin giao dịch được trả về từ paypal, dữ liệu sẽ được lưu vào trong cơ sở dữ liệu và hàm afterPaypalNotification sẽ được gọi (nếu nó tồn tại). Đây sẽ là nơi bạn xử lý các thao tác login khác liên quan đến giao dịch sau khi giao dịch thành công.

Tạo ra function trong /app/app_controller.php như sau:
<?php
function afterPaypalNotification($txnId){
//Here is where you can implement code to apply the transaction to your app.
//for example, you could now mark an order as paid, a subscription, or give the user premium access.
//retrieve the transaction using the txnId passed and apply whatever logic your site needs.

$transaction = ClassRegistry::init('PaypalIpn.InstantPaymentNotification')->findById($txnId);
$this->log($transaction['InstantPaymentNotification']['id'], 'paypal');

//Tip: be sure to check the payment_status is complete because failure transactions
// are also saved to your database for review.

if($transaction['InstantPaymentNotification']['payment_status'] == 'Completed'){
//Yay! We have monies!
}
else {
//Oh no, better look at this transaction to determine what to do; like email a decline letter.
}
}
?>

Chú ý:

1) Với các bạn chưa lần nào làm về paypal, các bạn có thể tìm hiểu qua về cách tạo một trang web trực tuyển qua paypal một cách đơn giản tại đây. Sau khi làm xong ví dụ này, tôi nghĩ các bạn sẽ hiểu rõ hơn nguyên tắc hoặt động của plugin này.

2) Plugin này hiện tại (version 2.1) theo tôi được biết thì chỉ có hỗ trợ 2 button chính là Paynow và Subscribe. Còn các nút AddToCart... thì chưa hỗ trợ việc lưu dữ liệu. Hi vọng khi các bạn sử dụng thì đã hỗ trợ đủ.

Chúc các bạn thành công  !^_^!

Chủ Nhật, 30 tháng 8, 2009

Note Config Apache

Cấu hình cho Apache hiển thị file Gzip .

- Cài module mod_defalte.so vào thư mục .../apache2.2/modules

- Sửa file .../apache2/conf/httpd.conf enable mod_deflate.so
LoadModule deflate_module modules/mod_deflate.so

- Add MultiViews to Options:
Options Indexes FollowSymLinks MultiViews

- Uncomment AddEncoding:
AddEncoding x-compress .Z
AddEncoding x-gzip .gz .tgz
- Comment AddType:
#AddType application/x-compress .Z
#AddType application/x-gzip .gz .tgz

- Để hiển thị file Gzip dưới dạng xml thêm dòng :
AddType text/xml .gz .tgz

- Khởi động lại Apache:
.../httpd restart

Thứ Ba, 25 tháng 8, 2009

So sánh cách lấy dữ liệu tự động và lấy theo query trong cakephp

I. So sánh


Trong cakephp, có 2 cách lấy dữ liệu chính là lấy dự liệu tự động thông qua các hàm viết sẵn của cakephp và lấy dữ liệu từ câu lệnh query trực tiếp.


Ưu nhược điểm của 2 phương pháp trên:


1. Lấy dữ liệu tự động


a) Ưu điểm


- Lấy dữ liệu từ các bảng sẽ được thực hiện tự động thông qua khai báo quan hệ ở model


- Việc thêm quan hệ hoặc thay đổi quan hệ giữa các bảng sẽ được thực hiện ở model, vì vậy khi quan hệ với bảng khác hoặc thay đổi dữ liệu chỉ cần thay đổi quan hệ ở model.


- Dễ dàng hơn trong việc phân trang, phân trang tìm kiếm.


- Dữ liệu lấy ra đã được đưa theo cấu trúc mảng hình cây hợp lý, làm cho việc hiển thị dữ liệu trở lên đơn giản và dễ dàng hơn.


b) Nhược điểm


- Việc lấy dữ liệu sẽ trở lên vô cùng nhiều và chậm do lấy dữ liệu từ tẩt cả các bảng quan hệ nếu không sử dụng hợp lý recursive và bindModel (cách dùng sẽ có ở dưới).


c) Định dạng dữ liệu lấy ra


Dữ liệu lấy ra sẽ được hiển thị theo nhiều định dang, tùy theo từng mối quan hệ là một – một, một nhiều hay nhiều nhiều.


- Với quan hệ một - một:



Array

(

    [User] => Array

        (

            [id] => 121

            [name] => Gwoo the Kungwoo

            [created] => 2007-05-01 10:31:01

        )

    [Profile] => Array

        (

            [id] => 12

            [user_id] => 121

            [skill] => Baking Cakes

            [created] => 2007-05-01 10:31:01

        )

)


- Với quan hệ một nhiều:



Array

(  

    [User] => Array

        (

            [id] => 121

            [name] => Gwoo the Kungwoo

            [created] => 2007-05-01 10:31:01

        )

    [Comment] => Array

        (

            [0] => Array

                (

                    [id] => 123

                    [user_id] => 121

                    [title] => On Gwoo the Kungwoo

                    [body] => The Kungwooness is not so Gwooish

                    [created] => 2006-05-01 10:31:01

                )

            [1] => Array

                (

                    [id] => 124

                    [user_id] => 121

                    [title] => More on Gwoo

                    [body] => But what of the ‘Nut?

                    [created] => 2006-05-01 10:41:01

                )

        )

)


- Quan hệ nhiều – một



Array

(

   [Profile] => Array

        (

            [id] => 12

            [user_id] => 121

            [skill] => Baking Cakes

            [created] => 2007-05-01 10:31:01

        )    

    [User] => Array

        (

            [id] => 121

            [name] => Gwoo the Kungwoo

            [created] => 2007-05-01 10:31:01

        )

)

- Quan hệ nhiều nhiều
Array

(  

    [Recipe] => Array

        (

            [id] => 2745

            [name] => Chocolate Frosted Sugar Bombs

            [created] => 2007-05-01 10:31:01

            [user_id] => 2346

        )

    [Tag] => Array

        (

            [0] => Array

                (

                    [id] => 123

                    [name] => Breakfast

                )

           [1] => Array

                (

                    [id] => 124

                    [name] => Dessert

                )

           [2] => Array

                (

                    [id] => 125

                    [name] => Heart Disease

                )

        )

)


2. Lấy dữ liệu từ câu lệnh query


a) Ưu điểm


- Việc lấy dữ liệu sẽ không còn phụ thuộc vào quan hệ ở model, mà chỉ phụ thuộc vào quan hệ khi khai báo ở câu query


- Việc lấy dữ liệu sẽ thực hiện nhanh hơn, liên kết giữa các bảng sẽ rõ ràng hơn dựa vào câu lệnh liên kết ở query.


b) Nhược điểm


- Khi thay đổi quan hệ giữa các bảng, hoặc thêm quan hệ với một bảng mới, phải sửa lại câu query.


- Việc phân trang sẽ trở nên khó khăn phức tạp hơn


- Dữ liệu lấy ra dưới dạng mảng, nhưng chưa được sắp xếp lại theo cấu trúc.


- Khi sử dụng câu lệnh query, ta phải hiểu rất rõ quan hệ và sử dụng thành thao các lệnh trong query


c) Định dạng dữ liệu lấy ra


Khi lấy dữ liệu thông qua câu lệnh query, thì với tất cả các quan hệ dữ liệu dữ liệu lấy ra từ câu lệnh query đểu có định dạng như sau:


Array


(



   [0] => Array
      (

[Category] => Array


(


[id] => 1


[name] => Thông tin thị trường


[alias] => tin_tuc


[parent_id] =>


[root_path] =>


[level] => 0


[order] =>


[lang] =>


[represent] =>


[is_hyperlink] => 0


[active] => 0


[layout] => 0


[created] => 0000-00-00 00:00:00


)



[NewsCategory] => Array


(


[id] => 16


[news_id] => 4


[category_id] => 1


)



)



[1] => Array


(


[Category] => Array


(


[id] => 2


[name] => Phân tích thị trường


[alias] =>


[parent_id] =>


[root_path] =>


[level] => 0


[order] =>


[lang] =>


[represent] =>


[is_hyperlink] => 0


[active] => 0


[layout] => 0


[created] => 0000-00-00 00:00:00


)



[NewsCategory] => Array


(


[id] => 17


[news_id] => 4


[category_id] => 2


)



)


...



)


3. So sánh tốc độ


Thực tế, cách sử dụng query và cách sử dụng lấy dữ liệu tự động thông qua các hàm find, findAll… sẽ không khác nhau là mấy hay nói đúng hơn là không khác gì nhau khi ta xác định rõ ràng recursive trong từng trường hơp cụ thể, kết hợp với sự dụng bindModel và unbindModel để xác định số lượng các bảng tham gia inner join.


II. Tối ưu dữ liệu theo cách lấy tự động


1. Sử dụng Recursive


Recursive trong cakephp thể hiện mức tham chiếu quan hệ nông, sâu giữa các bảng với nhau, trong cakephp có 4 mức thể hiện tham chiếu được thể hiện qua ví dụ sau đây:


Giả sử ta có tất cả 4 bảng bao gồm: domains, groups, users và news. Và mối quan hệ giữa các bảng như sau: Một domain có rất nhiều group, trong mỗi một group lại có rất nhiều user. Một user lại có thể đăng lên rất nhiều bài viết khác nhau. Vậy là ta có thể xác định các bảng có quan hệ tham chiếu đến nhau.


Ta có thể hình dung như sau:









































table



domains



groups



users



News



domains





hasMany







groups



belongsTo





hasMany





users





belongsTo





hasMany



news







belongsTo






Giả sử ta muốn lấy dữ liệu ở bảng group theo câu lệnh $this->Group->find(‘all’). Việc sử dụng giá trị recursive sẽ cho phép ta lấy dữ liệu khác nhau.


Cú pháp sử dụng recursive trong trường hợp này là:


$this->Group->recursive = 1


























Deapth



Mô tả



-1



Lấy dữ liệu ở bảng Group, không lấy thêm bất cứ bảng nào khác



0



Lấy dữ liệu ở bảng Group và dữ liệu domain tương ứng



1



Lấy dữ liệu ở bảng Group, Domain và dữ liệu ở bảng User tương ứng



2



Lấy dữ liệu ở bảng Group, Domain, User và dữ liệu ở bảng News tương ứng




Nhìn qua bảng trên ta thấy tùy từng giá trị recursive khác nhau mà cakephp thực hiện liên kết với (inner join) thích hợp. Giả sử như ta cho recursive bằng 2, có nghĩa là ta lấy ra dữ liệu của các group, dữ liệu domain tương ứng với mỗi group đó, đồng thời là một danh sách các user nằm trong từng group, trong mỗi user đấy lại lấy ra các tin tức do các user ấy đăng. Vậy có nghĩa là sẽ có 4 bảng liên kết với nhau. Với recursive là 1 thì chỉ có 3 bảng thôi.


Như vậy là tùy tường trường hợp cụ thể mà ta có thể khai báo giá trị recursive khác nhau. Trong trường hợp ta chỉ cần lấy dữ liệu từ mỗi bảng group thì ta chỉ cần khai báo giá trị recursive là -1. Nếu muốn lấy thêm dữ liệu ở bảng domain thì khai báo recursive = 0…. Việc khai báo recursive cho từng trường hợp sẽ làm tăng tốc độ query vì ta sẽ kiểm soát được số lượng các bảng liên kết với nhau.


2. Sử dụng bindModel và unbindModel


Trong một số trường hợp, với cùng một model chúng ta sẽ phải khai báo thêm một số quan hệ hoặc bỏ bớt một số quan hệ với các bảng khác, điều này xảy ra khi:


- Bạn cần giảm bớ số lượng dữ liệu và mối quan hệ của các bảng lien quan cần lấy đến, trong khi khởi tạo ở model ta đã khai báo tất cả các quan hệ ấy rồi. (ví dụ như trong model group ở trên, ta chỉ muốn lấy dữ liệu từ 2 bảng là group và user, trong khi đó theo quan hệ ta sẽ phải join đồng thời cả 3 bảng user, group và domain. Như vậy việc truy xuất dữ liệu sẽ chậm hơn)


- Bạn muốn thay đổi cách liên kết của một model xác định để sẵp xếp hoặc lọc dữ liệu liên quan.


Khi muốn thêm một liên kết ta sẽ dùng đến bindModel và khi muốn xóa một liên kết ta sẽ sử dụng unbindModel. (Cách sử dụng bindModel va unbindMode sẽ được bàn sau)

Sử dụng recursive, bindModel và unbindModel trong cakephp

Sử dụng recursive, bindModel và unbindModel sẽ giúp mọi người kiểm soát dữ liệu lấy ra trong cakephp.


1. Sử dụng Recursive


Recursive trong cakephp thể hiện mức tham chiếu quan hệ nông, sâu giữa các bảng với nhau, trong cakephp có 4 mức thể hiện tham chiếu được thể hiện qua ví dụ sau đây:


Giả sử ta có tất cả 4 bảng bao gồm: domains, groups, users và news. Và mối quan hệ giữa các bảng như sau: Một domain có rất nhiều group, trong mỗi một group lại có rất nhiều user. Một user lại có thể đăng lên rất nhiều bài viết khác nhau. Vậy là ta có thể xác định các bảng có quan hệ tham chiếu đến nhau.


Ta có thể hình dung như sau:









































table



domains



groups



users



News



domains





hasMany







groups



belongsTo





hasMany





users





belongsTo





hasMany



news







belongsTo






Giả sử ta muốn lấy dữ liệu ở bảng group theo câu lệnh $this->Group->find(‘all’). Việc sử dụng giá trị recursive sẽ cho phép ta lấy dữ liệu khác nhau.


Cú pháp sử dụng recursive trong trường hợp này là:


$this->Group->recursive = 1


























Deapth



Mô tả



-1



Lấy dữ liệu ở bảng Group, không lấy thêm bất cứ bảng nào khác



0



Lấy dữ liệu ở bảng Group và dữ liệu domain tương ứng



1



Lấy dữ liệu ở bảng Group, Domain và dữ liệu ở bảng User tương ứng



2



Lấy dữ liệu ở bảng Group, Domain, User và dữ liệu ở bảng News tương ứng




Nhìn qua bảng trên ta thấy tùy từng giá trị recursive khác nhau mà cakephp thực hiện liên kết với (inner join) thích hợp. Giả sử như ta cho recursive bằng 2, có nghĩa là ta lấy ra dữ liệu của các group, dữ liệu domain tương ứng với mỗi group đó, đồng thời là một danh sách các user nằm trong từng group, trong mỗi user đấy lại lấy ra các tin tức do các user ấy đăng. Vậy có nghĩa là sẽ có 4 bảng liên kết với nhau. Với recursive là 1 thì chỉ có 3 bảng thôi.


Như vậy là tùy tường trường hợp cụ thể mà ta có thể khai báo giá trị recursive khác nhau. Trong trường hợp ta chỉ cần lấy dữ liệu từ mỗi bảng group thì ta chỉ cần khai báo giá trị recursive là -1. Nếu muốn lấy thêm dữ liệu ở bảng domain thì khai báo recursive = 0…. Việc khai báo recursive cho từng trường hợp sẽ làm tăng tốc độ query vì ta sẽ kiểm soát được số lượng các bảng liên kết với nhau.


2. Sử dụng bindModel và unbindModel


Trong một số trường hợp, với cùng một model chúng ta sẽ phải khai báo thêm một số quan hệ hoặc bỏ bớt một số quan hệ với các bảng khác, điều này xảy ra khi:


- Bạn cần giảm bớ số lượng dữ liệu và mối quan hệ của các bảng lien quan cần lấy đến, trong khi khởi tạo ở model ta đã khai báo tất cả các quan hệ ấy rồi. (ví dụ như trong model group ở trên, ta chỉ muốn lấy dữ liệu từ 2 bảng là group và user, trong khi đó theo quan hệ ta sẽ phải join đồng thời cả 3 bảng user, group và domain. Như vậy việc truy xuất dữ liệu sẽ chậm hơn)


- Bạn muốn thay đổi cách liên kết của một model xác định để sẵp xếp hoặc lọc dữ liệu liên quan.



Khi muốn thêm một liên kết ta sẽ dùng đến bindModel và khi muốn xóa một liên kết ta sẽ sử dụng unbindModel.

Giả sử giờ ta có 2 model là user và group. Một group sẽ chứa nhiều user và mỗi user nằm trong 1 group.


Trươc tiên chúng ta sẽ khai báo 2 model




<?php
//app/models/group.php
class Group extends AppModel {
var $name = 'Group';

var $hasMany = array(
'User' => array(
'className' => 'User'
)
);
}

?>

<?php
//app/models/user.php

class User extends AppModel {
var $name = 'User';
}

?>


Giờ chúng ta sẽ xem cách hoạt động của bindModel và unbindModel qua ví dụ dưới đây. Trong groupController chúng ta sẽ lấy dữ liệu của group bằng $this->Group->find(), dữ liệu sẽ lấy luôn cả dữ liệu của user. Ví dụ minh họa dưới đây sẽ cho ta hiểu rõ hơn cách sử dùng và làm việc của bindModel và unbindModel.

function someAction() {
// Lấy dữ liệu của group, ta sẽ lấy được cả dữ liệu của user trong từng group ấy
$group = $this->Group->find('all');
echo 'Lấy theo model'
debug($group);

// Bỏ quan hệ hasMany...
$this->Group->unbindModel(
array('hasMany' => array('User'))
);

// Sử dụng lại chức năng find()
// Hiên thị group, không có user
$group = $this->Group->find('all');
echo 'Bỏ quan hệ với bảng user';
debug($group);

// Thêm quan hệ hasMany...

$this->Group->bindModel(
array('hasMany' => array(
'User' => array(
'className' => 'User'
)
)
)
);

// Sử dụng lại chức năng find()
// Hiên thị group, có user
$group = $this->Group->find('all');
echo 'Thêm quan hệ với bảng user';
debug($group);

// Bỏ quan hệ hasMany lần 2...
$this->Group->unbindModel(
array('hasMany' => array('User'))
);

// Sử dụng lại chức năng find()
// Hiên thị group, không có user
$group = $this->Group->find('all');
echo 'Bỏ quan hệ với bảng user lần 2';
debug($group);

//Chú ý: unbindModel và bindModel chỉ hiệu quả
// duy nhất trong lần lấy dữ liệu tiếp theo,
// sau lần thứ 2 sẽ lấy thông tin mặc định từ model

// Chúng ta sẽ sử dụng lại hàm find('all') sau unbindModel(),
// Dữ liệu lấy ra sẽ bao gổm cả group và user
echo 'Lấy dữ liệu mặc định';
$group = $this->Group->find('all');
debug($group);
}


Cú pháp chuẩn của unbindModel

$this->Model->unbindModel(
array('associationType' => array('associatedModelClassName'))
);


Cú pháp chuẩn của bindModel

$this->Model->bindModel(
array('associationName' => array(
'associatedModelClassName' => array(
// normal association keys go here...
)
)
)
);


Sử dụng hiệu quả recursive, bindModel và unbindModel sẽ giúp mọi người tăng tốc độ truy vấn query của cakephp vì với mỗi trường hợp lấy dữ liệu tôi đã xác định rõ các bảng cần lấy và quan hệ giữa chúng, vì vậy giảm thiều việc liên kết thừa giữa các bảng mà chúng ta không cần lấy. Chúc mọi người có một ngày vui vẻ @(^_^)@