PHP - 多維數組
多維數組指的是包含一個或多個數組的數組。
注釋:數組的維度指示您需要選擇元素的索引數。
- 對於二維數組,您需要兩個索引來選取元素
- 對於三維數組,您需要三個索引來選取元素
PHP - 兩維數組
$cars = array ( array("Volvo",22,18), array("BMW",15,13), array("Saab",5,2), array("Land Rover",17,15) );如需訪問 $cars 數組中的元素,我們必須使用兩個索引(行和列):
<?php echo $cars[0][0].": 庫存:".$cars[0][1].", 銷量:".$cars[0][2].".<br>"; echo $cars[1][0].": 庫存:".$cars[1][1].", 銷量:".$cars[1][2].".<br>"; echo $cars[2][0].": 庫存:".$cars[2][1].", 銷量:".$cars[2][2].".<br>"; echo $cars[3][0].": 庫存:".$cars[3][1].", 銷量:".$cars[3][2].".<br>"; ?>或者:
<?php for ($row = 0; $row < 4; $row++) { echo "<p><b>Row number $row</b></p>"; echo "<ul>"; for ($col = 0; $col < 3; $col++) { echo "<li>".$cars[$row][$col]."</li>"; } echo "</ul>"; } ?>PHP date() 函數用於對日期或時間進行格式化。
語法
date(format,timestamp)
參數 | 描述 |
---|---|
format | 必需。規定時間戳的格式。 |
timestamp | 可選。規定時間戳。默認是當前時間和日期。 |
<?php
echo "今天是 " . date("Y/m/d") . "<br>";
echo "今天是 " . date("Y.m.d") . "<br>";
echo "今天是 " . date("Y-m-d") . "<br>";
echo "今天是 " . date("l");
?>
PHP 提示 - 自動版權年份
使用 date() 函數在您的網站上自動更新版本年份:
版權所有 2010-<?php echo date("Y")?>
獲得簡單的時間
- h - 帶有首位零的 12 小時小時格式
- i - 帶有首位零的分鍾
- s - 帶有首位零的秒(00 -59)
- a - 小寫的午前和午后(am 或 pm)
<?php echo "現在時間是 " . date("h:i:sa"); ?>
獲得時區
<?php date_default_timezone_set("Asia/Shanghai"); echo "當前時間是 " . date("h:i:sa"); ?>
通過 PHP mktime() 創建日期
mktime() 函數返回日期的 Unix 時間戳。Unix 時間戳包含 Unix 紀元(1970 年 1 月 1 日 00:00:00 GMT)與指定時間之間的秒數。語法
mktime(hour,minute,second,month,day,year)

通過 PHP strtotime() 用字符串來創建日期
PHP strtotime() 函數用於把人類可讀的字符串轉換為 Unix 時間。
語法
strtotime(time,now)
PHP 在將字符串轉換為日期這方面非常聰明,所以您能夠使用各種值:
實例
<?php $d=strtotime("tomorrow"); echo date("Y-m-d h:i:sa", $d) . "<br>"; $d=strtotime("next Saturday"); echo date("Y-m-d h:i:sa", $d) . "<br>"; $d=strtotime("+3 Months"); echo date("Y-m-d h:i:sa", $d) . "<br>"; ?>
<?php $d1=strtotime("December 31"); $d2=ceil(($d1-time())/60/60/24); echo "距離十二月三十一日還有:" . $d2 ." 天。"; ?>服務器端包含 (SSI) 用於創建可在多個頁面重復使用的函數、頁眉、頁腳或元素。
PHP include 和 require 語句
通過 include 或 require 語句,可以將 PHP 文件的內容插入另一個 PHP 文件(在服務器執行它之前)。
include 和 require 語句是相同的,除了錯誤處理方面:
- require 會生成致命錯誤(E_COMPILE_ERROR)並停止腳本
- include 只生成警告(E_WARNING),並且腳本會繼續
假設我們有一個名為 "footer.php" 的標准的頁腳文件,就像這樣:
<?php echo "<p>Copyright © 2006-" . date("Y") . " W3School.com.cn</p>"; ?>
如需在一張頁面中引用這個頁腳文件,請使用 include 語句:
<html> <body> <h1>歡迎訪問我們的首頁!</h1> <p>一段文本。</p> <p>一段文本。</p> <?php include 'footer.php';?> </body> </html>
PHP 操作文件
PHP 擁有的多種函數可供創建、讀取、上傳以及編輯文件。
注意:請謹慎操作文件!
當您操作文件時必須非常小心。如果您操作失誤,可能會造成非常嚴重的破壞。常見的錯誤是:
- 編輯錯誤的文件
- 被垃圾數據填滿硬盤
- 意外刪除文件內容
PHP readfile() 函數
readfile() 函數讀取文件,並把它寫入輸出緩沖。
假設我們有一個名為 "webdictionary.txt" 的文本文件,存放在服務器上,就像這樣:
AJAX = Asynchronous JavaScript and XML CSS = Cascading Style Sheets HTML = Hyper Text Markup Language PHP = PHP Hypertext Preprocessor SQL = Structured Query Language SVG = Scalable Vector Graphics XML = EXtensible Markup Language
讀取此文件並寫到輸出流的 PHP 代碼如下(如讀取成功則 readfile() 函數返回字節數):
實例
<?php echo readfile("webdictionary.txt"); ?>
PHP Open File - fopen()
fopen() 的第一個參數包含被打開的文件名,第二個參數規定打開文件的模式。如果 fopen() 函數未能打開指定的文件,下面的例子會生成一段消息:<?php $myfile = fopen("webdictionary.txt", "r") or die("Unable to open file!"); echo fread($myfile,filesize("webdictionary.txt")); fclose($myfile); ?>
文件會以如下模式之一打開:
模式 | 描述 |
---|---|
r | 打開文件為只讀。文件指針在文件的開頭開始。 |
w | 打開文件為只寫。刪除文件的內容或創建一個新的文件,如果它不存在。文件指針在文件的開頭開始。 |
a | 打開文件為只寫。文件中的現有數據會被保留。文件指針在文件結尾開始。創建新的文件,如果文件不存在。 |
x | 創建新文件為只寫。返回 FALSE 和錯誤,如果文件已存在。 |
r+ | 打開文件為讀/寫、文件指針在文件開頭開始。 |
w+ | 打開文件為讀/寫。刪除文件內容或創建新文件,如果它不存在。文件指針在文件開頭開始。 |
a+ | 打開文件為讀/寫。文件中已有的數據會被保留。文件指針在文件結尾開始。創建新文件,如果它不存在。 |
x+ | 創建新文件為讀/寫。返回 FALSE 和錯誤,如果文件已存在。 |
PHP 讀取文件 - fread()
fread() 的第一個參數包含待讀取文件的文件名,第二個參數規定待讀取的最大字節數。
如下 PHP 代碼把 "webdictionary.txt" 文件讀至結尾:
fread($myfile,filesize("webdictionary.txt"));
PHP 關閉文件 - fclose()
注釋:用完文件后把它們全部關閉是一個良好的編程習慣。您並不想打開的文件占用您的服務器資源。
fclose() 需要待關閉文件的名稱(或者存有文件名的變量):
<?php
$myfile = fopen("webdictionary.txt", "r");
// some code to be executed....
fclose($myfile);
?>
PHP 讀取單行文件 - fgets()
下例輸出 "webdictionary.txt" 文件的首行:<?php $myfile = fopen("webdictionary.txt", "r") or die("Unable to open file!"); echo fgets($myfile); fclose($myfile); ?>注釋:調用 fgets() 函數之后,文件指針會移動到下一行。
PHP 檢查 End-Of-File - feof()
feof() 對於遍歷未知長度的數據很有用。
下例逐行讀取 "webdictionary.txt" 文件,直到 end-of-file:
<?php $myfile = fopen("webdictionary.txt", "r") or die("Unable to open file!"); // 輸出單行直到 end-of-file while(!feof($myfile)) { echo fgets($myfile) . "<br>"; } fclose($myfile); ?>
PHP 讀取單字符 - fgetc()
下例逐字符讀取 "webdictionary.txt" 文件,直到 end-of-file:<?php $myfile = fopen("webdictionary.txt", "r") or die("Unable to open file!"); // 輸出單字符直到 end-of-file while(!feof($myfile)) { echo fgetc($myfile); } fclose($myfile); ?>注釋:在調用 fgetc() 函數之后,文件指針會移動到下一個字符。
PHP 創建文件 - fopen()
如果您用 fopen() 打開並不存在的文件,此函數會創建文件,假定文件被打開為寫入(w)或增加(a)。
下面的例子創建名為 "testfile.txt" 的新文件。此文件將被創建於 PHP 代碼所在的相同目錄中:
$myfile = fopen("testfile.txt", "w")
PHP 文件權限
如果您試圖運行這段代碼時發生錯誤,請檢查您是否有向硬盤寫入信息的 PHP 文件訪問權限。
PHP 寫入文件 - fwrite()
fwrite() 的第一個參數包含要寫入的文件的文件名,第二個參數是被寫的字符串。<?php $myfile = fopen("newfile.txt", "w") or die("Unable to open file!"); $txt = "Bill Gates\n"; fwrite($myfile, $txt); $txt = "Steve Jobs\n"; fwrite($myfile, $txt); fclose($myfile); ?>
PHP 覆蓋(Overwriting)
如果現在 "newfile.txt" 包含了一些數據,我們可以展示在寫入已有文件時發生的的事情。所有已存在的數據會被擦除並以一個新文件開始。
<?php $myfile = fopen("newfile.txt", "w") or die("Unable to open file!"); $txt = "Mickey Mouse\n"; fwrite($myfile, $txt); $txt = "Minnie Mouse\n"; fwrite($myfile, $txt); fclose($myfile); ?>
創建上傳腳本
"upload_file.php" 文件含有供上傳文件的代碼:
<?php if ($_FILES["file"]["error"] > 0) { echo "Error: " . $_FILES["file"]["error"] . "<br />"; } else { echo "Upload: " . $_FILES["file"]["name"] . "<br />"; echo "Type: " . $_FILES["file"]["type"] . "<br />"; echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />"; echo "Stored in: " . $_FILES["file"]["tmp_name"]; } ?>
- $_FILES["file"]["name"] - 被上傳文件的名稱
- $_FILES["file"]["type"] - 被上傳文件的類型
- $_FILES["file"]["size"] - 被上傳文件的大小,以字節計
- $_FILES["file"]["tmp_name"] - 存儲在服務器的文件的臨時副本的名稱
- $_FILES["file"]["error"] - 由文件上傳導致的錯誤代碼
上傳限制
在這個腳本中,我們增加了對文件上傳的限制。用戶只能上傳 .gif 或 .jpeg 文件,文件大小必須小於 20 kb:
<?php if ((($_FILES["file"]["type"] == "image/gif") || ($_FILES["file"]["type"] == "image/jpeg") || ($_FILES["file"]["type"] == "image/pjpeg")) && ($_FILES["file"]["size"] < 20000)) { if ($_FILES["file"]["error"] > 0) { echo "Error: " . $_FILES["file"]["error"] . "<br />"; } else { echo "Upload: " . $_FILES["file"]["name"] . "<br />"; echo "Type: " . $_FILES["file"]["type"] . "<br />"; echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />"; echo "Stored in: " . $_FILES["file"]["tmp_name"]; } } else { echo "Invalid file"; } ?>
注釋:對於 IE,識別 jpg 文件的類型必須是 pjpeg,對於 FireFox,必須是 jpeg。
保存被上傳的文件
上面的例子在服務器的 PHP 臨時文件夾創建了一個被上傳文件的臨時副本。
這個臨時的復制文件會在腳本結束時消失。要保存被上傳的文件,我們需要把它拷貝到另外的位置:
<?php if ((($_FILES["file"]["type"] == "image/gif") || ($_FILES["file"]["type"] == "image/jpeg") || ($_FILES["file"]["type"] == "image/pjpeg")) && ($_FILES["file"]["size"] < 20000)) { if ($_FILES["file"]["error"] > 0) { echo "Return Code: " . $_FILES["file"]["error"] . "<br />"; } else { echo "Upload: " . $_FILES["file"]["name"] . "<br />"; echo "Type: " . $_FILES["file"]["type"] . "<br />"; echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />"; echo "Temp file: " . $_FILES["file"]["tmp_name"] . "<br />"; if (file_exists("upload/" . $_FILES["file"]["name"])) { echo $_FILES["file"]["name"] . " already exists. "; } else { move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]); echo "Stored in: " . "upload/" . $_FILES["file"]["name"]; } } } else { echo "Invalid file"; } ?>
上面的腳本檢測了是否已存在此文件,如果不存在,則把文件拷貝到指定的文件夾。
注釋:這個例子把文件保存到了名為 "upload" 的新文件夾。
cookie 常用於識別用戶。setcookie() 函數用於設置 cookie。
注釋:setcookie() 函數必須位於 <html> 標簽之前。
語法
setcookie(name, value, expire, path, domain);
在下面的例子中,我們將創建名為 "user" 的 cookie,把為它賦值 "Alex Porter"。我們也規定了此 cookie 在一小時后過期:
<?php setcookie("user", "Alex Porter", time()+3600); ?>注釋:在發送 cookie 時,cookie 的值會自動進行 URL 編碼,在取回時進行自動解碼(為防止 URL 編碼,請使用 setrawcookie() 取而代之)。
在下面的例子中,我們取回了名為 "user" 的 cookie 的值,並把它顯示在了頁面上:
<?php // Print a cookie echo $_COOKIE["user"]; // A way to view all cookies print_r($_COOKIE); ?>
在下面的例子中,我們使用 isset() 函數來確認是否已設置了 cookie:
<html> <body> <?php if (isset($_COOKIE["user"])) echo "Welcome " . $_COOKIE["user"] . "!<br />"; else echo "Welcome guest!<br />"; ?> </body> </html>當刪除 cookie 時,您應當使過期日期變更為過去的時間點。
<?php // set the expiration date to one hour ago setcookie("user", "", time()-3600); ?>PHP session 變量用於存儲有關用戶會話的信息,或更改用戶會話的設置。Session 變量保存的信息是單一用戶的,並且可供應用程序中的所有頁面使用。
在您把用戶信息存儲到 PHP session 中之前,首先必須啟動會話。
注釋:session_start() 函數必須位於 <html> 標簽之前
存儲 Session 變量
存儲和取回 session 變量的正確方法是使用 PHP $_SESSION 變量:
<?php session_start(); // store session data $_SESSION['views']=1; ?> <html> <body> <?php //retrieve session data echo "Pageviews=". $_SESSION['views']; ?> </body> </html>
輸出:
Pageviews=1
終結 Session
如果您希望刪除某些 session 數據,可以使用 unset() 或 session_destroy() 函數。
unset() 函數用於釋放指定的 session 變量:
<?php unset($_SESSION['views']); ?>
您也可以通過 session_destroy() 函數徹底終結 session:
<?php session_destroy(); ?>
注釋:session_destroy() 將重置 session,您將失去所有已存儲的 session 數據。
PHP mail() 函數
PHP mail() 函數用於從腳本中發送電子郵件。
語法
mail(to,subject,message,headers,parameters)
參數 | 描述 |
---|---|
to | 必需。規定 email 接收者。 |
subject | 必需。規定 email 的主題。注釋:該參數不能包含任何新行字符。 |
message | 必需。定義要發送的消息。應使用 LF (\n) 來分隔各行。 |
headers | 可選。規定附加的標題,比如 From、Cc 以及 Bcc。 應當使用 CRLF (\r\n) 分隔附加的標題。 |
parameters | 可選。對郵件發送程序規定額外的參數。 |
PHP 簡易 E-Mail
通過 PHP 發送電子郵件的最簡單的方式是發送一封文本 email。
在下面的例子中,我們首先聲明變量($to, $subject, $message, $from, $headers),然后我們在 mail() 函數中使用這些變量來發送了一封 e-mail:
<?php $to = "someone@example.com"; $subject = "Test mail"; $message = "Hello! This is a simple email message."; $from = "someonelse@example.com"; $headers = "From: $from"; mail($to,$subject,$message,$headers); echo "Mail Sent."; ?>
PHP Mail Form
通過 PHP,您能夠在自己的站點制作一個反饋表單。下面的例子向指定的 e-mail 地址發送了一條文本消息:
<html>
<body>
<?php
if (isset($_REQUEST['email']))
//if "email" is filled out, send email
{
//send email
$email = $_REQUEST['email'] ;
$subject = $_REQUEST['subject'] ;
$message = $_REQUEST['message'] ;
mail( "someone@example.com", "Subject: $subject",
$message, "From: $email" );
echo "Thank you for using our mail form";
}
else
//if "email" is not filled out, display the form
{
echo "<form method='post' action='mailform.php'>
Email: <input name='email' type='text' /><br />
Subject: <input name='subject' type='text' /><br />
Message:<br />
<textarea name='message' rows='15' cols='40'>
</textarea><br />
<input type='submit' />
</form>";
}
?>
</body>
</html>
例子解釋:
- 首先,檢查是否填寫了郵件輸入框
- 如果未填寫(比如在頁面被首次訪問時),輸出 HTML 表單
- 如果已填寫(在表單被填寫后),從表單發送郵件
- 當點擊提交按鈕后,重新載入頁面,顯示郵件發送成功的消息
PHP 防止 E-mail 注入
防止 e-mail 注入的最好方法是對輸入進行驗證。
<html>
<body>
<?php
function spamcheck($field)
{
//filter_var() sanitizes the e-mail
//address using FILTER_SANITIZE_EMAIL
$field=filter_var($field, FILTER_SANITIZE_EMAIL
);
//filter_var() validates the e-mail
//address using FILTER_VALIDATE_EMAIL
if(filter_var($field, FILTER_VALIDATE_EMAIL
))
{
return TRUE;
}
else
{
return FALSE;
}
}
if (isset($_REQUEST['email']))
{//if "email" is filled out, proceed
//check if the email address is invalid
$mailcheck = spamcheck($_REQUEST['email']);
if ($mailcheck==FALSE)
{
echo "Invalid input";
}
else
{//send email
$email = $_REQUEST['email'] ;
$subject = $_REQUEST['subject'] ;
$message = $_REQUEST['message'] ;
mail("someone@example.com", "Subject: $subject",
$message, "From: $email" );
echo "Thank you for using our mail form";
}
}
else
{//if "email" is not filled out, display the form
echo "<form method='post' action='mailform.php'>
Email: <input name='email' type='text' /><br />
Subject: <input name='subject' type='text' /><br />
Message:<br />
<textarea name='message' rows='15' cols='40'>
</textarea><br />
<input type='submit' />
</form>";
}
?>
</body>
</html>
在上面的代碼中,我們使用了 PHP 過濾器來對輸入進行驗證:
- FILTER_SANITIZE_EMAIL 從字符串中刪除電子郵件的非法字符
- FILTER_VALIDATE_EMAIL 驗證電子郵件地址
基本的錯誤處理:使用 die() 函數
die("File not found");
創建自定義錯誤處理器
創建一個自定義的錯誤處理器非常簡單。我們很簡單地創建了一個專用函數,可以在 PHP 中發生錯誤時調用該函數。
該函數必須有能力處理至少兩個參數 (error level 和 error message),但是可以接受最多五個參數(可選的:file, line-number 以及 error context):
語法
error_function(error_level,error_message,
error_file,error_line,error_context)
參數 | 描述 |
---|---|
error_level | 必需。為用戶定義的錯誤規定錯誤報告級別。必須是一個值數。 參見下面的表格:錯誤報告級別。 |
error_message | 必需。為用戶定義的錯誤規定錯誤消息。 |
error_file | 可選。規定錯誤在其中發生的文件名。 |
error_line | 可選。規定錯誤發生的行號。 |
error_context | 可選。規定一個數組,包含了當錯誤發生時在用的每個變量以及它們的值。 |
錯誤報告級別
值 | 常量 | 描述 |
---|---|---|
2 | E_WARNING | 非致命的 run-time 錯誤。不暫停腳本執行。 |
8 | E_NOTICE | Run-time 通知。 腳本發現可能有錯誤發生,但也可能在腳本正常運行時發生。 |
256 | E_USER_ERROR | 致命的用戶生成的錯誤。這類似於程序員使用 PHP 函數 trigger_error() 設置的 E_ERROR。 |
512 | E_USER_WARNING | 非致命的用戶生成的警告。這類似於程序員使用 PHP 函數 trigger_error() 設置的 E_WARNING。 |
1024 | E_USER_NOTICE | 用戶生成的通知。這類似於程序員使用 PHP 函數 trigger_error() 設置的 E_NOTICE。 |
4096 | E_RECOVERABLE_ERROR | 可捕獲的致命錯誤。類似 E_ERROR,但可被用戶定義的處理程序捕獲。(參見 set_error_handler()) |
8191 | E_ALL | 所有錯誤和警告,除級別 E_STRICT 以外。 (在 PHP 6.0,E_STRICT 是 E_ALL 的一部分) |
function customError($errno, $errstr)
{
echo "<b>Error:</b> [$errno] $errstr<br />";
echo "Ending Script";
die();
}
上面的代碼是一個簡單的錯誤處理函數。當它被觸發時,它會取得錯誤級別和錯誤消息。然后它會輸出錯誤級別和消息,並終止腳本。
Set Error Handler
PHP 的默認錯誤處理程序是內建的錯誤處理程序。我們打算把上面的函數改造為腳本運行期間的默認錯誤處理程序。
可以修改錯誤處理程序,使其僅應用到某些錯誤,這樣腳本就可以不同的方式來處理不同的錯誤。不過,在本例中,我們打算針對所有錯誤來使用我們的自定義錯誤處理程序:
set_error_handler("customError");
由於我們希望我們的自定義函數來處理所有錯誤,set_error_handler() 僅需要一個參數,可以添加第二個參數來規定錯誤級別。
觸發錯誤
在腳本中用戶輸入數據的位置,當用戶的輸入無效時觸發錯誤的很有用的。在 PHP 中,這個任務由 trigger_error() 完成。
您可以在腳本中任何位置觸發錯誤,通過添加的第二個參數,您能夠規定所觸發的錯誤級別。可能的錯誤類型:
- E_USER_ERROR - 致命的用戶生成的 run-time 錯誤。錯誤無法恢復。腳本執行被中斷。
- E_USER_WARNING - 非致命的用戶生成的 run-time 警告。腳本執行不被中斷。
- E_USER_NOTICE - 默認。用戶生成的 run-time 通知。腳本發現了可能的錯誤,也有可能在腳本運行正常時發生。
錯誤記錄
默認地,根據在 php.ini 中的 error_log 配置,PHP 向服務器的錯誤記錄系統或文件發送錯誤記錄。通過使用 error_log() 函數,您可以向指定的文件或遠程目的地發送錯誤記錄。
通過電子郵件向您自己發送錯誤消息,是一種獲得指定錯誤的通知的好辦法。
通過 E-Mail 發送錯誤消息
在下面的例子中,如果特定的錯誤發生,我們將發送帶有錯誤消息的電子郵件,並結束腳本:
<?php //error handler function function customError($errno, $errstr) { echo "<b>Error:</b> [$errno] $errstr<br />"; echo "Webmaster has been notified"; error_log("Error: [$errno] $errstr",1, "someone@example.com","From: webmaster@example.com"); } //set error handler set_error_handler("customError",E_USER_WARNING); //trigger error $test=2; if ($test>1) { trigger_error("Value must be 1 or below",E_USER_WARNING); } ?>
以上代碼的輸出應該類似這樣:
Error: [512] Value must be 1 or below Webmaster has been notified
接收自以上代碼的郵件類似這樣:
Error: [512] Value must be 1 or below
這個方法不適合所有的錯誤。常規錯誤應當通過使用默認的 PHP 記錄系統在服務器上進行記錄。
異常(Exception)用於在指定的錯誤發生時改變腳本的正常流程。當異常被觸發時,通常會發生:
- 當前代碼狀態被保存
- 代碼執行被切換到預定義的異常處理器函數
- 根據情況,處理器也許會從保存的代碼狀態重新開始執行代碼,終止腳本執行,或從代碼中另外的位置繼續執行腳本
異常的基本使用
當異常被拋出時,其后的代碼不會繼續執行,PHP 會嘗試查找匹配的 "catch" 代碼塊。
如果異常沒有被捕獲,而且又沒用使用 set_exception_handler() 作相應的處理的話,那么將發生一個嚴重的錯誤(致命錯誤),並且輸出 "Uncaught Exception" (未捕獲異常)的錯誤消息。
正確的處理程序應當包括:
- Try - 使用異常的函數應該位於 "try" 代碼塊內。如果沒有觸發異常,則代碼將照常繼續執行。但是如果異常被觸發,會拋出一個異常。
- Throw - 這里規定如何觸發異常。每一個 "throw" 必須對應至少一個 "catch"
- Catch - "catch" 代碼塊會捕獲異常,並創建一個包含異常信息的對象
創建一個自定義的 Exception 類
這個自定義的 exception 類繼承了 PHP 的 exception 類的所有屬性,您可向其添加自定義的函數。<?php class customException extends Exception { public function errorMessage() { //error message $errorMsg = 'Error on line '.$this->getLine().' in '.$this->getFile() .': <b>'.$this->getMessage().'</b> is not a valid E-Mail address'; return $errorMsg; } } $email = "someone@example...com"; try { //check if if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) { //throw exception if email is not valid throw new customException($email); } } catch (customException $e) { //display custom message echo $e->errorMessage(); } ?>
例子解釋:
上面的代碼拋出了一個異常,並通過一個自定義的 exception 類來捕獲它:
- customException() 類是作為舊的 exception 類的一個擴展來創建的。這樣它就繼承了舊類的所有屬性和方法。
- 創建 errorMessage() 函數。如果 e-mail 地址不合法,則該函數返回一條錯誤消息
- 把 $email 變量設置為不合法的 e-mail 地址字符串
- 執行 "try" 代碼塊,由於 e-mail 地址不合法,因此拋出一個異常
- "catch" 代碼塊捕獲異常,並顯示錯誤消息
多個異常
可以使用多個 if..else 代碼塊,或一個 switch 代碼塊,或者嵌套多個異常。這些異常能夠使用不同的 exception 類,並返回不同的錯誤消息:<?php
class customException extends Exception
{
public function errorMessage()
{
//error message
$errorMsg = 'Error on line '.$this->getLine().' in '.$this->getFile()
.': <b>'.$this->getMessage().'</b> is not a valid E-Mail address';
return $errorMsg;
}
}
$email = "someone@example.com";
try
{
//check if
if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE)
{
//throw exception if email is not valid
throw new customException($email);
}
//check for "example" in mail address
if(strpos($email, "example") !== FALSE)
{
throw new Exception("$email is an example e-mail");
}
}
catch (customException $e)
{
echo $e->errorMessage();
}
catch(Exception $e)
{
echo $e->getMessage();
}
?>
例子解釋:
上面的代碼測試了兩種條件,如何任何條件不成立,則拋出一個異常:
- customException() 類是作為舊的 exception 類的一個擴展來創建的。這樣它就繼承了舊類的所有屬性和方法。
- 創建 errorMessage() 函數。如果 e-mail 地址不合法,則該函數返回一個錯誤消息。
- 執行 "try" 代碼塊,在第一個條件下,不會拋出異常。
- 由於 e-mail 含有字符串 "example",第二個條件會觸發異常。
- "catch" 代碼塊會捕獲異常,並顯示恰當的錯誤消息
如果沒有捕獲 customException,緊緊捕獲了 base exception,則在那里處理異常。
重新拋出異常
有時,當異常被拋出時,您也許希望以不同於標准的方式對它進行處理。可以在一個 "catch" 代碼塊中再次拋出異常。
腳本應該對用戶隱藏系統錯誤。對程序員來說,系統錯誤也許很重要,但是用戶對它們並不感興趣。為了讓用戶更容易使用,您可以再次拋出帶有對用戶比較友好的消息的異常:
<?php
class customException extends Exception
{
public function errorMessage()
{
//error message
$errorMsg = $this->getMessage().' is not a valid E-Mail address.';
return $errorMsg;
}
}
$email = "someone@example.com";
try
{
try
{
//check for "example" in mail address
if(strpos($email, "example") !== FALSE)
{
//throw exception if email is not valid
throw new Exception($email);
}
}
catch(Exception $e)
{
//re-throw exception
throw new customException($email);
}
}
catch (customException $e)
{
//display custom message
echo $e->errorMessage();
}
?>
例子解釋:
上面的代碼檢測在郵件地址中是否含有字符串 "example"。如果有,則再次拋出異常:
- customException() 類是作為舊的 exception 類的一個擴展來創建的。這樣它就繼承了舊類的所有屬性和方法。
- 創建 errorMessage() 函數。如果 e-mail 地址不合法,則該函數返回一個錯誤消息。
- 把 $email 變量設置為一個有效的郵件地址,但含有字符串 "example"。
- "try" 代碼塊包含另一個 "try" 代碼塊,這樣就可以再次拋出異常。
- 由於 e-mail 包含字符串 "example",因此觸發異常。
- "catch" 捕獲到該異常,並重新拋出 "customException"。
- 捕獲到 "customException",並顯示一條錯誤消息。
如果在其目前的 "try" 代碼塊中異常沒有被捕獲,則它將在更高層級上查找 catch 代碼塊。
設置頂層異常處理器 (Top Level Exception Handler)
set_exception_handler() 函數可設置處理所有未捕獲異常的用戶定義函數。
<?php
function myException($exception)
{
echo "<b>Exception:</b> " , $exception->getMessage();
}
set_exception_handler('myException');
throw new Exception('Uncaught Exception occurred');
?>
以上代碼的輸出應該類似這樣:
Exception: Uncaught Exception occurred
在上面的代碼中,不存在 "catch" 代碼塊,而是觸發頂層的異常處理程序。應該使用此函數來捕獲所有未被捕獲的異常。
異常的規則
- 需要進行異常處理的代碼應該放入 try 代碼塊內,以便捕獲潛在的異常。
- 每個 try 或 throw 代碼塊必須至少擁有一個對應的 catch 代碼塊。
- 使用多個 catch 代碼塊可以捕獲不同種類的異常。
- 可以在 try 代碼塊內的 catch 代碼塊中再次拋出(re-thrown)異常。
簡而言之:如果拋出了異常,就必須捕獲它。
PHP 過濾器用於驗證和過濾來自非安全來源的數據,比如用戶的輸入。
您應該始終對外部數據進行過濾!
什么是外部數據?
- 來自表單的輸入數據
- Cookies
- 服務器變量
- 數據庫查詢結果
函數和過濾器
如需過濾變量,請使用下面的過濾器函數之一:
- filter_var() - 通過一個指定的過濾器來過濾單一的變量
- filter_var_array() - 通過相同的或不同的過濾器來過濾多個變量
- filter_input - 獲取一個輸入變量,並對它進行過濾
- filter_input_array - 獲取多個輸入變量,並通過相同的或不同的過濾器對它們進行過濾
在下面的例子中,我們用 filter_var() 函數驗證了一個整數:
<?php
$int = 123;
if(!filter_var($int, FILTER_VALIDATE_INT)
)
{
echo("Integer is not valid");
}
else
{
echo("Integer is valid");
}
?>
Validating 和 Sanitizing
有兩種過濾器:
Validating 過濾器:
- 用於驗證用戶輸入
- 嚴格的格式規則(比如 URL 或 E-Mail 驗證)
- 如果成功則返回預期的類型,如果失敗則返回 FALSE
Sanitizing 過濾器:
- 用於允許或禁止字符串中指定的字符
- 無數據格式規則
- 始終返回字符串
選項和標志
選項和標志用於向指定的過濾器添加額外的過濾選項。
不同的過濾器有不同的選項和標志。
在下面的例子中,我們用 filter_var() 和 "min_range" 以及 "max_range" 選項驗證了一個整數:
<?php
$var=300;
$int_options = array(
"options"=>array
(
"min_range"=>0,
"max_range"=>256
)
);
if(!filter_var($var, FILTER_VALIDATE_INT, $int_options)
)
{
echo("Integer is not valid");
}
else
{
echo("Integer is valid");
}
?>
驗證輸入
我們需要作的第一件事情是確認是否存在我們正在查找的輸入數據。
然后我們用 filter_input() 函數過濾輸入的數據。
在下面的例子中,輸入變量 "email" 被傳到 PHP 頁面:
<?php
if(!filter_has_var(INPUT_GET, "email"))
{
echo("Input type does not exist");
}
else
{
if (!filter_input(INPUT_GET, "email", FILTER_VALIDATE_EMAIL)
)
{
echo "E-Mail is not valid";
}
else
{
echo "E-Mail is valid";
}
}
?>
例子解釋:
上面的例子有一個通過 "GET" 方法傳送的輸入變量 (email):
- 檢測是否存在 "GET" 類型的 "email" 輸入變量
- 如果存在輸入變量,檢測它是否是有效的郵件地址
凈化輸入
讓我們試着清理一下從表單傳來的 URL。
首先,我們要確認是否存在我們正在查找的輸入數據。
然后,我們用 filter_input() 函數來凈化輸入數據。
在下面的例子中,輸入變量 "url" 被傳到 PHP 頁面:
<?php
if(!filter_has_var(INPUT_POST, "url"))
{
echo("Input type does not exist");
}
else
{
$url = filter_input(INPUT_POST, "url", FILTER_SANITIZE_URL)
;
}
?>
例子解釋:
上面的例子有一個通過 "POST" 方法傳送的輸入變量 (url):
- 檢測是否存在 "POST" 類型的 "url" 輸入變量
- 如果存在此輸入變量,對其進行凈化(刪除非法字符),並將其存儲在 $url 變量中
假如輸入變量類似這樣:"http://www.W3非o法ol.com.c字符n/",則凈化后的 $url 變量應該是這樣的:
http://www.W3School.com.cn/
過濾多個輸入
表單通常由多個輸入字段組成。為了避免對 filter_var 或 filter_input 重復調用,我們可以使用 filter_var_array 或 the filter_input_array 函數。
在本例中,我們使用 filter_input_array() 函數來過濾三個 GET 變量。接收到的 GET 變量是一個名字、一個年齡以及一個郵件地址:
<?php
$filters = array
(
"name" => array
(
"filter"=>FILTER_SANITIZE_STRING
),
"age" => array
(
"filter"=>FILTER_VALIDATE_INT,
"options"=>array
(
"min_range"=>1,
"max_range"=>120
)
),
"email"=> FILTER_VALIDATE_EMAIL,
);
$result = filter_input_array(INPUT_GET, $filters)
;
if (!$result["age"])
{
echo("Age must be a number between 1 and 120.<br />");
}
elseif(!$result["email"])
{
echo("E-Mail is not valid.<br />");
}
else
{
echo("User input is valid");
}
?>
例子解釋:
上面的例子有三個通過 "GET" 方法傳送的輸入變量 (name, age and email)
- 設置一個數組,其中包含了輸入變量的名稱,以及用於指定的輸入變量的過濾器
- 調用 filter_input_array 函數,參數包括 GET 輸入變量及剛才設置的數組
- 檢測 $result 變量中的 "age" 和 "email" 變量是否有非法的輸入。(如果存在非法輸入,)
filter_input_array() 函數的第二個參數可以是數組或單一過濾器的 ID。
如果該參數是單一過濾器的 ID,那么這個指定的過濾器會過濾輸入數組中所有的值。
如果該參數是一個數組,那么此數組必須遵循下面的規則:
- 必須是一個關聯數組,其中包含的輸入變量是數組的鍵(比如 "age" 輸入變量)
- 此數組的值必須是過濾器的 ID ,或者是規定了過濾器、標志以及選項的數組
使用 Filter Callback
通過使用 FILTER_CALLBACK 過濾器,可以調用自定義的函數,把它作為一個過濾器來使用。這樣,我們就擁有了數據過濾的完全控制權。
您可以創建自己的自定義函數,也可以使用已有的 PHP 函數。
規定您准備用到過濾器函數的方法,與規定選項的方法相同。
在下面的例子中,我們使用了一個自定義的函數把所有 "_" 轉換為空格:
<?php
function convertSpace($string)
{
return str_replace("_", " ", $string);
}
$string = "Peter_is_a_great_guy!";
echo filter_var($string, FILTER_CALLBACK, array("options"=>"convertSpace"))
;
?>
以上代碼的結果是這樣的:
Peter is a great guy!
例子解釋:
上面的例子把所有 "_" 轉換成空格:
- 創建一個把 "_" 替換為空格的函數
- 調用 filter_var() 函數,它的參數是 FILTER_CALLBACK 過濾器以及包含我們的函數的數組