是Include.jsp文件
<!-- this is the Include.jsp -->
<%@ page contentType="text/html; charset=GB2312" %>
<%@ page language="java" %>
<HTML>
<HEAD>
<TITLE>動態加載文件</TITLE>
</HEAD>
<BODY>
<CENTER>
<FONT SIZE = 10 COLOR = blue>動態加載文件</FONT>
</CENTER>
<br>
<HR>
<br>
<font size=5>
<!-- 用jsp:include指令動態加載文件 -->
<jsp:include page="jspInsert.jsp">
<jsp:param name="name" value="jsp:include"/>
<jsp:param name="file" value="jspInsert.jsp"/>
</jsp:include>
</font>
</BODY>
</HTML>
下面是jspInsert.jsp文件
<HTML>
<BODY>
您好!這里我們用到了
<Font Color=Blue>
<%= request.getParameter("name")%>
</Font>
指令!
<BR>
我們在這里加載了文件:
<Font Color=Blue>
<%= request.getParameter("file")%>
</Font>。<br>
</HTML>
</BODY>
么是 CGI?
公共網關接口(CGI),是一套標準,定義了信息是如何在 Web 服務器和客戶端腳本之間進行交換的。
CGI 規范目前是由 NCSA 維護的,NCSA 定義 CGI 如下:
公共網關接口(CGI),是一種用于外部網關程序與信息服務器(如 HTTP 服務器)對接的接口標準。
目前的版本是 CGI/1.1,CGI/1.2 版本正在推進中。
Web 瀏覽
為了更好地了解 CGI 的概念,讓我們點擊一個超鏈接,瀏覽一個特定的網頁或 URL,看看會發生什么。
您的瀏覽器聯系上 HTTP Web 服務器,并請求 URL,即文件名。
Web 服務器將解析 URL,并查找文件名。如果找到請求的文件,Web 服務器會把文件發送回瀏覽器,否則發送一條錯誤消息,表明您請求了一個錯誤的文件。
Web 瀏覽器從 Web 服務器獲取響應,并根據接收到的響應來顯示文件或錯誤消息。
然而,以這種方式搭建起來的 HTTP 服務器,不管何時請求目錄中的某個文件,HTTP 服務器發送回來的不是該文件,而是以程序形式執行,并把執行產生的輸出發送回瀏覽器顯示出來。
公共網關接口(CGI),是使得應用程序(稱為 CGI 程序或 CGI 腳本)能夠與 Web 服務器以及客戶端進行交互的標準協議。這些 CGI 程序可以用 Python、PERL、Shell、C 或 C++ 等進行編寫。
CGI 架構圖
下圖演示了 CGI 的架構:
Web 服務器配置
在您進行 CGI 編程之前,請確保您的 Web 服務器支持 CGI,并已配置成可以處理 CGI 程序。所有由 HTTP 服務器執行的 CGI 程序,都必須在預配置的目錄中。該目錄稱為 CGI 目錄,按照慣例命名為 /var/www/cgi-bin。雖然 CGI 文件是 C++ 可執行文件,但是按照慣例它的擴展名是 .cgi。
默認情況下,Apache Web 服務器會配置在 /var/www/cgi-bin 中運行 CGI 程序。如果您想指定其他目錄來運行 CGI 腳本,您可以在 httpd.conf 文件中修改以下部分:
<Directory "/var/www/cgi-bin"> AllowOverride None Options ExecCGI Order allow,deny Allow from all</Directory><Directory "/var/www/cgi-bin">Options All</Directory>
在這里,我們假設已經配置好 Web 服務器并能成功運行,你可以運行任意的 CGI 程序,比如 Perl 或 Shell 等。
第一個 CGI 程序
請看下面的 C++ 程序:
實例
#include<iostream>usingnamespacestd; intmain(){cout << "Content-type:text/html\r\n\r\n"; cout << "<html>\n"; cout << "<head>\n"; cout << "<title>Hello World - 第一個 CGI 程序</title>\n"; cout << "</head>\n"; cout << "<body>\n"; cout << "<h2>Hello World! 這是我的第一個 CGI 程序</h2>\n"; cout << "</body>\n"; cout << "</html>\n"; return0;}
編譯上面的代碼,把可執行文件命名為 cplusplus.cgi,并把這個文件保存在 /var/www/cgi-bin 目錄中。在運行 CGI 程序之前,請使用 chmod 755 cplusplus.cgi UNIX 命令來修改文件模式,確保文件可執行。訪問可執行文件,您會看到下面的輸出:
Hello World! 這是我的第一個 CGI 程序
上面的 C++ 程序是一個簡單的程序,把它的輸出寫在 STDOUT 文件上,即顯示在屏幕上。在這里,值得注意一點,第一行輸出Content-type:text/html\r\n\r\n。這一行發送回瀏覽器,并指定要顯示在瀏覽器窗口上的內容類型。您必須理解 CGI 的基本概念,這樣才能進一步使用 Python 編寫更多復雜的 CGI 程序。C++ CGI 程序可以與任何其他外部的系統(如 RDBMS)進行交互。
HTTP 頭信息
行 Content-type:text/html\r\n\r\n 是 HTTP 頭信息的組成部分,它被發送到瀏覽器,以便更好地理解頁面內容。HTTP 頭信息的形式如下:
HTTP 字段名稱: 字段內容例如Content-type: text/html\r\n\r\n
還有一些其他的重要的 HTTP 頭信息,這些在您的 CGI 編程中都會經常被用到。
頭信息 | 描述 |
---|---|
Content-type: | MIME 字符串,定義返回的文件格式。例如 Content-type:text/html。 |
Expires: Date | 信息變成無效的日期。瀏覽器使用它來判斷一個頁面何時需要刷新。一個有效的日期字符串的格式應為 01 Jan 1998 12:00:00 GMT。 |
Location: URL | 這個 URL 是指應該返回的 URL,而不是請求的 URL。你可以使用它來重定向一個請求到任意的文件。 |
Last-modified: Date | 資源的最后修改日期。 |
Content-length: N | 要返回的數據的長度,以字節為單位。瀏覽器使用這個值來表示一個文件的預計下載時間。 |
Set-Cookie: String | 通過 string 設置 cookie。 |
CGI 環境變量
所有的 CGI 程序都可以訪問下列的環境變量。這些變量在編寫 CGI 程序時扮演了非常重要的角色。
變量名 | 描述 |
---|---|
CONTENT_TYPE | 內容的數據類型。當客戶端向服務器發送附加內容時使用。例如,文件上傳等功能。 |
CONTENT_LENGTH | 查詢的信息長度。只對 POST 請求可用。 |
HTTP_COOKIE | 以鍵 & 值對的形式返回設置的 cookies。 |
HTTP_USER_AGENT | 用戶代理請求標頭字段,遞交用戶發起請求的有關信息,包含了瀏覽器的名稱、版本和其他平臺性的附加信息。 |
PATH_INFO | CGI 腳本的路徑。 |
QUERY_STRING | 通過 GET 方法發送請求時的 URL 編碼信息,包含 URL 中問號后面的參數。 |
REMOTE_ADDR | 發出請求的遠程主機的 IP 地址。這在日志記錄和認證時是非常有用的。 |
REMOTE_HOST | 發出請求的主機的完全限定名稱。如果此信息不可用,則可以用 REMOTE_ADDR 來獲取 IP 地址。 |
REQUEST_METHOD | 用于發出請求的方法。最常見的方法是 GET 和 POST。 |
SCRIPT_FILENAME | CGI 腳本的完整路徑。 |
SCRIPT_NAME | CGI 腳本的名稱。 |
SERVER_NAME | 服務器的主機名或 IP 地址。 |
SERVER_SOFTWARE | 服務器上運行的軟件的名稱和版本。 |
下面的 CGI 程序列出了所有的 CGI 變量。
實例
#include<iostream>#include<stdlib.h>usingnamespacestd; conststringENV[24] = {"COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE", "HTTP_ACCEPT", "HTTP_ACCEPT_ENCODING", "HTTP_ACCEPT_LANGUAGE", "HTTP_CONNECTION", "HTTP_HOST", "HTTP_USER_AGENT", "PATH", "QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT", "REQUEST_METHOD", "REQUEST_URI", "SCRIPT_FILENAME", "SCRIPT_NAME", "SERVER_ADDR", "SERVER_ADMIN", "SERVER_NAME","SERVER_PORT","SERVER_PROTOCOL", "SERVER_SIGNATURE","SERVER_SOFTWARE"}; intmain(){cout << "Content-type:text/html\r\n\r\n"; cout << "<html>\n"; cout << "<head>\n"; cout << "<title>CGI 環境變量</title>\n"; cout << "</head>\n"; cout << "<body>\n"; cout << "<table border = \"0\" cellspacing = \"2\">"; for(inti = 0; i < 24; i++ ){cout << "<tr><td>" << ENV[i] << "</td><td>"; // 嘗試檢索環境變量的值char *value = getenv(ENV[i].c_str()); if(value != 0){cout << value; }else{cout << "環境變量不存在。"; }cout << "</td></tr>\n"; }cout << "</table><\n"; cout << "</body>\n"; cout << "</html>\n"; return0;}
C++ CGI 庫
在真實的實例中,您需要通過 CGI 程序執行許多操作。這里有一個專為 C++ 程序而編寫的 CGI 庫,我們可以從ftp://ftp.gnu.org/gnu/cgicc/ 上下載這個 CGI 庫,并按照下面的步驟安裝庫:
$tar xzf cgicc-X.X.X.tar.gz$cd cgicc-X.X.X/ $./configure --prefix=/usr$make$make install
您可以點擊 C++ CGI Lib Documentation,查看相關的庫文檔。
GET 和 POST 方法
您可能有遇到過這樣的情況,當您需要從瀏覽器傳遞一些信息到 Web 服務器,最后再傳到 CGI 程序。通常瀏覽器會使用兩種方法把這個信息傳到 Web 服務器,分別是 GET 和 POST 方法。
使用 GET 方法傳遞信息
GET 方法發送已編碼的用戶信息追加到頁面請求中。頁面和已編碼信息通過 ? 字符分隔開,如下所示:
http://www.test.com/cgi-bin/cpp.cgi?key1=value1&key2=value2
GET 方法是默認的從瀏覽器向 Web 服務器傳信息的方法,它會在瀏覽器的地址欄中生成一串很長的字符串。當您向服務器傳密碼或其他一些敏感信息時,不要使用 GET 方法。GET 方法有大小限制,在一個請求字符串中最多可以傳 1024 個字符。
當使用 GET 方法時,是使用 QUERY_STRING http 頭來傳遞信息,在 CGI 程序中可使用 QUERY_STRING 環境變量來訪問。
您可以通過在 URL 后跟上簡單連接的鍵值對,也可以通過使用 HTML <FORM> 標簽的 GET 方法來傳信息。
簡單的 URL 實例:Get 方法
下面是一個簡單的 URL,使用 GET 方法傳遞兩個值給 hello_get.py 程序。
/cgi-bin/cpp_get.cgi?first_name=ZARA&last_name=ALI
下面的實例生成 cpp_get.cgi CGI 程序,用于處理 Web 瀏覽器給出的輸入。通過使用 C++ CGI 庫,可以很容易地訪問傳遞的信息:
實例
#include<iostream>#include<vector>#include<string>#include<stdio.h>#include<stdlib.h>#include<cgicc/CgiDefs.h>#include<cgicc/Cgicc.h>#include<cgicc/HTTPHTMLHeader.h>#include<cgicc/HTMLClasses.h>usingnamespacestd;usingnamespacecgicc; intmain(){CgiccformData; cout << "Content-type:text/html\r\n\r\n"; cout << "<html>\n"; cout << "<head>\n"; cout << "<title>使用 GET 和 POST 方法</title>\n"; cout << "</head>\n"; cout << "<body>\n"; form_iteratorfi = formData.getElement("first_name"); if( !fi->isEmpty() && fi != (*formData).end()){cout << "名:" << **fi << endl; }else{cout << "No text entered for first name" << endl; }cout << "<br/>\n"; fi = formData.getElement("last_name"); if( !fi->isEmpty() &&fi != (*formData).end()){cout << "姓:" << **fi << endl; }else{cout << "No text entered for last name" << endl; }cout << "<br/>\n"; cout << "</body>\n"; cout << "</html>\n"; return0;}
現在,編譯上面的程序,如下所示:
$g++ -o cpp_get.cgi cpp_get.cpp -lcgicc
生成 cpp_get.cgi,并把它放在 CGI 目錄中,并嘗試使用下面的鏈接進行訪問:
/cgi-bin/cpp_get.cgi?first_name=ZARA&last_name=ALI
這會產生以下結果:
名:ZARA姓:ALI
簡單的表單實例:GET 方法
下面是一個簡單的實例,使用 HTML 表單和提交按鈕傳遞兩個值。我們將使用相同的 CGI 腳本 cpp_get.cgi 來處理輸入。
<formaction="/cgi-bin/cpp_get.cgi"method="get">名:<inputtype="text"name="first_name"><br/> 姓:<inputtype="text"name="last_name"/><inputtype="submit"value="提交"/></form>
下面是上述表單的實際輸出,請輸入名和姓,然后點擊提交按鈕查看結果。
使用 POST 方法傳遞信息
一個更可靠的向 CGI 程序傳遞信息的方法是 POST 方法。這種方法打包信息的方式與 GET 方法相同,不同的是,它不是把信息以文本字符串形式放在 URL 中的 ? 之后進行傳遞,而是把它以單獨的消息形式進行傳遞。該消息是以標準輸入的形式傳給 CGI 腳本的。
我們同樣使用 cpp_get.cgi 程序來處理 POST 方法。讓我們以同樣的例子,通過使用 HTML 表單和提交按鈕來傳遞兩個值,只不過這次我們使用的不是 GET 方法,而是 POST 方法,如下所示:
<formaction="/cgi-bin/cpp_get.cgi"method="post">名:<inputtype="text"name="first_name"><br/>姓:<inputtype="text"name="last_name"/><inputtype="submit"value="提交"/></form>
向 CGI 程序傳遞復選框數據
當需要選擇多個選項時,我們使用復選框。
下面的 HTML 代碼實例是一個帶有兩個復選框的表單:
<formaction="/cgi-bin/cpp_checkbox.cgi"method="POST"target="_blank"><inputtype="checkbox"name="maths"value="on"/> 數學<inputtype="checkbox"name="physics"value="on"/> 物理<inputtype="submit"value="選擇學科"/></form>
下面的 C++ 程序會生成 cpp_checkbox.cgi 腳本,用于處理 Web 瀏覽器通過復選框給出的輸入。
實例
#include<iostream>#include<vector>#include<string>#include<stdio.h>#include<stdlib.h>#include<cgicc/CgiDefs.h>#include<cgicc/Cgicc.h>#include<cgicc/HTTPHTMLHeader.h>#include<cgicc/HTMLClasses.h>usingnamespacestd;usingnamespacecgicc; intmain(){CgiccformData; boolmaths_flag, physics_flag; cout << "Content-type:text/html\r\n\r\n"; cout << "<html>\n"; cout << "<head>\n"; cout << "<title>向 CGI 程序傳遞復選框數據</title>\n"; cout << "</head>\n"; cout << "<body>\n"; maths_flag = formData.queryCheckbox("maths"); if(maths_flag){cout << "Maths Flag: ON " << endl; }else{cout << "Maths Flag: OFF " << endl; }cout << "<br/>\n"; physics_flag = formData.queryCheckbox("physics"); if(physics_flag){cout << "Physics Flag: ON " << endl; }else{cout << "Physics Flag: OFF " << endl; }cout << "<br/>\n"; cout << "</body>\n"; cout << "</html>\n"; return0;}
向 CGI 程序傳遞單選按鈕數據
當只需要選擇一個選項時,我們使用單選按鈕。
下面的 HTML 代碼實例是一個帶有兩個單選按鈕的表單:
<formaction="/cgi-bin/cpp_radiobutton.cgi"method="post"target="_blank"><inputtype="radio"name="subject"value="maths"checked="checked"/> 數學 <inputtype="radio"name="subject"value="physics"/> 物理<inputtype="submit"value="選擇學科"/></form>
下面的 C++ 程序會生成 cpp_radiobutton.cgi 腳本,用于處理 Web 瀏覽器通過單選按鈕給出的輸入。
實例
#include<iostream>#include<vector>#include<string>#include<stdio.h>#include<stdlib.h>#include<cgicc/CgiDefs.h>#include<cgicc/Cgicc.h>#include<cgicc/HTTPHTMLHeader.h>#include<cgicc/HTMLClasses.h>usingnamespacestd;usingnamespacecgicc; intmain(){CgiccformData; cout << "Content-type:text/html\r\n\r\n"; cout << "<html>\n"; cout << "<head>\n"; cout << "<title>向 CGI 程序傳遞單選按鈕數據</title>\n"; cout << "</head>\n"; cout << "<body>\n"; form_iteratorfi = formData.getElement("subject"); if( !fi->isEmpty() && fi != (*formData).end()){cout << "Radio box selected: " << **fi << endl; }cout << "<br/>\n"; cout << "</body>\n"; cout << "</html>\n"; return0;}
向 CGI 程序傳遞文本區域數據
當需要向 CGI 程序傳遞多行文本時,我們使用 TEXTAREA 元素。
下面的 HTML 代碼實例是一個帶有 TEXTAREA 框的表單:
<formaction="/cgi-bin/cpp_textarea.cgi"method="post"target="_blank"><textareaname="textcontent"cols="40"rows="4">請在這里輸入文本...</textarea><inputtype="submit"value="提交"/></form>
下面的 C++ 程序會生成 cpp_textarea.cgi 腳本,用于處理 Web 瀏覽器通過文本區域給出的輸入。
實例
#include<iostream>#include<vector>#include<string>#include<stdio.h>#include<stdlib.h>#include<cgicc/CgiDefs.h>#include<cgicc/Cgicc.h>#include<cgicc/HTTPHTMLHeader.h>#include<cgicc/HTMLClasses.h>usingnamespacestd;usingnamespacecgicc; intmain(){CgiccformData; cout << "Content-type:text/html\r\n\r\n"; cout << "<html>\n"; cout << "<head>\n"; cout << "<title>向 CGI 程序傳遞文本區域數據</title>\n"; cout << "</head>\n"; cout << "<body>\n"; form_iteratorfi = formData.getElement("textcontent"); if( !fi->isEmpty() && fi != (*formData).end()){cout << "Text Content: " << **fi << endl; }else{cout << "No text entered" << endl; }cout << "<br/>\n"; cout << "</body>\n"; cout << "</html>\n"; return0;}
向 CGI 程序傳遞下拉框數據
當有多個選項可用,但只能選擇一個或兩個選項時,我們使用下拉框。
下面的 HTML 代碼實例是一個帶有下拉框的表單:
<formaction="/cgi-bin/cpp_dropdown.cgi"method="post"target="_blank"><selectname="dropdown"><optionvalue="Maths"selected>數學</option><optionvalue="Physics">物理</option></select><inputtype="submit"value="提交"/></form>
下面的 C++ 程序會生成 cpp_dropdown.cgi 腳本,用于處理 Web 瀏覽器通過下拉框給出的輸入。
實例
#include<iostream>#include<vector>#include<string>#include<stdio.h>#include<stdlib.h>#include<cgicc/CgiDefs.h>#include<cgicc/Cgicc.h>#include<cgicc/HTTPHTMLHeader.h>#include<cgicc/HTMLClasses.h>usingnamespacestd;usingnamespacecgicc; intmain(){CgiccformData; cout << "Content-type:text/html\r\n\r\n"; cout << "<html>\n"; cout << "<head>\n"; cout << "<title>向 CGI 程序傳遞下拉框數據</title>\n"; cout << "</head>\n"; cout << "<body>\n"; form_iteratorfi = formData.getElement("dropdown"); if( !fi->isEmpty() && fi != (*formData).end()){cout << "Value Selected: " << **fi << endl; }cout << "<br/>\n"; cout << "</body>\n"; cout << "</html>\n"; return0;}
在 CGI 中使用 Cookies
HTTP 協議是一種無狀態的協議。但對于一個商業網站,它需要在不同頁面間保持會話信息。例如,一個用戶在完成多個頁面的步驟之后結束注冊。但是,如何在所有網頁中保持用戶的會話信息。
在許多情況下,使用 cookies 是記憶和跟蹤有關用戶喜好、購買、傭金以及其他為追求更好的游客體驗或網站統計所需信息的最有效的方法。
它是如何工作的
服務器以 cookie 的形式向訪客的瀏覽器發送一些數據。如果瀏覽器接受了 cookie,則 cookie 會以純文本記錄的形式存儲在訪客的硬盤上。現在,當訪客訪問網站上的另一個頁面時,會檢索 cookie。一旦找到 cookie,服務器就知道存儲了什么。
cookie 是一種純文本的數據記錄,帶有 5 個可變長度的字段:
Expires : cookie 的過期日期。如果此字段留空,cookie 會在訪客退出瀏覽器時過期。
Domain : 網站的域名。
Path : 設置 cookie 的目錄或網頁的路徑。如果您想從任意的目錄或網頁檢索 cookie,此字段可以留空。
Secure : 如果此字段包含單詞 "secure",那么 cookie 只能通過安全服務器進行檢索。如果此字段留空,則不存在該限制。
Name=Value : cookie 以鍵值對的形式被設置和獲取。
設置 Cookies
向瀏覽器發送 cookies 是非常簡單的。這些 cookies 會在 Content-type 字段之前,與 HTTP 頭一起被發送。假設您想設置 UserID 和 Password 為 cookies,設置 cookies 的步驟如下所示:
實例
#include<iostream>usingnamespacestd; intmain(){cout << "Set-Cookie:UserID=XYZ;\r\n"; cout << "Set-Cookie:Password=XYZ123;\r\n"; cout << "Set-Cookie:Domain=www.w3cschool.cc;\r\n"; cout << "Set-Cookie:Path=/perl;\n"; cout << "Content-type:text/html\r\n\r\n"; cout << "<html>\n"; cout << "<head>\n"; cout << "<title>CGI 中的 Cookies</title>\n"; cout << "</head>\n"; cout << "<body>\n"; cout << "設置 cookies" << endl; cout << "<br/>\n"; cout << "</body>\n"; cout << "</html>\n"; return0;}
從這個實例中,我們了解了如何設置 cookies。我們使用 Set-Cookie HTTP 頭來設置 cookies。
在這里,有一些設置 cookies 的屬性是可選的,比如 Expires、Domain 和 Path。值得注意的是,cookies 是在發送行"Content-type:text/html\r\n\r\n 之前被設置的。
編譯上面的程序,生成 setcookies.cgi,并嘗試使用下面的鏈接設置 cookies。它會在您的計算機上設置四個 cookies:
/cgi-bin/setcookies.cgi
獲取 Cookies
檢索所有設置的 cookies 是非常簡單的。cookies 被存儲在 CGI 環境變量 HTTP_COOKIE 中,且它們的形式如下:
key1=value1;key2=value2;key3=value3....
下面的實例演示了如何獲取 cookies。
實例
#include<iostream>#include<vector>#include<string>#include<stdio.h>#include<stdlib.h>#include<cgicc/CgiDefs.h>#include<cgicc/Cgicc.h>#include<cgicc/HTTPHTMLHeader.h>#include<cgicc/HTMLClasses.h>usingnamespacestd;usingnamespacecgicc; intmain(){Cgicccgi; const_cookie_iteratorcci; cout << "Content-type:text/html\r\n\r\n"; cout << "<html>\n"; cout << "<head>\n"; cout << "<title>CGI 中的 Cookies</title>\n"; cout << "</head>\n"; cout << "<body>\n"; cout << "<table border = \"0\" cellspacing = \"2\">"; // 獲取環境變量constCgiEnvironment& env = cgi.getEnvironment(); for(cci = env.getCookieList().begin(); cci != env.getCookieList().end(); ++cci){cout << "<tr><td>" << cci->getName() << "</td><td>"; cout << cci->getValue(); cout << "</td></tr>\n"; }cout << "</table><\n"; cout << "<br/>\n"; cout << "</body>\n"; cout << "</html>\n"; return0;}
現在,編譯上面的程序,生成 getcookies.cgi,并嘗試使用下面的鏈接獲取您的計算機上所有可用的 cookies:
/cgi-bin/getcookies.cgi
這會產生一個列表,顯示了上一節中設置的四個 cookies 以及您的計算機上所有其他的 cookies:
UserID XYZPassword XYZ123Domain www.w3cschool.ccPath /perl
文件上傳實例
為了上傳一個文件,HTML 表單必須把 enctype 屬性設置為 multipart/form-data。帶有文件類型的 input 標簽會創建一個 "Browse" 按鈕。
<html><body><formenctype="multipart/form-data"action="/cgi-bin/cpp_uploadfile.cgi"method="post"><p>文件:<inputtype="file"name="userfile"/></p><p><inputtype="submit"value="上傳"/></p></form></body></html>
這段代碼的結果是下面的表單:
文件:
注意:上面的實例已經故意禁用了保存上傳的文件在我們的服務器上。您可以在自己的服務器上嘗試上面的代碼。
下面是用于處理文件上傳的腳本 cpp_uploadfile.cpp:
實例
#include<iostream>#include<vector>#include<string>#include<stdio.h>#include<stdlib.h>#include<cgicc/CgiDefs.h>#include<cgicc/Cgicc.h>#include<cgicc/HTTPHTMLHeader.h>#include<cgicc/HTMLClasses.h>usingnamespacestd;usingnamespacecgicc; intmain(){Cgicccgi; cout << "Content-type:text/html\r\n\r\n"; cout << "<html>\n"; cout << "<head>\n"; cout << "<title>CGI 中的文件上傳</title>\n"; cout << "</head>\n"; cout << "<body>\n"; // 獲取要被上傳的文件列表const_file_iteratorfile = cgi.getFile("userfile"); if(file != cgi.getFiles().end()){// 在 cout 中發送數據類型cout << HTTPContentHeader(file->getDataType()); // 在 cout 中寫入內容file->writeToStream(cout); }cout << "<文件上傳成功>\n"; cout << "</body>\n"; cout << "</html>\n"; return0;}
上面的實例是在 cout 流中寫入內容,但您可以打開文件流,并把上傳的文件內容保存在目標位置的某個文件中。
譯自: https://opensource.com/article/18/10/book-to-website-epub-using-pandoc
作者: Kiko Fernandez-reyes
譯者: jlztan
通過 Markdown 和 Pandoc,可以做到編寫一次,發布兩次。
Pandoc 是一個命令行工具,用于將文件從一種標記語言轉換為另一種標記語言。在我 對 Pandoc 的簡介 一文中,我演示了如何把 Markdown 編寫的文本轉換為網頁、幻燈片和 PDF。
在這篇后續文章中,我將深入探討 Pandoc ,展示如何從同一個 Markdown 源文件生成網頁和 ePub 格式的電子書。我將使用我即將發布的電子書《 面向對象思想的 GRASP 原則 》為例進行講解,這本電子書正是通過以下過程創建的。
首先,我將解釋這本書使用的文件結構,然后介紹如何使用 Pandoc 生成網頁并將其部署在 GitHub 上;最后,我演示了如何生成對應的 ePub 格式電子書。
你可以在我的 GitHub 倉庫 Programming Fight Club 中找到相應代碼。
我用 Markdown 語法完成了所有的寫作,你也可以使用 HTML 標記,但是當 Pandoc 將 Markdown 轉換為 ePub 文檔時,引入的 HTML 標記越多,出現問題的風險就越高。我的書按照每章一個文件的形式進行組織,用 Markdown 的 H1 標記(#)聲明每章的標題。你也可以在每個文件中放置多個章節,但將它們放在單獨的文件中可以更輕松地查找內容并在以后進行更新。
元信息遵循類似的模式,每種輸出格式都有自己的元信息文件。元信息文件定義有關文檔的信息,例如要添加到 HTML 中的文本或 ePub 的許可證。我將所有 Markdown 文檔存儲在名為 parts 的文件夾中(這對于用來生成網頁和 ePub 的 Makefile 非常重要)。下面以一個例子進行說明,讓我們看一下目錄,前言和關于本書(分為 toc.md、preface.md 和 about.md 三個文件)這三部分,為清楚起見,我們將省略其余的章節。
關于本書這部分內容的開頭部分類似:
# About this book {-}
## Who should read this book {-}
Before creating a complex software system one needs to create a solid foundation.
General Responsibility Assignment Software Principles (GRASP) are guidelines to assign
responsibilities to software classes in object-oriented programming.
每一章完成后,下一步就是添加元信息來設置網頁和 ePub 的格式。
我創建的網頁的元信息文件(web-metadata.yaml)是一個簡單的 YAML 文件,其中包含 <head> 標簽中的作者、標題、和版權等信息,以及 HTML 文件中開頭和結尾的內容。
我建議(至少)包括 web-metadata.yaml 文件中的以下字段:
---
title: <a href="/grasp-principles/toc/">GRASP principles for the Object-oriented mind</a>
author: Kiko Fernandez-Reyes
rights: 2017 Kiko Fernandez-Reyes, CC-BY-NC-SA 4.0 International
header-includes:
- |
```{=html}
<link rel="stylesheet">
<link rel="stylesheet">
```
include-before:
- |
```{=html}
<p>If you like this book, please consider
spreading the word or
<a >
buying me a coffee
</a>
</p>
```
include-after:
- |
```{=html}
<div class="footnotes">
<hr>
<div class="container">
<nav class="pagination" role="pagination">
<ul>
<p>
<span class="page-number">Designed with</span> ?? <span class="page-number"> from Uppsala, Sweden</span>
</p>
<p>
<a rel="license" ><img alt="Creative Commons License" style="border-width:0" src="http://m.jungjaehyung.com/uploadfile/2024/0807/20240807030249413.png" /></a>
</p>
</ul>
</nav>
</div>
</div>
```
---
下面幾個變量需要注意一下:
這些只是其中一部分可用的變量,查看 HTML 中的模板變量(我的文章 Pandoc簡介 中介紹了如何查看 LaTeX 的模版變量,查看 HTML 模版變量的過程是相同的)對其余變量進行了解。
網頁可以作為一個整體生成,這會產生一個包含所有內容的長頁面;也可以分成多章,我認為這樣會更容易閱讀。我將解釋如何將網頁劃分為多章,以便讀者不會被長網頁嚇到。
為了使網頁易于在 GitHub Pages 上部署,需要創建一個名為 docs 的根文件夾(這是 GitHub Pages 默認用于渲染網頁的根文件夾)。然后我們需要為 docs 下的每一章創建文件夾,將 HTML 內容放在各自的文件夾中,將文件內容放在名為 index.html 的文件中。
例如,about.md 文件將轉換成名為 index.html 的文件,該文件位于名為 about(about/index.html)的文件夾中。這樣,當用戶鍵入 http://<your-website.com>/about/ 時,文件夾中的 index.html 文件將顯示在其瀏覽器中。
下面的 Makefile 將執行上述所有操作:
# Your book files
DEPENDENCIES= toc preface about
# Placement of your HTML files
DOCS=docs
all: web
web: setup $(DEPENDENCIES)
@cp $(DOCS)/toc/index.html $(DOCS)
# Creation and copy of stylesheet and images into
# the assets folder. This is important to deploy the
# website to Github Pages.
setup:
@mkdir -p $(DOCS)
@cp -r assets $(DOCS)
# Creation of folder and index.html file on a
# per-chapter basis
$(DEPENDENCIES):
@mkdir -p $(DOCS)/$@
@pandoc -s --toc web-metadata.yaml parts/$@.md \
-c /assets/pandoc.css -o $(DOCS)/$@/index.html
clean:
@rm -rf $(DOCS)
.PHONY: all clean web setup
選項 - c /assets/pandoc.css 聲明要使用的 CSS 樣式表,它將從 /assets/pandoc.cs 中獲取。也就是說,在 <head> 標簽內,Pandoc 會添加這樣一行:
<link rel="stylesheet" href="/assets/pandoc.css">
使用下面的命令生成網頁:
make
根文件夾現在應該包含如下所示的文件結構:
.---parts
| |--- toc.md
| |--- preface.md
| |--- about.md
|
|---docs
|--- assets/
|--- index.html
|--- toc
| |--- index.html
|
|--- preface
| |--- index.html
|
|--- about
|--- index.html
通過以下步驟將網頁部署到 GitHub 上:
你可以在 GitHub Pages 的網站上獲得更多詳細信息。
我的書的網頁 便是通過上述過程生成的,可以在網頁上查看結果。
ePub 格式的元信息文件 epub-meta.yaml 和 HTML 元信息文件是類似的。主要區別在于 ePub 提供了其他模板變量,例如 publisher 和 cover-image 。ePub 格式圖書的樣式表可能與網頁所用的不同,在這里我使用一個名為 epub.css 的樣式表。
---
title: 'GRASP principles for the Object-oriented Mind'
publisher: 'Programming Language Fight Club'
author: Kiko Fernandez-Reyes
rights: 2017 Kiko Fernandez-Reyes, CC-BY-NC-SA 4.0 International
cover-image: assets/cover.png
stylesheet: assets/epub.css
...
將以下內容添加到之前的 Makefile 中:
epub:
@pandoc -s --toc epub-meta.yaml \
$(addprefix parts/, $(DEPENDENCIES:=.md)) -o $(DOCS)/assets/book.epub
用于產生 ePub 格式圖書的命令從 HTML 版本獲取所有依賴項(每章的名稱),向它們添加 Markdown 擴展,并在它們前面加上每一章的文件夾路徑,以便讓 Pandoc 知道如何進行處理。例如,如果 $(DEPENDENCIES 變量只包含 “前言” 和 “關于本書” 兩章,那么 Makefile 將會這樣調用:
@pandoc -s --toc epub-meta.yaml \
parts/preface.md parts/about.md -o $(DOCS)/assets/book.epub
Pandoc 將提取這兩章的內容,然后進行組合,最后生成 ePub 格式的電子書,并放在 Assets 文件夾中。
這是使用此過程創建 ePub 格式電子書的一個 示例 。
從 Markdown 文件創建網頁和 ePub 格式電子書的過程并不困難,但有很多細節需要注意。遵循以下大綱可能使你更容易使用 Pandoc。
via: https://opensource.com/article/18/10/book-to-website-epub-using-pandoc
作者: Kiko Fernandez-Reyes 選題: lujun9972 譯者: jlztan 校對: wxy
本文由 LCTT 原創編譯, Linux中國 榮譽推出
*請認真填寫需求信息,我們會在24小時內與您取得聯系。