PHP表單之表單驗證
一、表單安全
1、htmlspecialchars()函式
把特殊字元轉換為 HTML 實體。這意味著 < 和 > 之類的 HTML 字元會被替換為 < 和 > 。這樣可防止攻擊者通過在表單中注入 HTML 或 JavaScript 程式碼(跨站點指令碼攻擊)對程式碼進行利用。
跨站點指令碼攻擊(Cross Site Scripting):為不和層疊樣式表(Cascading Style Sheets, CSS)的縮寫混淆,故將跨站指令碼攻擊縮寫為XSS。惡意攻擊者往Web頁面裡插入惡意html程式碼,當用戶瀏覽該頁之時,嵌入其中Web裡面的html程式碼會被執行,從而達到惡意攻擊使用者的特殊目的。
HTML 實體:HTML 中的預留字元必須被替換為字元實體。如果希望正確地顯示預留字元,我們必須在 HTML 原始碼中使用字元實體(character entities)。
顯示結果 | 描述 | 實體名稱 | 實體編號 |
---|---|---|---|
空格 | |   | |
< | 小於號 | < | < |
> | 大於號 | > | > |
& | 和號 | & | & |
“ | 引號 | " | " |
‘ | 撇號 | ' (IE不支援) | ' |
¢ | 分 | ¢ | ¢ |
£ | 鎊 | £ | £ |
¥ | 日圓 | ¥ | ¥ |
€ | 歐元 | € | € |
§ | 小節 | § | § |
© | 版權 | © | © |
® | 註冊商標 | ® | ® |
™ | 商標 | ™ | ™ |
× | 乘號 | × | × |
÷ | 除號 | ÷ | ÷ |
一個簡單的加法器(注意看其中的htmlspecialchars)
<html>
<body>
<form method='post' action='<?php echo htmlspecialchars($_SERVER['PHP_SELF'])?>'>
<input type="text" pattern="[0-9]*" name="left">
+
<input type="text" pattern="[0-9]*" name="right">
=
<input type="submit" value="計算">
</form>
</body>
</html>
<?php
echo $_POST['left']+$_POST['right'];
?>
2、建立表單驗證函式
<html>
<head>
<title>表單測試</title>
</head>
<body>
<?php
$name = $email = $website=$comment="";
function format_input($data){
$data=trim($data);#去除首尾多餘的空白符
$data=stripcslashes($data);#去除使用者輸入的反斜槓
$data=htmlspecialchars($data);#轉化為html實體
return $data;
}
if($_SERVER['REQUEST_METHOD']=="POST"){
$name=format_input($_POST['name']);
$email=format_input($_POST['email']);
$website=format_input($_POST['website']);
$comment=format_input($_POST['comment']);
}
?>
<form method="POST" action="<?php echo htmlspecialchars($_SERVER['PHP_SELF'])?>">
姓名:<input type="text" name="name" />
<br /><br />
電郵:<input type="text" name="email" />
<br /><br />
網址:<input type="text" name="website" />
<br /><br />
評論:<textarea cols="22" rows="5" name="comment"></textarea>
<br /><br />
<input type='submit' value='提交' />
</form>
<?php
echo "<br />name:".$name;
echo "<br />email:".$email;
echo "<br />website:".$website;
echo "<br />comment:".$comment;
?>
</body>
</html>
二、表單必填
欄位 | 驗證規則 |
---|---|
Name | 必需。必須包含字母和空格。 |
必需。必須包含有效的電子郵件地址(包含 @ 和 .)。 | |
Website | 可選。如果選填,則必須包含有效的 URL。 |
Comment | 可選。多行輸入欄位(文字框)。 |
<html>
<head>
<title>表單必填</title>
<style>
.error {color:#FF0000;}
</style>
</head>
<body>
<?php
$name = $email = $website=$comment="";
$nameErr=$emailErr=$websiteErr=$commentErr="";
function format_input($data){
$data=trim($data);#去除首尾多餘的空白符
$data=stripcslashes($data);#去除使用者輸入的反斜槓
$data=htmlspecialchars($data);#轉化為html實體
return $data;
}
if($_SERVER['REQUEST_METHOD']=="POST"){
if(empty($_POST['name']))
$nameErr="姓名是必填的!";
else
$name=format_input($_POST['name']);
if(empty($_POST['email']))
$emailErr="郵箱是必填的!";
else
$email=format_input($_POST['email']);
$website=format_input($_POST['website']);
$comment=format_input($_POST['comment']);
}
?>
<form method="POST" action="<?php echo htmlspecialchars($_SERVER['PHP_SELF'])?>">
姓名:<input type="text" name="name" />
<span class="error">*<?php echo $nameErr; ?></span>
<br /><br />
電郵:<input type="text" name="email" />
<span class="error">*<?php echo $emailErr; ?></span>
<br /><br />
網址:<input type="text" name="website" />
<br /><br />
評論:<textarea cols="22" rows="5" name="comment"></textarea>
<br /><br />
<input type='submit' value='提交' />
</form>
<?php
echo "<br />name:".$name;
echo "<br />email:".$email;
echo "<br />website:".$website;
echo "<br />comment:".$comment;
?>
</body>
</html>
三、格式匹配
利用正則表示式(Regular Expression)對使用者輸入的資料進行格式驗證。更多有關正則表示式的知識請看正則表示式30分鐘入門教程以及正則表示式全部符號解釋。
int preg_match ( string $pattern , string $subject );
搜尋subject與pattern給定的正則表示式的一個匹配。
Regex quick reference
符號 | 意義 |
---|---|
[abc] | A single character: a, b or c |
[^abc] | Any single character but a, b, or c |
[a-z] | Any single character in the range a-z |
[a-zA-Z] | Any single character in the range a-z or A-Z |
^ | Start of line |
$ | End of line |
\A | Start of string |
\z | End of string |
. | Any single character |
\s | Any whitespace character |
\S | Any non-whitespace character |
\d | Any digit |
\D | Any non-digit |
\w | Any word character (letter, number, underscore) |
\W | Any non-word character |
\b | Any word boundary character |
(…) | Capture everything enclosed |
(a | b) |
a? | Zero or one of a |
a* | Zero or more of a |
a+ | One or more of a |
a{3} | Exactly 3 of a |
a{3,} | 3 or more of a |
a{3,6} | Between 3 and 6 of a |
1、匹配姓名
“/^[a-zA-Z ]*$/”
只允許空格和字母,”^”表示開頭,”$”表示結尾,[a-zA-Z ]表示a-z或者A-Z或者空格中的一個字元。
$name = test_input($_POST["name"]);
if (!preg_match("/^[a-zA-Z ]*$/",$name)) {
$nameErr = "只允許字母和空格!";
}
2、匹配E-mail
“/([\w-]+\@[\w-]+.[\w-]+)/”
“\w”匹配包括下劃線的任何單詞字元。等價於’[A-Za-z0-9_]’;
+匹配前面的子表示式一次或多次;
“-“匹配”-“。
3、匹配URL
“/\b(?:(?:https?|ftp):\/\/|www.)[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i”
四、保留表單中的值
原理:在input標籤中嵌入PHP指令碼。
如果type=”text”,那麼就嵌入value=”<?php echo $valuableName; ?>”
如果type=”radio”,那麼就嵌入<?php if (isset($valuableName) && $valuableName==”value1”) echo “checked”;?>
最後寫了一個簡單的登入表單:
<html>
<head>
<title>一個簡易的登入表單</title>
</head>
<body>
<?php
$email = $passwd ="";
$emailErr=$passwdErr="";
if($_SERVER['REQUEST_METHOD']=='POST'){
if(empty($_POST['email']))
$emailErr='請輸入郵箱!';
else if(preg_match("/([\w\-]+\@[\w\-]+\.[\w\-]+)/",$_POST['email']))
$email=clear_input($_POST['email']);
else $emailErr="請輸入有效的郵箱!";
if(empty($_POST['passwd']))
$passwdErr='請輸入密碼!';
else
$passwd=clear_input($_POST['passwd']);
}
function clear_input($data){
$data=trim($data);
$data=stripcslashes($data);
$data=htmlspecialchars($data);
return $data;
}
?>
<form method="post" action="<?php echo htmlspecialchars($_SERVER['PHP_SELF']);?>">
郵箱:<input type="text" name="email" value="<?php echo $email;?>" />
<span class='error'><?php echo $emailErr;?></span>
<br />
密碼:<input type="password" name="passwd" value="<?php echo $passwd;?>"/>
<span class='error'><?php echo $passwdErr;?></span>
<br />
<input type="submit" name="submit" value="登入">
</form>
<?php
echo "你輸入的<br />";
echo "郵箱:".$email;
echo "<br />";
echo "密碼:".$passwd;
?>
</body>
</html>