Saturday, July 3, 2010

Tạo đường dẫn thân thiện với PHP

Nguồn: http://opensource.com.vn/opensource/programming/php/52-tao-duong-dan-than-thien-voi-php.html
altMột trong những lý do chính để sử dụng ngôn ngữ kịch bản PHP là do khả năng dễ dàng tạo nội dung động. Thông thường nó sẽ dẫn tới một mã đơn dùng tạo ra nội dung ựa trên các tham số đầu vào ( đó là các giá trị trên URL).

Bài viết này bao gồm các kỹ thuật và phương thức để thay thế cho các tham số trên URL một cách đẹp đẽ và thân thiện, không khác gì việc làm thế nào để đọc các tham số này.
Nếu bạn không chắc chắn về những điều đã nói ở trên, hãy xem qua ví dụ bên dưới. Một website lưu trữ danh sách các bài viết trong cơ sở dữ liệu gọi là articles. Bây giờ chúng ta sẽ xây dựng website mà mỗi bài viết được liên quan bởi mổi ID như:
http://www.domain.com/article.php?article_id=1234

Tuy nhiên đây không phải là cách tốt nhất để làm việc này. Đầu tiên, nếu người dùng đã đọc một lượng lớn bài viết trên website thì lịch sử lưu trữ của trình duyệt trên máy họ sẽ lưu lại lượng lớn các ID khác nhau. Vì vậy họ không thể quay trở lại bài viết nào đó một cách dễ dàng mà không sử dụng bookmark hoặc trở lại từ trang chủ để tìm kiếm liên kết từ đầu.
Quan trọng hơn đây là dữ liệu quý giá để cách bộ máy tìm kiếm sử dụng để đánh chỉ mục cho trang của bạn. Chúng ta sẽ xây dựng theo cách mỗi bài viết được truy cập bởi một phương thức thân thiện hơn. Ví dụ, một bài viết sau này đây có dạng đường dẫn:
http://www.domain.com/articles/multi-step-wizards
Bài viết này sẽ trình bài cách đọc địa chỉ URL như trên và dẫn nó tới dữ liệu trong cơ sở dữ liệu của bạn. Có nhiều cách để làm được việc này với PHP, chúng ta sẽ xem xét mỗi phương thức và thảo luận về chúng(pros and cons of each.)
Thêm nữa ý tưởng được sử dụng ở đây có thế là "thông qua" mỗi cách (như việc đọc URL một cách thông thường) nhưng chúng ta sẽ bỏ qua nó.

Apache's Mod Rewrite
Cách đầu tiên chúng ta tìm hiểu là mod_rewrite của Apache. module này làm việc theo cách gán các địa chỉ truy vấn với thiết lập của các luật được chỉ định trước và truyền dữ liệu cho mã lệnh với định dạng mà bạn thiết lập.
Chúng ta có file news.php ở thư mục gốc của website (mà bạn có thể truy cập trực tiếp theo đường dẫn http://www.domain.com/news.php). Đoạn mã này sẽ trả về dữ liệu của bài viết theo tham số news_id trên URL.
Nếu ta truy cập vào bài viết với ID bằng 63 bạn có thể dùng đường dẫn http://www.example.com/news.php?news_id=63.
Thay vào đó ta muốn tạo cho nó một cách đẹp đẽ hơn, tốt hơn là duyệt qua URL, chúng ta muốn truy cập đến bài viết theo dạng http://www.example.com/news/63.html. Không có lý do đặc biệt nào để được như vậy - đây chỉ là ví dụ.
Dù sao đi nữa chúng ta có thể làm được việc này với mod_rewrite bằng luật đơn giản, hoặc ở cấu hình của máy chủ (httpd.conf) hoặc ở tập tin .htaccess trong thư mục chứa website.
Nội dung như sau:
.htaccess
RewriteEngine on
RewriteRule ^/news/([0-9]+)\.html /news.php?news_id=$1

Sử dụng mẫu biểu thức chính quy trên đây ta sẽ lấy tất cả các truy vấn phù hợp tới website bắt đầu bằng news sau đó là số đi cùng với .html. Các mục được đặt trong dấu ngoặc đơn được lưu với các giá trị như $1 hoặc $2 ( chúng ta chỉ có một dấu ngoặc với $1 được thiết lập ).
Tiếp đó chúng ta sử dụng tham số $1 trên URL. Trong file news.php chúng ta sẽ truy cập tới tham số như với cách ta gọi mã này ở cách thông thường:
news.php
$news_id = $_GET['news_id'];
?>


Các tham số URL mở rộng

Đôi khi ta gặp phải tình trạng cần cung cấp một số tham số mở rộng trên URL cho đoạn mã. Quay trở lại với ví dụ ở trên, có lẽ bạn có thể truy cập tới news.php với tham ố mở rộng là 'print', dùng để hiển thị in ấn cho bài viết (bạn cần sử dụng css cho nó, nhưng không có vấn đề gì với ví dụ này).
Bạn có thể truy cập bằng cách http://www.example.com/news.php?news_id=63&print=1.
Sử dụng cách tạo đường dẫn thân thiện ta muốn truy cập tới bài viết bằng cách http://www.example.com/news/63.html?print=1, luật bên trên là cách đơn giản để bỏ đi tham số print trên URL. Để truyền nó cho mã lệnh ta cần sử dụng giá trị của Apache %{QUERY_STRING} trong biểu thức của mod_rewrite. Ta chỉ việc gắn vào news_id dấu &.
.htaccess
RewriteEngine on
RewriteRule ^/news/([0-9]+)\.html /news.php?news_id=$1&%{QUERY_STRING}

Bây giờ ta có thể truy cập tới tham số thông qua phương thức $_GET
news.php
$news_id = $_GET['news_id'];
$printVersion = isset($_GET['print']);
?>

Tất cả đều sử dụng mod_rewrite. Đây là một module hiệu quả và khá phức tạp, và bạn có thể dễ dàng gặp rắc rối khi sử dụng nó. Đôi khi nó có thể rất khó khăn để lấy biểu thức của bạn một cách chính xác, hoặc bạn tạo ra quy tắc không đúng vv... Có một số cấu hình gỡ lỗi bạn có thể sử dụng để khắc phục vấn đề bạn có thể gặp phải.

Sử dụng Apache Forcetype Directive

Thay thế cho mod_rewrite là sử dụng ForceType directive. Nó cho phép mã lệnh PHP hoạt động mà không cần có phần mở rộng .php. Thông thường máy chủ được cấu hình tập tin PHP phải kết thúc bằng .php, vì vậy các mã khác không phải php(như .html) không được thực thi bằng PHP engine.
Quay trở lại ví dụ sử dụng mod_rewrite, thay vì có một đoạn mã là news.php ở thư mục gốc, đoạn mã của chúng ta có thể được gọi là news. Vì vậy nó có thể được truy cập theo dạng http://www.example.com/news.
Sử dụng thiết lập sau trong httpd.conf hoặc .htaccess sẽ thực thi news như là một tập tin PHP.
.htaccess

ForceType application/x-httpd-php

Bây giờ khi chúng ta truy cập bài viết theo dạng http://www.example.com/news/63.html, đoạn mã news sẽ được truy cập trực tiếp và ta phải phân tích phần /63.html. Nó được lưu với giá trị máy chủ PATH_INFO.
news
echo $_SERVER['PATH_INFO'];
// outputs '/63.html'
?>

Ta có mẫu biểu thức chính quy để xác định ố 63 trong chuỗi. Cũng có kỹ thuật khác để bạn sẽ tìm ra dữ liệu một cách chính xác, như là sử dụng hàm explode(). Ví dụ, nếu bạn bung chuỗi này ở / tiếp đó tất cả các phần của đường dẫn sẽ được lưu trong mảng (chỉ có một phần ở ví dụ này cho nên nó sẽ không hoạt động). Quay trở lại mẫu biểu thức chính quy.
Đây là một mẫu biểu thức chính quy (phù hợp với preg_match()), sẽ tìm chuỗi có dấu / bắt đầu sau đó là số cùng với .html. Nó sẽ lưu toàn bộ những gì phù hợp vào mảng từ đó trích ra ID của bài viết.
news
$path = $_SERVER['PATH_INFO'];
preg_match('!^/(\d+)\.html$!', $path, $matches);

// $matches[0] will store the entire matched string, while $matches[1]
// stores the string matched in the first set of brackets. We want it
// to be an int, so we simply cast it.
$news_id = (int) $matches[1];
?>


Bây giờ ta có thể sử dụng $news_id trong đoạn mã. Chắc chắn nếu đường dẫn không đúng với định dạng thì $news_id có thể là 0 sau khi ta đặt nó là dạng int, để an oàn hơn cho cơ sở dữ liệu thậm chí cả khi bài viết không tồn tại.

Sử dụng điều hướng trang thông báo lỗi 404
Đây chỉ là một cách để có được kết quả, dù sao nó cũng là cách đơn giản nhất để khai triển và cũng tốt hơn.
Bằng cách chỉnh chỉnh sửa cấu hình thông báo lỗi 404 bạn có một phương cách điều khiển riêng mà sẽ quyết định cách đối xử với các truy vấn. Dĩ nhiên đây chỉ là truy vấn tới tập tin không tồn tại. Ví dụ, nếu bạn có hình ảnh trên website bạn vẫn có thể truy cập tới chúng nếu tồn tại. Vì vậy việc quyết địng đối xử 404 không được sử dụng.
Thêm nữa, bằng cách sử dụng hàm header() bạn có thể trả về header 200 OK hoặc 404 File Not Found, ở phía người dùng cuối họ không quan tâm rằng trang này thực sự không tìm thấy.

Ví dụ:
Nếu bạn truy cập theo đường dẫn : http://www.domain.com/d/articles/php/index.html. Trang này sẽ sử dụng 'ForceType' với mã lênh PHP gọi là 'd' để xử lý truy vấn, nhưng chúng ta không sử dụng phương pháp này.
Giả sử ta muốn URL có dạng : http://www.domain.com/articles/php/index.html. Thay vì tạo đường dẫn này cho mỗi bài viết, chúng ta có thể sử dụng việc xử lý 404 để duyệt qua đường dẫn bài viết như chúng ta đang làm với tập tin d.

Thực hiện xử lý 404
Chúng ta không thực hiện xử lý các ví dụ ở trên thay vào đó chúng ta sẽ thực hiện xử lý cách bài viết ví dụ. Ta cũng sẽ thêm vào mục đích để xử lý các truy vấn khác (ngoài news) và cả các trang lỗi..
Điều đầu tiên là ta tạo xử lý 404. Việc này có thể làm tại tập tin .htaccess hay httpd.conf.
.htaccess
ErrorDocument 404 /handler.php

Điều này có nghĩa rằng tất cả các truy vấn tới tập tin không tồn tại sẽ được trả về tập tin handler.php trên thư mục gốc của website.
Trong đoạn mã này ta cần phân tích truy vấn. Bạn có thể tìm thấy truy vấn gốc bằng giá trị REDIRECT_URL .
handler.php
$request = $_SERVER['REDIRECT_URL'];

// explode on / to find all the different request parts
$parts = explode('/', $request);

// flag to determine whether or not we've found content
$found = false;

// the first element will be empty to we get rid of it
array_shift($parts);

// now we determine the type of content
switch ($parts[0]) {
case 'news':
// use a very similar regex to our previous example
preg_match('!^(\d+)\.html$!', $parts[1], $matches);
$news_id = (int) $matches[1];

$output = getNewsArticle($news_id);
// this function doesn't really exist, but if it
// did it would return the news content if article
// found, or return null if not

if ($output !== null)
$found = true;
break;

case 'articles':
// here we would implement a handler to display a document,
// say if they accessed http://www.example.com/documents/1234.html
break;
default:
}

if ($found) {
// output a header to say the content exists, other a 404 will be sent
header('HTTP/1.1: 200 OK');
echo $output;
}
else {
// no content was found. this should be automatically sent by the
// server anyway, but we'll specify anyway just in case
header('HTTP/1.0 404 Not Found');
echo 'File not found';
}
?>

Rõ ràng đoạn mã này còn thô sơ nhưng hy vọng thông qua đoạn mã này bạn sẽ tìm ra cách tốt hơn.

Sử dụng mod_rewrite như là 404 Handler

Trong khi chỉnh sửa cấu hình xử lý 404 là cách linh động để tạo đường dẫn thân thiện, thì lỗi lớn nhất của nó là khi dữ liệu được cung cấp phương thức POST, không phù hợp (theo cách Apache hướng dữ liệu truy vấn khi sử dụng ErrorDocument).
Ta có thể sử dụng kết hợp giữa mod_rewrite và cấu hình xử lý 404. Các mà kỹ thuật này hoạt động là sử dụng mod_rewrite hướng tất cả truy vấn tới đoạn mã xác định khi mã truy vấn tới một tập tin là không tồn tại. Sử dụng đoạn mã sau (trong tập tin .htaccess hoặc httpd.conf).

Using mod_rewrite to foward requests that don't correspond to an existing file or directory (.htaccess)
RewriteEngine On
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1


Đầu tiên RewriteCond kiểm tra xem truy vấn tới tập tin có tồn tại hay không. Ở mod_rewrite -f quy định là tập tin, khi không phải là toán tử. !-f có nghĩa "nếu truy vấn tới tập tin không tồn tại".
Nếu rewrite_cond thành công succeeds (truy vấn tới tập tin không tìm thấy), tiếp đó Apache chuyển tới điều kiện tiếp theo. Chỉ thị !-d có nghĩa điều kiện thành công nếu truy vấn không phù hợp với thư mục tồn tại trên máy chủ
Cuối cùng nếu cả 2 điều kiện thành công truy vấn được chuyển tới tập tin index.php, được chỉ định ởRewriteRule.
Bạn có thể sử dụng kỹ thuật này ở phần trước (ở Sử dụng điều hướng trang thông báo lỗi 404) để đọc URL . Sử dụng kỹ thuật được phác qua ở đây bạn có thể truy cập tới dữ liệu POST .

Theo Quentin Zervaas

No comments:

Router Packet Networking

Đây là video ngắn khá hay, mô tả đường đi của một gói tin trên Mạng Internet.