Python核心編程筆記————Web 編程:CGI 和 WSGI(二)

高級CGI

mulitipart 表單提交和文件上傳

. CGI 特別指出只允許兩種表單編碼:“application/x-www-form-urlencoded”和“multipart/form-dat”。且前者是默認的,因此前者不需要特別指出,但是後者需要明確給出編碼:

<FORM enctype="multipart/form-data" ...>

. 表單提交的時候可以使用任意編碼,但是在上傳文件的時候只能使用multipart編碼,通過使用輸入類型爲文件的方式來完成:

<INPUT type=file name=...>

. 這個指令顯示一個空的文本框,同時旁邊有個按鈕,可以通過該按鈕瀏覽文件目錄結構

多值字段

. 常見的處理多值字段的情況是有一系列的複選框,在提交表單的時候,數據以鍵值對的方式傳遞給服務器,當提交的不止一個複選框的時候,就會出現多個值對應一個鍵。在這種情況下,cgi模塊會建立一個包含這類實例的列表,可以遍歷該列表獲得所有值。

cookie

. 可以將其看做web站點服務器要求保存在客戶端上的二進制數據。
  從一個頁面跳轉到另一個頁面的方式可以是通過GET請求中的鍵值對來實現;也可以通過使用隱藏的表單字段,就像是一個標識符,找得到這個標識符就顯示這個頁面。這些變量和值由服務器託管,因爲這些信息必須嵌入到新生成的頁面中並返回給客戶端。
  另一個可以保持多個頁面連續瀏覽的方式是在客戶端保存這些數據,這就是引入cookie的原因。服務器向客戶端發送一個請求來保存 cookie,而不必用在返回的 Web 頁面中嵌入數據的方法來保持數據。cookie 連接到最初服務器的主域上(這樣一個服務器就不能設置或者覆蓋其他 Web 站點中的 cookie),並且有一定的存儲期限(因此瀏覽器不會堆滿 cookie)。

cookie 和文件上傳

. 接下來的例子展示了cookie和文件上傳,當第一次登錄網頁,沒有緩存,表單中的輸入框都是空的,生成過結果頁面後,腳本設置了cookie,緩存在瀏覽器中,當再次回到表單頁面的時候,會自動填入相應的值:

import cgi
from urllib.parse import quote,unquote
import os
import io

class AdvCGI(object):
    header = 'Content-Type: text/html\n\n'
    url = "/cgi-bin/advcgi.py"

    formhtml = '''<html><head><tltle>
    Advanced CGI demon</title></head>
    <body><h2>Advanced CGI Demo Form:</h2>
    <form method = post action = "%s" enctype = "multipart/form-data">
    <h3>my cookie setting</h3>
    <li><code><b>CPPuser = %s</b></code>
    <h3>enter cookie value:<br>
    <input name = cookie value = %s> (<i>optional</i>)</h3>
    <h3>enter your name:<br>
    <input name = person value = %s> (<i>required</i>)</h3>
    <h3>what languages can you program in? (<i>at least one required</i>)</h3>
    %s
    <h3>enter file to upload <small>(max size 4K)</samll></h3>
    <input type = file name = upfile value = "%s" size = 45>
    <p><input type = submit>
    </form></body></html>
    '''

    langset = ('Python','C','C++','Ruby','Java','PHP')
    langitem = '<input type = checkbox name = lang value = "%s" %s>%s\n'

    # 從客戶端(瀏覽器)讀取cookie,這個方法只會被showform方法調用
    def getcookie(self):
        if 'HTTP_COOKIE' in os.environ:
            #使用HTTP_COOKIE這個環境變量訪問cookie
            cookies = [x.strip() for x in os.environ['HTTP_COOKIE'].split(';')]
            for eachCookie in cookies:
                if len(eachCookie)>6 and eachCookie[:3]=='CPP':
                    tag = eachCookie[3:7]
                    try:
                        self.cookies[tag] = eval(unquote(eachCookie[8:]))
                    except:
                        self.cookies[tag] = unquote(eachCookie[8:])
            if 'info' not in self.cookies:
                self.cookies['info'] = ''
            if 'user' not in self.cookies:
                self.cookies['user'] = ''
        else:
            self.cookies['info'] = self.cookies['user'] = ''

        if self.cookies['info'] != '':
            self.who,langStr,self.fn = self.cookies['info'].split(':')
            self.langs = langStr.split(',')
        else:
            self.who = self.fn = ''
            self.langs = ['Python']

    #用於顯示初始界面
    def showForm(self):
        self.getcookie()
        #放置複選框
        langStr = []
        for eachlang in AdvCGI.langset:
            langStr.append(AdvCGI.langitem % (eachlang,'CHECKED' if eachlang in self.langs else '',eachlang))

        if not ('user' in self.cookies and self.cookies['user']):
            cookStatus = '<i>(cookie has not been set yet)</i>'
            userCook = ''
        else:
            userCook = cookStatus = self.cookies['user']
        print('%s%s' % (AdvCGI.header,AdvCGI.formhtml % (AdvCGI.url,cookStatus,
                                                         userCook,self.who,
                                                         ''.join(langStr),self.fn)))

    #用於錯誤反饋
    errhtml = '''html><head><tltle>
    Advanced CGI demon</title></head>
    <body><h3>Error</h3>
    <b>%s</b><p>
    <form><input type = button value = Back
    ONCLICK = "window.history.back()"></form>
    </body></html>
    '''

    def showErr(self):
        print(AdvCGI.header + AdvCGI.errhtml % self.err)

    #用於生成結果信息頁
    reshtml = '''<html><head><tltle>
    Advanced CGI demon</title></head>
    <h3>your cookies value is: <b>%s</b></h3>
    <h3>your name is: <b>%s</b></h3>
    <h3>your can program in the fallowing languages:</h3>
    <ul>%s</ul>
    <h3>your uoloaded file...<br>
    name:<i>%s</i><br>
    contents:</h3>
    <pre>%s</pre>
    Click <a href = "%s"><b>here</b></a>to return to form
    </body></html>
    '''

	#這裏設置了cookies,還加上了CPP前綴,和get那裏是對應的
    def setcookie(self):
        for eachcookie in self.cookies.keys():
            print('Set-Cookie: CPP%s=%s;path=/' % \
                  (eachcookie,quote(self.cookies[eachcookie])))

    def doResult(self):
        MAXBYTES = 4096
        langlist = ''.join('<li>%s<br>' % eachlang for eachlang in self.langs)
        filedata = self.fp.read(MAXBYTES)
        if len(filedata) == MAXBYTES and f.read():
            filedata = '%s%s' % (filedata,'... <b><i>(file truncated due to size)</i></b>')
        self.fp.close()
        if filedata == '':
            filedata = '<b><i>(file not given or upload error)</i></b>'
        filename = self.fn

        if not ('user' in self.cookies and self.cookies['user']):
            cookStatus = '<i>(cookie has not been set yet)</i>'
            userCook = ''
        else:
            userCook = cookStatus = self.cookies['user']

        self.cookies['info'] = ':'.join((self.who,','.join(self.langs),filename))
        self.setcookie()

        print('%s%s' % (AdvCGI.header,AdvCGI.reshtml % (cookStatus,self.who,langlist,
                                                        filename,filedata,AdvCGI.url)))

    #決定跳轉到哪一個頁面
    def go(self):
        self.cookies = {}
        self.err = ''
        form = cgi.FieldStorage()
        if not form.keys():
            self.showForm()
            return
        if 'person' in form:
            self.who = form['person'].value.strip().title()
            if self.who == '':
                self.err = 'your name is required.(blank)'
        else:
            self.err = 'your name is required.(miss)'

        self.cookies['user'] = unquote(form['cookie'].value.strip()) if 'cookie' in form else ''

        if 'lang' in form:
            langData = form['lang']
            #isinstance() 函數來判斷一個對象是否是一個已知的類型
            if isinstance(langData,list):
                self.langs = [eachLang.value for eachLang in langData]
            else:
                self.langs = [langData.value]
        else:
            self.err = 'at least one language required'

        if 'upfile' in form:
            upfile = form['upfile']
            #or 表示從左到右掃描,返回第一個爲真的表達式值,無真值則返回最後一個表達式值。
            self.fn = upfile.filename or ''
            if upfile.file:
                self.fp = upfile.file
            else:
                self.fp = io.StringIO('(no data)')
        else:
            self.fp = io.StringIO('(no file)')
            self.fn = ''

        if not self.err:
            self.doResult()
        else:
            self.showErr()

if __name__ == '__main__':
    page = AdvCGI()
    page.go()

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章