Python cho người Việt

Python cho người Việt

Lập trình web với Python (4)

written by Nguyễn Thành Nam, on Mar 10, 2010 12:46:00 PM.

Trong kỳ này, chúng ta sẽ xem xét một chương trình CGI có xử lý dữ liệu nhập.

Ở kỳ trước, chúng ta đã biết cấu trúc chung của một chương trình CGI. Chương trình CGI mà chúng ta dùng làm ví dụ không thật sự hữu dụng vì chúng chỉ xuất giá trị ngẫu nhiên.

Một chương trình CGI hữu dụng thường sẽ nhận dữ liệu nhập qua các mẫu đơn (form), xử lý các dữ liệu này, và trả về kết quả.

Các dữ liệu nhập được truyền đến ứng dụng web ở dạng bộ 2 (khóa, giá trị) (key-value pair). Ví dụ nếu chúng ta điền vào một mẫu đơn có trường nhập tên là name và giá trị của nó là Nguyễn Việt Nam thì khóa sẽ là name và giá trị là Nguyễn Việt Nam. Thông thường có hai phương thức truyền dữ liệu đến ứng dụng web là GET và POST.

Trong phương thức GET, các bộ 2 (khóa, giá trị) này sẽ được truyền qua URL. Với ví dụ ở trên, URL sẽ có dạng http://host/path?name=Nguyễn+Việt+Nam. Bạn đọc sẽ chú ý các điểm quan trọng sau:

  1. Đi ngay phía sau đường dẫn đến ứng dụng CGI là một dấu chấm hỏi (?). Ký tự này dùng để thông báo phần phía sau là dữ liệu nhập.

  2. Phân cách giữa khóa và giá trị của dữ liệu nhập là dấu bằng (=).

  3. Khóa và giá trị được chuyển mã theo dạng phù hợp. Chúng ta thấy rằng ký tự khoảng trắng được chuyển thành ký tự cộng (+). Việc chuyển mã này nhằm làm cho URL không chứa các ký tự đặc biệt có thể gây nhầm lẫn.

  4. Không được nêu rõ trong ví dụ là ký tự phân cách các bộ 2 (khóa, giá trị) là ký tự và (&).

Trong phương thức POST, các bộ 2 (khóa, giá trị) được truyền trong nội dung yêu cầu HTTP, và không hiện rõ cho người dùng.

Hãy thử nghiệm với chương trình ví dụ sau (đặt tên nó là fp.py):

#!c:/python26/python

print "Content-Type: text/html"
print

print """<html>
      <head>
              <title>CGI form processing</title>
      </head>
      <body>
              <fieldset>
                      <legend>Number guessing game</legend>
                      <form method="POST">
                              <label for="number">Enter a number</label>
                              <input type="text" name="number" value="" />
                              <input type="submit" />
                      </form>
              </fieldset>
      </body>
</html>
"""

Kết quả mà chúng ta nhận được là một mẫu đơn như hình:

/static/web-programming/cgi/form1.png

Một số điểm quan trọng trong chương trình này là sự sử dụng các thẻ liên quan đến mẫu đơn.

  1. Trước hết là thẻ form dùng để thông báo sự bắt đầu của một mẫu đơn. Các thuộc tính (attribute) thông thường của thẻ này gồm methodaction.

    1. Thuộc tính method xác định phương thức truyền dữ liệu. Chúng ta có thể sử dụng GET hoặc POST.

    2. Thuộc tính action xác định đường dẫn đến chương trình CGI sẽ xử lý mẫu đơn này. Nếu không xác định thì chính địa chỉ hiện tại sẽ được dùng.

  2. Thẻ input xác định một trường nhập. Thẻ này có các thuộc tính chính là type, name, và value.

    1. Thuộc tính type xác định kiểu nhập là một ô nhập (text box), một nút nhấn (button), một nút chọn (radio button), hoặc một tập tin (file). Ở ví dụ này chúng ta xác định một ô nhập với kiểu text.

    2. Thuộc tính name xác định khóa của bộ 2. Trong ví dụ này khóa nhập là number.

    3. Thuộc tính value xác định giá trị khởi đầu của trường nhập này. Chúng ta để trống.

  3. Thẻ input với thuộc tính typesubmit sẽ tạo một nút nhấn. Nút nhấn này đặc biệt vì nó sẽ gửi các giá trị chúng ta nhập vào mẫu đơn đến chương trình CGI.

Thông tin chi tiết về các thẻ HTML có thể được xem thêm từ các tài liệu từ W3C.

Chương trình này cũng chỉ là in ra một mẫu đơn nhưng chúng ta đã có thể nhấn nút để gửi mẫu đơn đó đi.

Chúng ta sẽ sửa nó để in lại những gì đã nhận từ trình duyệt.

#!c:/python26/python

import cgi

print "Content-Type: text/html"
print

print """<html>
      <head>
              <title>CGI form processing</title>
      </head>
      <body>
              <fieldset>
                      <legend>Number guessing game</legend>
                      <form method="POST">
                              <label for="number">Enter a number</label>
                              <input type="text" name="number" value="" />
                              <input type="submit" />
                      </form>
              </fieldset>
"""

form = cgi.FieldStorage()
if form.has_key('number'):
      print """You have entered: %s""" % form.getfirst('number')

print """</body>
</html>
"""

Điều đầu tiên chúng ta nhận ra là sự sử dụng mô-đun cgi. Mô-đun này cho phép chúng ta tạo một đối tượng FieldStorage. Đối tượng FieldStorage chứa các bộ 2 (khóa, giá trị) chúng ta nhận được từ trình duyệt trong một cấu trúc như kiểu từ điển. Do đó chúng ta có thể dùng phương thức has_key để kiểm tra sự tồn tại của khóa tương ứng. Để lấy giá trị từ FieldStorage ta có thể dùng form['number'].value hoặc gọi các hàm như getvalue, getfirst, hay getlist. Các hàm này được đề cập đến một cách chi tiết trong bộ tài liệu sử dụng Python.

Nếu tinh ý, chúng ta sẽ thấy rằng khi dữ liệu nhập chứa các thẻ HTML hợp lệ thì kết quả xuất ra sẽ hiển thị cả những thẻ HTML này. Ví dụ khi ta nhập Nguyễn <b>Việt</b> Nam.

/static/web-programming/cgi/form2.png

Điều này có thể là đúng theo ý định, hoặc cũng thể nằm ngoài mong muốn. Chúng ta gọi đây là các lỗi kịch bản chéo trang (Cross Site Scripting, XSS). Cách khắc phục là trước khi hiển thị các chuỗi không nằm trong kiểm soát của chương trình (ví dụ như dữ liệu nhập, dữ liệu xuất từ hệ thống khác, v.v...), chúng ta sẽ cần chuyển mã các ký tự đặc biệt. Mô-đun cgi cung cấp hàm escape để làm việc này. Mã nguồn mới sẽ gói getfirst trong cgi.escape như sau:

#!c:/python26/python

import cgi

print "Content-Type: text/html"
print

print """<html>
      <head>
              <title>CGI form processing</title>
      </head>
      <body>
              <fieldset>
                      <legend>Number guessing game</legend>
                      <form method="POST">
                              <label for="number">Enter a number</label>
                              <input type="text" name="number" value="" />
                              <input type="submit" />
                      </form>
              </fieldset>
"""

form = cgi.FieldStorage()
if form.has_key('number'):
      print """You have entered: %s""" % cgi.escape( \
                      form.getfirst('number'), True)

print """</body>
</html>
"""

Giờ đây, chuỗi được xuất ra sẽ giống hệt với chuỗi nhập.

/static/web-programming/cgi/form3.png

Chúng ta cũng có thể thử với phương thức GET bằng cách nhập thẳng URL http://localhost/cgi-bin/fp.py?number=Nguyễn+<b>Việt</b>+Nam. Chúng ta cũng sẽ nhận được kết quả tương tự.

Vậy là qua hai phần chúng ta đã tìm hiểu về cách hoạt động của một chương trình CGI. Điểm mạnh của giao thức CGI là tính đơn giản và an toàn cao vì mỗi yêu cầu được một tiến trình riêng xử lý. Cũng chính vì mô hình đơn giản như vậy nên CGI gặp phải nhiều cản trở trong việc phát triển. Cản trở đầu tiên là chương trình CGI phải tự xử lý trạng thái giữa các yêu cầu kế tiếp nhau, hay còn gọi là phiên làm việc (session). Cản trở thứ hai là chương trình CGI sẽ phải được thiết kế đặc biệt nếu muốn sử dụng các biến có phạm vi toàn ứng dụng (application scope). Cuối cùng, chương trình CGI chạy chậm hơn và tốn tài nguyên hơn vì mỗi yêu cầu phải được xử lý riêng.

Trong các phần tới, chúng ta sẽ xem qua cách hoạt động của những công nghệ tiên tiến, giải quyết được các điểm yếu của giao thức CGI.

Comments

  • Anh ơi có thể cho biết các công nghệ anh định nói tới là những công nghệ gì được không ạ, anh có thể viết các đề mục ngắn gọn để bọn em tìm hiểu trước mỗi một tutorial được không anh. Chẳng hạn các tutorial tiếp theo nội dụng anh sẽ viết về cái gì được không ạ, coi như là một dàn bàn ngắn gọn thôi ạ.

    Comment by naruto720640@gmail.com — Mar 14, 2010 6:04:25 PM | #

  • Trong hai, hoặc ba, hoặc bốn bài tới có thể mình sẽ nói về FCGI và WSGI.

    Về cơ bản thì FCGI cũng giống với CGI.

    Nhưng WSGI thì mô hình hoạt động có khác nên có thể cần một bài nói sơ về cách hoạt động, và một bài khác nói về chức năng nâng cao.

    Comment by Nguyễn Thành Nam — Mar 17, 2010 9:54:12 AM | #

  • Hôm nay tìm trên google mới thấy trang web này. Loại bài “Lập trình web với Python” rất hay, mình sẽ theo dõi. Cám ơn và hy vọng tác giả sẽ post đều đặn lọat bài này.

    Comment by zoro — Mar 19, 2010 9:18:15 PM | #

  • WSGI là tốt nhất đúng không anh, ý em là mạnh mẽ nhất ấy ạ? Chờ lâu quá không thấy anh ra tutorial mới nào, tiện thể anh cho em hỏi luôn.

    Comment by naruto — Apr 17, 2010 12:45:03 PM | #

  • Anh ơi , sao trang web của mình không dùng plone, hay là do mình dùng ké máy chủ, mà máy chủ dùng ké không có plone ?

    Comment by naruto720640@gmail.com — Apr 17, 2010 12:47:41 PM | #

  • Anh cho em hỏi một chút làm thế nào để có thể hiển thị được tiếng việt ạ?

    Comment by naruto — Apr 23, 2010 6:45:14 PM | #

  • Xin lỗi anh em hỏi hơi nhiều , em tìm được rồi về vấn đề tiếng việt trong python: www.vithon.org/tags/unicode , để em thử tìm hiểu xem , có gì khó em sẽ hỏi anh tiếp.

    Comment by naruto — Apr 24, 2010 5:03:56 PM | #

  • www.java2s.com/Tutorial/Python/0440__CGI-Web/DemonstratesuseofcgiFieldStoragewithanXHTMLform.htmllà một trang tương đối hay dạy rất nhiều ngôn ngữ trong đó có python. Định vào diễn đàn nhưng không vào được có lẽ do máy chủ dùng ké. Post vào đây vậy.Hy vọng có ích đối với ai đó quan tâm đến lập trình nói chung và python nói riêng.

    Comment by naruto — May 3, 2010 8:59:40 PM | #

  • Theo anh nên dùng ide nào và editor nào ngoài cái idle có sẵn trong python ạ.?

    Comment by Naruto — May 8, 2010 6:24:14 PM | #

  • Nếu bạn không muốn dùng idle kèm theo của Python bạn không nên bỏ qua Pysripter. Nó thực sự đem lại cho bạn một cảm giác thật tuyệt

    Comment by Naruto — May 9, 2010 2:46:15 PM | #

  • Chờ loạt bài về wsgi và fcgi của anh lâu quá :p

    Comment by Hồ Sỹ Cảnh — May 27, 2010 8:28:17 PM | #

  • Anh ơi sao Cái chữ “Việt” trong Nguyễn Việt Nam nó lại không hiện lên. Cho em hỏi có cần phải configure apache để nó hiển thị được font unicode không ạ?

    Em làm giống như anh mà khi đánh tiếng Việt nó không hiện lên được ?

    Comment by naruto — Jul 22, 2010 12:10:20 AM | #

  • <input type=”text” name=”number” value=”" /><— Đổi thành <input type=”text” id=”number” value=”" /> thì thẻ <label> mới có ý nghĩa.

    Comment by telwo — Nov 27, 2010 4:10:50 PM | #