PHP學習練手(十五)
阻止垃圾郵件
一、垃圾郵件的預防技術
使用正則表示式或過濾器擴充套件驗證任何電子郵件地址
在表單值中監視這些字元。如果值中包含該列表中的任何內容,就不要使用那個值。
2.1 程式碼:
email2.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Contact Me</title>
</head>
<body>
<h1>Contact Me</h1 >
<?php
if($_SERVER['REQUEST_METHOD'] == 'POST')
{
//函式功能是實現字元過濾
function spam_scrubber($value)
{
$very_bad = array('to', 'cc:', 'content-type:', 'mime-version:','multipart-mixed:','content-transfer-encoding');
//判斷$value中是否存在$very_bad中包含的各種變數
foreach($very_bad as $v)
{
if(stripos($value, $v) != false)
{
return '';
}
}
//字串替換
$value = str_replace(array("\r", "\n", "%0a", "%0d" ), '' , $value);
//過濾空格
return trim($value);
}
//將函式作用到陣列的每個值上
$scrubbed = array_map('spam_scrubber', $_POST);
if(!empty($scrubbed['name']) && !($scrubbed['email']) && !empty($scrubbed['comments']))
{
$body = "Name: {$scrubbed['name']}\n\nComments: {$scrubbed['comments']}";
//字元截斷
$body = Wordwrap($body, 70);
mail('[email protected]', 'Contact From Submission', $body, "From:{$_POST['email']}");
echo '<p><em>Thank you for contacting me. I will reply some day.</em></p>';
$_POST =array() ; //將$_POST清空
}else{
echo '<p style="font-weight: bold; color: #C00"></p>';
}
}
?>
<p>Please fill out this form to contact me.</p>
<form action="email.php" method="post">
<p>Name: <input type="text" name="name" size="30" maxlength="60" value="<?php if(isset($_POST['name'])) echo $_POST['name']; ?>" /></p>
<p>Email Address: <input type="text" name="name" size="30" maxlength="80" value="<?php if(isset($_POST['email'])) echo $_POST['email']; ?>" /></p>
<p>Comments: <textarea name="comments" rows="5" cols="30"><?php if(isset($_POST['comments'])) echo $_POST['comments']; ?></textarea></p>
<p><input type="submit" name="submit" value="Send!" /></p>
</form>
</body>
</html>
2.2 函式解析:
stripos():函式查詢字串在另一字串中第一次出現的位置(不區分大小寫)。
str_replace():函式以其他字元替換字串中的一些字元(區分大小寫)。
array_map():將函式作用到陣列中的每個值上,每個值都乘以本身,並返回帶有新值的陣列。
2.3程式碼解析:
$very_bad = array('to', 'cc:', 'content-type:', 'mime-version:','multipart-mixed:','content-transfer-encoding');
//判斷$value中是否存在$very_bad中包含的各種變數
foreach($very_bad as $v)
{
if(stripos($value, $v) != false)
{
return '';
}
}
解釋: $very_bad
儲存了所有可能的不合法聯絡人字元。foreach迴圈一次將訪問$very_bad
中的一個數據項,stripos()函式將檢查作為$value
提供給該函式的資料項是否存在字串中。一旦發現“危險”字串,函式將返回一個空字串並終止執行。
2.4 程式碼執行:
注:由於提交的Email Address中出現了不合法字元,因此,該郵件不會被髮送。
通過型別驗證資料
一、2種驗證方法:
- 白名單:設定能通過的使用者,白名單以外的使用者都不能通過
- 黑名單:設定不能通過的使用者,黑名單以外的使用者都能通過。
1.1 程式碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Widget</title>
</head>
<body>
<?php # Script 13.2 - calculator.php
if($_SERVER['REQUEST_METHOD']=='POST')
{
$quantity = (int) $_POST['quantity'];
$price = (float) $_POST['price'];
$tax = (float) $_POST['tax'];
if(($quantity > 0) && ($price > 0) && ($tax > 0))
{
$total = $quantity * $price;
$total += $total * ($tax/100);
echo '<p>The cost of purchasing '.$quantity.' widget(s) at $'.number_format($price, 2).'each, plus tax, is $'.number_format($total, 2).'</p>';
}else{
echo '<p style = "font-weight: bold; color: #C00">Please enter a valid quantity, price, and tax rate.</p>';
}
}
?>
<h1>Widget Cost Calculator</h1>
<form action="calculator.php" method="post">
<p>Quantity: <input type="text" name="quantity" size="5" maxlength="10" value="<?php if(isset($quantity)) echo $quantity; ?>" /></p>
<p>Price: <input type="text" name="price" size="5" maxlength="10" value="<?php if(isset($price)) echo $price; ?>" /></p>
<p>Tax: <input type="text" name="tax" size="5" maxlength="10" value="<?php if(isset($tax)) echo $tax; ?>" /></p>
<p><input type="submit" name="submit" value="Calculate" /></p>
</form>
</body>
</html>
1.2 程式碼解釋:
$quantity = (int) $_POST['quantity'];
$price = (float) $_POST['price'];
$tax = (float) $_POST['tax'];
解釋:通過強制轉換變數型別,驗證資料的正確格式
1.3 程式碼執行:
按型別驗證檔案
1、$_FILES['upload']['type']
是指上傳瀏覽器提供的MIME型別。但是惡意使用者很容易通過提供虛假的MIME型別誘騙瀏覽器
2、Fileinfo是在伺服器端進行內容型別的檢驗。Fileinof通過獲取檔案的“魔法位元組”或“魔法數字”來判斷檔案的型別(和編碼),例如,構成GIF圖片的資料必須以ASCII碼GIF89a或GIF87a開頭,構成PDF檔案的資料必須以%PDF開頭。
3、如何使用Fileinfo:
要使用Fileinfo,首先建立Fileinfo資源:
$fileinfo = finfo_open(kind)
kind值是個常量,指定建立的資源型別,判斷檔案型別的常量是FILEINFO_MIME_TYPE,即$file = finfo_open(FILEINFO_MYIME_TYPE)
接下來,呼叫finfo_file()函式,提供Fileinfo資源和要檢查的檔案的引用
finfo_file($fileinfo, $filename)
此函式基於檔案的實際“魔法位元組”,返回檔案的MIME型別(已經建立的資源)完成後,應關閉Fileinfo的資源
finfo_close($fileindo)
4、程式碼upload_rtf.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Upload a RTF Document</title>
</head>
<body>
<?php # Script 13.3 - upload_rtf.php
if($_SERVER['REQUEST_METHOD'] == 'POST')
{
if(isset($_FILES['upload']) && file_exists($_FILES['upload']['tmp_name']))
{
//建立fileinfo資源
$fileinfo = finfo_open(FILEINFO_MIME_TYPE);
//伺服器端檢查檔案型別
if(finfo_file($fileinfo, $_FILES['upload']['tmp_name']) == 'text/rtf')
{
echo '<p><em>The file would be acceptable</em></p>';
//刪除臨時檔案
unlink($_FILE['upload']['tmp_name']);
}else{
echo '<p style = "font-weight: bold; color: #C00">Please upload an RTF document.</p>';
}
//關閉Fileinfo資源
finfo_close($fileinfo);
}
}
?>
<form enctype="multipart/form-data" action="upload_rtf.php" method = "post">
<input type="hidden" name="MAX_FILE_SIZE" value="524288" />
<fieldset>
<legend>Select an RTF document of 512KB or smaller to be uploaded</legend>
<p><b>File:</b> <input type="file" name="upload"/></p>
<div align="center"><input type="submit" name="submit" value="Submit"></div>
</fieldset>
</form>
</body>
</html>
阻止XSS攻擊
1、XSS(跨站指令碼)攻擊——
許多動態驅動的web應用程式會獲取使用者提交的資訊,將其儲存在資料庫中,然後在另一個頁面上重新顯示該資訊。當用戶在資料中輸入HTML程式碼,這種程式碼就可能拋棄站點的佈局和美感。更糟糕的是,JS也只是純文字,但它是Web瀏覽器內可執行的指令碼,可能會造成彈窗,竊取cookie或者把瀏覽器重定向到其他站點,稱之為XSS攻擊。
2、程式碼:
xss.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>XSS Attacks</title>
</head>
<body>
<?php # Script 13.4 - xss.php
if($_SERVER['REQUEST_METHOD'] == 'POST')
{
echo "<h2>Original</h2><p>{$_POST['data']}</p>";
echo '<h2>After htmlspecialchars() </h2><p>'.htmlspecialchars($_POST['data']).'</p>';
echo '<h2>After htmlentities() </h2><p>'.htmlentities($_POST['data']).'</p>';
echo "<h2>After strip_tags() </h2><p>".strip_tags($_POST['data'])."</p>";
}
?>
<form action="xss.php" method="post">
<p>Do your worst!<textarea name="data" cols="40" rows="4"></textarea><div><input type="submit" name="submit" value="Submit" /></div>
</p>
</form>
</body>
</html>
3、函式解析:
htmlspecialchars():把預定義的字元轉換為 HTML 實體
htmlentities():把字元轉換為 HTML 實體
strip_tags():去掉字串中的 HTML 標籤
這3個函式以從破壞性最小到最大的順序列出。
4、程式碼執行:
使用過濾器擴充套件
1、過濾器擴充套件的目的——驗證資料或清理資料
2、使用函式filter_var(variable, filter[,options])
3、過濾器選擇
4、程式碼:
calculator2.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Widget</title>
</head>
<body>
<?php # Script 13.2 - calculator.php
if($_SERVER['REQUEST_METHOD']=='POST')
{
//$quantity = (int) $_POST['quantity'];
//$price = (float) $_POST['price'];
//$tax = (float) $_POST['tax'];
//如果是整數則儲存,否則為null
$quantity = (isset($_POST['quantity'])) ? filter_var($_POST['quantity'], FILTER_VALIDATE_INT, array('min_range'=>1)) : NULL;
//如果是浮點數,則儲存,否則為null
$price = (isset($_POST['price'])) ? filter_var($_POST['price'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : NULL;
$tax = (isset($_POST['tax'])) ? filter_var($_POST['tax'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : NULL;
if(($quantity > 0) && ($price > 0) && ($tax >
0))
{
$total = $quantity * $price;
$total += $total * ($tax/100);
echo '<p>The cost of purchasing '.$quantity.' widget(s) at $'.number_format($price, 2).'each, plus tax, is $'.number_format($total, 2).'</p>';
}else{
echo '<p style = "font-weight: bold; color: #C00">Please enter a valid quantity, price, and tax rate.</p>';
}
}
?>
<h1>Widget Cost Calculator</h1>
<form action="calculator2.php" method="post">
<p>Quantity: <input type="text" name="quantity" size="5" maxlength="10" value="<?php if(isset($quantity)) echo $quantity; ?>" /></p>
<p>Price: <input type="text" name="price" size="5" maxlength="10" value="<?php if(isset($price)) echo $price; ?>" /></p>
<p>Tax: <input type="text" name="tax" size="5" maxlength="10" value="<?php if(isset($tax)) echo $tax; ?>" /></p>
<p><input type="submit" name="submit" value="Calculate" /></p>
</form>
</body>
</html>
5、程式碼執行
預防SQL注入攻擊
1、SQL注入攻擊——是指企圖把不良程式碼插入到站點SQL查詢中。這類攻擊的目標之一是,它們將建立一個語法上無效的查詢,從而再得到的出錯訊息中呈現關於指令碼或資料庫的某些訊息。而注入攻擊更大的目的是改變、破壞或暴露儲存的資料。
2、預處理語句的效能
預處理語句比老式的查詢方式更安全,而且可能也會更快。如果一個PHP指令碼多次傳送相同的PHP查詢到MySQL,每次使用不同的值,預處理可以加快速度。在這種情況下,只會把查詢本身傳送給MySQL,並且只會解析一次。然後,單獨把值傳送給MySQL。
3、如果不使用預處理語句,整個查詢(包括SQL語法和具體的值)都會作為一個長字串傳送到MySQL。然後MySQL分析並執行它。使用預處理查詢,SQL語法首先被髮送到MySQL解析,確保它在語法上是有效的,然後單獨傳送特定的值,MySQL使用這些值組合查詢,然後執行它。
4、預處理的優點:它可以帶來更高的安全性、並且可能提供更好的工作的效能。
5、程式碼:
post_message.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Post a message</title>
</head>
<body>
<?php # Script 13.6 - post_message.php
if($_SERVER['REQUEST_METHOD'] == 'POST')
{
$mysqli = mysqli_connect('localhost', 'root', '1111', 'forum');
$sql = "INSERT INTO messages(forum_id, parent_id, user_id, subject, body, date_entered) VALUES (?,?,?,?,?, NOW())";
$stmt = mysqli_prepare($mysqli, $sql);
mysqli_stmt_bind_param($stmt, 'iiiss', $forum_id, $parent_id, $user_id, $subject, $body);
$forum_id = (int) $_POST['forum_id'];
$parent_id = (int) $_POST['parent_id'];
$user_id = 3;
$subject = strip_tags($_POST['subject']);
$body = strip_tags($_POST['body']);
mysqli_stmt_execute($stmt);
if(mysqli_stmt_affected_rows($stmt) == 1){
echo '<p>Your messages has been posted.</p>';
}else{
echo '<p style="font-weight: bold; color: #C00">Your message could not be posted.</p>';
echo '<p>'.mysqli_stmt_error($stmt).'</p>';
}
mysqli_stmt_close($stmt);
mysqli_close($mysqli);
}
?>
<form action="post_message.php" method="post">
<fieldset>
<legend>Post a message</legend>
<p><b>Subject</b>: <input type="text" name="subject" size="30" maxlength="100" /></p>
<p><b>Body</b>: <textarea name="body" cols="40" rows="4"></textarea></p>
<div align="center"><input type="submit" name="submit" value="Submit"></div>
</fieldset>
<input type="hidden" name="forum_id" value="1" />
<input type="hidden" name="parent_id" value="0" />
</form>
</body>
</html>
6、程式碼解析:
$sql = "INSERT INTO messages(forum_id, parent_id, user_id, subject, body, date_entered) VALUES (?,?,?,?,?, NOW())"; //預處理sql語句
$stmt = mysqli_prepare($mysqli, $sql); //將結果寫入到對應的資料庫變數中
mysqli_stmt_bind_param($stmt, 'iiiss', $forum_id, $parent_id, $user_id, $subject, $body); //繫結對應的引數,‘iiiss’表示第1,2, 3是整數 第4,5是字串等型別
mysqli_stmt_execute($stmt);//執行預處理語句
mysqli_stmt_close($stmt);//關閉預處理資源
7、程式碼執行