php w3c

PHP 程式設計初探 - 上課教材

PHP 程式設計初探 > 課程內容 > 第 02 章 - 網頁表單設計

第 02 章 - 網頁表單設計

上次更新日期 2020/03/12

如果需要透過 PHP 讓使用者瀏覽器端與伺服器端的資料庫進行互動,那就必須設計表單。什麼是表單呢?例如,你總有用過 google 吧, 你在 google 上面輸入關鍵字,然後,google 根據你輸入的關鍵字,使用他的資料庫環境去比對,最終找出你想要瀏覽的網頁資料, 回傳到你的瀏覽器上~在一開始你輸入資料的那個畫面,那個動作就是表單的行為!另外,你不是可能會登入?可能會填密碼? 那些界面都是表單啦!

學習目標:

  1. 了解什麼是表單 (form)
  2. 了解 get 與 post 的傳輸方法
  3. 學習怎麼應用 input / textarea / select 等資料傳輸的方式
  4. 學習透過 PHP 將上述的資料以變數方法取得並應用。

2.1: 互動式網站:表單的製作

就如同我們要搜尋某些資料的時候,會前往 google 網站,或者是其他相關搜尋引擎一樣,我們必須要拿出『關鍵字』, 然後輸入到搜尋引擎網站提供的條列式框框內,按下 [enter] 或搜尋之後,我們所填寫的關鍵字就會被攜帶到搜尋引擎的伺服器, 透過伺服器端自己進行搜尋任務後,將搜尋到的結果以 HTML, CSS 或其他多媒體 (如 youtube) 的方式回傳到瀏覽器上, 這就是一個可以互動的網站流程。

要達成這個流程,有幾個基本步驟是得要進行的:

  • Server 要提供某種功能,讓使用者可以在瀏覽器上面輸入關鍵字,或者是『選擇』或者是『勾選』關鍵資料
  • Server 在使用者按下送出後,會將使用者在上一步驟進行的資料,以變數或某種方式取得這些關鍵資料
  • Server 在透過這些關鍵資料的判定後,進行某些預設的動作 (程式碼階段),然後將輸出的結果以 HTML 或某種多媒體方式,回傳給使用者的瀏覽器。 回傳的資料可能是同一個網頁,也可能是另一個新的網頁。

你會發現,幾乎都是 Server 要進行的任務,因此,這些動作我們也經常稱為伺服器端的程式語言 (Server Side Language),在台灣最常用的可能就是 PHP 以及 .NET 了。

  • 整體表單的製作

若你需要透過瀏覽器上傳資料到伺服器上,那麼網頁就得要有名為 form 的表單標籤。另外,上傳的資料主要有兩種方法,分別是:

  • get:利用字串方式傳送,資料量較小,沒有加密,字串長度被限制在 512bytes 內。
  • post:利用封包傳送模式,將資料打包成為封包狀態再傳送出去,除具有保密性之外,還可突破 512bytes 的限制。

此外,如同上面的說明,你上傳的資料是要給哪個檔案來處理?所以,一般來說,form 的常見的屬性有這些:

<form  name="表單名(可忽略)"  action="要將資料上傳到server端的哪個檔案處理"  method="get或post">
....
</form>
  • 常見的輸入資料,使用 input 與 type="text", type="submit"

大部分傳輸的資訊,主要是透過變數格式將資料上傳的。亦即你在網頁上面設計好變數名稱,讓使用者填寫後勾選變數內容,再將資料送上去。 因此,每個設計的按鈕或填寫的資訊中,都需要有個變數名字 (variable name) 來代表用戶所勾選的資訊

用來提供使用者輸入參數的標籤中,最常用的就是 input 這個標籤。這個標籤可用的類型非常多!在這個小節我們先拿 type="text" 來做說明。 當你使用了上述的類型,還必須要指定這個輸入資料的『變數名稱』才行。一般常見的屬性有:

  • input 屬性為 type="text" 時,常見的屬性設定:
    • name="var" :就是輸入變數名稱
    • value="content" :你可以提供一個『預設值』喔!就是打開瀏覽器預設幫你輸入好的一些資料
    • placeholder="顯示提示資訊" :跟 value 不一樣,這個值會顯示在框框內,但是當使用者輸入任何資料後,這些資訊就會消失。

如果你的 name 設定為 var,而使用者在框框內輸入 abc 時,那麼在 server 上就會有『 $var = "abc" 』的資料可用喔!

但是,資料總是需要送出吧!這時就需要 type="submit" 的使用了!

  • input 屬性為 type="submit" 時,常見的屬性設定:
    • value="按鈕上面顯示的文字"
例題 2.1-1:建立一個簡單的方塊式的表單,提供使用者單純輸入姓氏與名字的方框,並提供上傳按鈕即可
  1. 建立名為 /www/php/unit02-1-1.php 的檔案,並將 HTML 相關的資訊先整理好;
  2. 建立一個表單,且表單使用的上傳方式為 get,表單上傳的檔名為 unit02-1-1-get.php,表單的名稱為 myform
  3. 表單裡面建立一個名為 myname1 的 text 類型輸入框,且顯示『你的姓氏』資料,使用 placeholder 功能,在輸入框內預顯示『王』
  4. 表單裡面建立一個名為 myname2 的 text 類型輸入框,且顯示『你的名字』資料,使用 placeholder 功能,在輸入框內預顯示『小明』
  5. 表單裡面建立一個 submit 按鈕,文字顯示『開始上傳資料』
  6. 在 /www/php/index.php 加入這個程式的連結
完成的結果會有點像這樣: 第一個 input 類型的表單P

如上題的模樣,在你填寫了姓氏與名字之後,按下上傳,結果螢幕會出現找不到檔案,而且網址會變成有點像這樣:

第一個 input 類型的表單P

注意看,檔名會變成 unit02-1-1-get.php ,而且後面會加上前一章講到的變數設定模式在網址列上面,這就是 GET 的傳輸方式。 一般來說,真的,沒有重要資料的畫面才使用這種 GET 方式,否則,你的許多資料都會出現在網址列上面,相當可怕!要注意!要注意!

2.2: 轉碼功能函數與表單資料取得

從前面一章節的內容,我們會知道其實在 PHP 裡面,括號與引號帶有很重要的意義!很多時候,某些人士會想要攻擊你的系統, 這個時候,從網址列插入奇怪的攻擊碼,就可能會是一個可怕的後果~因此,我們要將『程式碼』轉成『一般文字』,這樣來處理, 對於你的系統會比較安全。

  • 轉碼的 function 設計

不過,如果重複的資料一直撰寫,就跟我們之前玩 CSS 的時候一樣,很難修改。因此,我們可以透過 PHP 的 include 方式, 來將各個轉碼功能呼叫進來,這樣就輕鬆很多!其實轉碼功能就是將 $_GET 以及 $_POST, $_REQUEST 等變數的內容, 若有出現各種奇怪的符號時,就轉成 HTML 的特殊編碼而已。例如底下的案例:

例題 2.2-1:建立轉碼功能的函式庫檔案
  1. 先建立一個新檔案,檔名就稱為 /www/php/functions.php,不需要任何內容,空檔案即可。因為這個檔案的重點是被呼叫來的, 類似 CSS 的引入檔,因此,不需要有 HTML 的版面編碼! ;
  2. 將底下的資料寫入 functions.php 當中:
    <?php
    // 可以避免你的系統被 XSS 攻擊的基礎防禦,透過 HTML 字元編碼轉碼而來
    $_GET      && SafeFilter($_GET);
    $_POST     && SafeFilter($_POST);
    $_REQUEST  && SafeFilter($_REQUEST);
    $_COOKIE   && SafeFilter($_COOKIE);
    
    function SafeFilter (&$arr) {
        if (is_array($arr)) {
            foreach ($arr as $key => $value) {
                if (!is_array($value)) {
                    if (!get_magic_quotes_gpc()) {
                        $value = addslashes($value);
                    }
                    $arr[$key] = htmlspecialchars($value,ENT_QUOTES); 
                } else {
                    SafeFilter($arr[$key]);
                }
            }
        }
    }
    ?>
    
    上述的資料目前你看不懂沒關係,先呼叫,未來講到函數 (function) 時,再回頭來看看,你就會知道了!

你無須進行任何查閱,反正裡面也沒有內容,所以看不到任何資料。未來直接呼叫其他表單的資訊時,你才會知道這個檔案的功能。

  • 表單資料的取得

現在,讓我們開始來處理 unit02-1-1-get.php 的檔案內容吧!

例題 2.2-2:取得 GET 表單的內容,並且顯示到網頁上
  1. 先建立一個新檔案,檔名就稱為 /www/php/unit02-1-1-get.php,後續將程式碼寫入 body 當中 ;
  2. 在最上方增加一段程式碼,將 functions.php 的內容引入:
    <?php 
    	include ("functions.php");
    ?>
    
  3. 在 include 底下,將 myname1 與 myname2 的變數抓下來,因為是 GET 的方法,所以直接透過 $_GET['var'] 來處理即可。
    // 一般用來讀取前一個檔案傳來的表單資料,大多使用底下的方式來擷取的喔!
    $var = $_GET['var'];
    
  4. 在 body 內容中,透過嵌入式語法,以 echo 的方式,將抓到的資料顯示出來。
完成的結果會有點像這樣: 取得來自表單的資料,並且顯示到網頁中

你可以從網址列將變數資料抓下來,不過,事實上還是不要將資料貼到網址列應該是比較好的。那如何處理? 事實上,直接將 form 的 method 改成 post 即可喔!相當簡單!

  • 使用表單 post 方法,同時增加 HTML5 的 required="required" 語法檢查

同樣的,我們使用例題 2.1-1 的方案來處理,直接設計一下題目即可:

例題 2.2-3:改用 POST 方法,同時增加確認輸入的 required 功能
  1. 將 /www/php/unit02-1-1.php 另存新檔成為 unit02-2-3.php,然後進行修改
  2. 將表單的方法從 get 改成 post 狀態
  3. 將表單的上傳接收檔名改成 unit02-2-3-get.php
  4. 將姓氏的 input 標籤內容中,增加一個『 required="required" 』的內容,增加判斷
  5. 在 /www/php/index.php 加入這個程式的連結
完成的結果會有點像這樣: hello PHP

如果你在 unit02-1-1.php 當中,保持空白然後按下送出會怎樣?當然輸出的名字部份就是一片空白!你當然可以在 unit02-1-1-get.php 當中透過 PHP 的 if 來處理, 不過,如果能夠在使用者送出之前就來檢查,不是更好?沒錯~但是以前要達成這樣的功能都得要透過 javascript 撰寫程式碼來判斷,但新的支援 HTML5 的瀏覽器 (對!你沒看錯!是需要瀏覽器支援的!),可以加上『 required="required" 』在 input 標籤內,達到讓用戶一定要填寫的目的! 所以,在你的 unit02-2-3.php 裡面,讓兩個 input 都加上述的功能,然後嘗試不輸入任何字串就上傳看看,你應該就會看到如上的警告!

  • post 表單資料的取得方式

POST 表單資料的取得就不是 $_GET 來處理,而是 $_POST 來處理。如果不想要知道是哪一種表單資料,直接以 $_REQUEST 來處理也行!

例題 2.2-4:取得 POST 表單資料
  1. 將 /www/php/unit02-1-1-get.php 另存新檔成為 unit02-2-3-get.php,然後進行修改
  2. 將最上方的 GET 取得方法中,第一個以 POST 取代,另一個以 REQUEST 取代
回到網頁,將 unit02-2-3.php 的資料填寫完畢後,直接按下上傳,看看處理的結果如何: POST 表單資料的擷取

很快的,資料就可以被抓下來了!

2.3: type="password" 的密碼功能

如果你需要使用者輸入密碼欄位,倘若還使用 type="text" 時,密碼會被看光光。那怎辦?很簡單! 我們就將密碼變成特殊符號,如小數點或者是星號之類的,那就搞定了!這就得要用到 type="password" 的功能囉!

例題 2.3-1:製作密碼輸入欄位
  1. 將 /www/php/unit02-2-3.php 另存新檔成為 unit02-3-1.php,然後進行修改
  2. 表單上傳的檔名改為 unit-2-3-1-get.php
  3. 加入兩個變數,分別是 mypass1 以及 mypass2,使用的就是 type="password" 類型
  4. 同時 input 標記內部需要有 required=required 的設計
  5. 修改 submit 類型,將顯示的資料改為『 上傳我的密碼 』樣式
  6. 在 /www/php/index.php 加入這個程式的連結
完成的結果會有點像這樣: 來填密碼

這時你就會發現你的密碼欄位真的隱藏了起來!相當有趣吧!現在,讓我們將這些資料抓下來吧:

例題 2.3-2:取得密碼資料
  1. 將 /www/php/unit02-2-3-get.php 另存新檔成為 unit02-3-1-get.php,然後進行修改
  2. 將最上方取得 myname1 的地方,修改成以 mypass1 等由上個例題傳來的兩個密碼;
  3. 將密碼顯示到螢幕上
回到網頁,將 unit02-3-1.php 的資料填寫完畢後,直接按下上傳,看看處理的結果如何: POST 表單資料的擷取

竟然顯示出明碼!這真的不好!我們希望『當你忘記密碼時,除了重新設定密碼之外, 應該是沒有人會知道你的密碼明文』這樣的環境才是對的。所以,改天你問某網站,說你的密碼忘記了,可以幫你找回來嘛? 對方說 OK 沒問題時,你得要注意了...

  • 透過 hash('密碼格式', '密碼明文') 產生加密的密碼

那麼如何針對密碼明文加密呢?透過 PHP 的運算函式庫即可。基本上建議直接使用 sha256 這個密碼加密機制,然後透過 hash() 函式即可。 更多加密的演算法不在本文的介紹範圍內,而且,除非是惡意網站,否則,使用 sha256 應該稍微可以滿足大家對於密碼紀錄的需求了!

$pw1 = hash('sha256', "$_POST['pw1']");

這樣就可以推算出你的密碼,此時這串加密過的資料就可以放在資料庫,或者是暫時記憶到程式碼當中。由於本系資料庫的課程是在未來才會教, 因此,在底下的練習當中,我們將密碼藏在程式碼當中,當然,這個密碼是加密過的!然後,透過讓使用者輸入帳號與密碼, 來判斷使用者輸入的資訊是否為正確。

例題 2.3-3:取得密碼資料-真的是加密過的!
  1. 持續修改 /www/php/unit02-3-1-get.php 這個檔案內容
  2. 增加兩行顯示出密碼的加密結果,並將結果與明碼資料一起顯示到螢幕上
回到網頁,將 unit02-3-1.php 的資料填寫完畢後,直接按下上傳,看看處理的結果如何: POST 表單資料的擷取

另外,如果想要知道我們在 2.2 所製作的 functions.php 有沒有效果,那麼就在剛剛的密碼欄位上面輸入『 let's go 』去看看, 你大概就能知道為什麼說有效果了!因為後來會自動的加上反斜線 (\) 在單引號前面喔!

2.4: textarea 長版文字

如果你要讓人家寫一些文件類型的資料,那就不能單純使用 input 標記的 text 類型啊~因為只能一行,太少了! 那怎辦?這時就得要使用 textarea 的類型才行!一般來說, textarea 標記的資料,大致上是這樣的:

<textarea name="mytxt" style="width: 95%; height: 10em ">
寫些資料
<textarea>

讓我們來測試一下這個用法:

例題 2.4-1:測試大量留言的文件資料
  1. 先建立一個新檔案,檔名就稱為 /www/php/unit02-4-1.php,後續將程式碼寫入 body 當中 ;
  2. 使用 post 表單,同時上傳檔名改為 unit02-4-1-get.php;
  3. 使用一個 input 的 type="text" 類型方框,變數名稱 mytitle,且長度為 95% 的長度樣式
  4. 使用一個 areatext 的大量留言,變數名稱為 mytxt,樣式長度 95% 且高為 10em (行)
  5. 使用一個 sumbit ,內容為『傳送你的留言』
  6. 在 /www/php/index.php 加入這個程式的連結
完成的結果會有點像這樣: textarea 的測試

事實上,所有的 input 與 textarea 也都能夠使用 style 這種 CSS 的樣式表來修訂其樣式,讓它展示的比較美觀一些! 例如上面的設定,可以讓方塊的長度相同,對齊的比較完整,看起來當然順眼很多喔!接下來,當然就是將資料抓下來!

例題 2.4-2:將大量的資料顯示到螢幕上
  1. 將 /www/php/unit02-3-1-get.php 轉存成為 unit02-4-1-get.php,同時注意 functions.php 是否引入了。
  2. 利用 $_REQUEST 的方式,將主旨與內容通通抓下來
  3. 透過 div 等方式,將資料格式化輸出到螢幕上。
回到網頁,將 unit02-4-1.php 的資料填寫完畢後,直接按下上傳,看看處理的結果如何: POST 表單資料的擷取

2.5: type="radio" 的單選功能

有的時候,我們會需要使用者填寫單選項的資料,例如性別的選擇等等。但是因為就只有幾個選項而已,因此不太想讓使用者輸入, 而是希望類似選擇題,讓使用者直接點選即可。這時就用到單選功能的項目了:

<label><input type="radio" name="gender" value="male" /> 男生</label>
<label><input type="radio" name="gender" value="female" /> 女生</label>
<label><input type="radio" name="gender" value="unknown" /> 不便告知</label>
例題 2.5-1:設計單選項目
  1. 先建立一個新檔案,檔名就稱為 /www/php/unit02-5-1.php,後續將程式碼寫入 body 當中 ;
  2. 建立使用 post 為主的表單,上傳的檔案使用 unit02-5-1-get.php,表單名稱 myform
  3. 建立名為 gender 的變數名稱的單選,內容分別為 male (男生)、 female (女生)、 nuknown (不告訴你) 三個項目
  4. 建立一個名為『上傳你的選擇』的 submit 按鈕。
  5. 在 /www/php/index.php 加入這個程式的連結
完成的結果會有點像這樣: 性別選擇

有個問題,那就是,這個選擇一定要勾選到小圓圈才會有效果,好煩!能不能點選到『男生』的文字上面就可以了?行!使用 <label> </label> 將需要處理的項目整個圈選起來,就可以組合成為一個集合的效果!

例題 2.5-2:選擇項目時,搭配 label 的用法
  1. 將 /www/php/unit02-5-1.php 另存檔成為 unit02-5-2.php
  2. 將三個單選項目,分別使用 label 組合 (三組)。
  3. 在 /www/php/index.php 加入這個程式的連結

完成的結果跟之前一樣,只是點選時,可以點選文字即可單選跳動了!現在,請將你的答案抓下來吧!

例題 2.5-3:將單選項目抓下來
  1. 將 /www/php/unit02-4-1-get.php 轉存成為 unit02-5-1-get.php,同時注意 functions.php 是否引入了。
  2. 利用 $_REQUEST 的方式,將 gender 變數抓下來
  3. 將選擇的性別輸出到螢幕上
回到網頁,將 unit02-5-2.php 的資料填寫完畢後,直接按下上傳,看看處理的結果如何: POST 表單資料的擷取

2.6: type="checkbox" 的複選功能

有時候,我們需要的資料會是『複選』的模樣!就是多選題啦!不是單選而已。這時候就需要 checkbox 來處理了。那麼 checkbox 的語法如何呢? 也不難,這樣做看看:

<input type='checkbox' name='myfood[]' value='廣東粥' />廣東粥

一般來說,複選會使用到『陣列』的機制,陣列在 HTML 裡面必需要加上中括號[]才行!不過 PHP 裡面倒是不需要加上中括號。 現在,讓我們來選擇一下,你可能會有興趣的餐點項目:

例題 2.6-1:選擇複選的功能
  1. 先建立一個新檔案,檔名就稱為 /www/php/unit02-6-1.php,後續將程式碼寫入 body 當中 ;
  2. 建立使用 post 為主的表單,上傳的檔案使用 unit02-6-1-get.php,表單名稱 myform
  3. 以上面的語法,建立名為 myfood[] 的變數名稱,用在單選上面。至於 value 與顯示名稱的對應, 請寫下至少 5 個以上的可能選擇的餐點。同時,使用 label 放大選擇的範圍
  4. 建立一個名為『上傳你的選擇』的 submit 按鈕。
  5. 在 /www/php/index.php 加入這個程式的連結
完成的結果會有點像這樣: 複選題

複選的 HTML 原始碼如上,還算簡單啊!但是怎麼抓出來資料呢?這就是個大問題!基本上,抓取下來的變數資料, 其實是『陣列』,所謂的陣列就有點像我們以前唸書的時候,那個 f(x) 的意思,其中 x 會有多個!例如 f(0)=1, f(1)=2 之類的。 在 php 底下,我們使用的是 f[0], f[1] 之類的,亦即使用中括號取代小括號~那,到底有幾個 x 呢?可以這樣計算:

count($arrayname);

那就直接來測試一下,將資料抓下來吧!不過需要注意的是,第一個陣列的內容 (就是 f(x) 的 x ),是從 0 號開始喔!

例題 2.6-2:將複選項目抓下來
  1. 將 /www/php/unit02-5-1-get.php 轉存成為 unit02-6-1-get.php,同時注意 functions.php 是否引入了。
  2. 利用 $_REQUEST 的方式,將 myfood 變數抓下來,特別記得,在 html 裡面變數名稱有 myfood[],但是在 php 裡面,必需要取消中括號才對喔!
  3. 在變數取得後,使用『 $nu = count($myfood) 』計算出圈選的個數
  4. 因為我們尚未談到迴圈,所以這裡就單純列出前三項餐點 (不論勾選幾個,都列出 3 個)
回到網頁,將 unit02-6-1.php 的資料填寫完畢後,直接按下上傳,看看處理的結果如何: POST 表單資料的擷取

2.7: select 與 option 的下拉式選單

有時候,某些『單選』的資料量太龐大,如果將所有的單選資料全部列出在同一個畫面上,似乎很混亂!而且,版面的排版也容易跑掉,醜醜的。 這個時候,使用下拉式選單來替換單選的項目,應該是還不錯的選擇。我們可以透過 select 搭配 option 來處理這樣的事情即可! 他的基本語法是這樣的:

<select name="myselect">
	<option value="value1">value1</option>
	<option value="value2">value2</option>
	<option value="value3">value3</option>
</select>

現在,繼續來做幾個慣用的單選功能吧!

例題 2.7-1:使用下拉式選單的單選功能
  1. 先建立一個新檔案,檔名就稱為 /www/php/unit02-7-1.php,後續將程式碼寫入 body 當中 ;
  2. 建立使用 post 為主的表單,上傳的檔案使用 unit02-7-1-get.php,表單名稱 myform
  3. 建立名為 mylang 的變數名稱的 select 標記資料
  4. 建立三種以上的常用語言與數值,包括中文、英文、日文、韓文等
  5. 建立一個名為『上傳你的語言』的 submit 按鈕。
  6. 在 /www/php/index.php 加入這個程式的連結
完成的結果會有點像這樣: 下拉式選單

要將資料抓下來就太簡單了!那就自己動作做:

例題 2.7-2:將單選項目抓下來
  1. 將 /www/php/unit02-6-1-get.php 轉存成為 unit02-7-1-get.php,同時注意 functions.php 是否引入了。
  2. 利用 $_REQUEST 的方式,將 mylang 變數抓下來
  3. 螢幕上顯示出你選擇的語言
回到網頁,將 unit02-7-1.php 的資料填寫完畢後,直接按下上傳,看看處理的結果如何: POST 表單資料的擷取

2.8: 小小挑戰題

前一節課程我們有計算到 BMI 的項目,但是那個時候只能用人工的方法去處理。現在,請使用上面的種種方式, 完成類似底下的結果。亦即,我只要輸入身高、體重,程式可以幫我計算出 BMI 的數值。檔名請設定為 unit02-8-1.php, 上傳的處理檔案為 unit02-8-1-get.php。

POST 表單資料的擷取