Php高级知识 2

8、PHP Cookies

cookie 常用于识别用户。

8.1 什么是 Cookie?

cookie 常用于识别用户。cookie 是服务器留在用户计算机中的小文件。每当相同的计算机通过浏览器请求页面时,它同时会发送 cookie。通过 PHP,您能够创建并取回 cookie 的值。

8.2 如何创建 cookie?

setcookie() 函数用于设置 cookie。

注释:setcookie() 函数必须位于 <html> 标签之前。

语法

setcookie(name, value, expire, path, domain);

例子

在下面的例子中,我们将创建名为 "user" 的 cookie,把为它赋值 "Alex Porter"。我们也规定了此 cookie 在一小时后过期:

<?php
setcookie("user", "Alex Porter", time()+3600);
?>

<html>
<body>

</body>
</html>

注释:在发送 cookie 时,cookie 的值会自动进行 URL 编码,在取回时进行自动解码(为防止 URL 编码,请使用 setrawcookie() 取而代之)。

8.3 如何取回 Cookie 的值?

PHP 的 $_COOKIE 变量用于取回 cookie 的值。

在下面的例子中,我们取回了名为 "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>

8.4 如何删除 cookie?

当删除 cookie 时,您应当使过期日期变更为过去的时间点。

删除的例子:

<?php
// set the expiration date to one hour ago
setcookie("user", "", time()-3600);
?>

8.5 如果浏览器不支持 cookie 该怎么办?

如果应用程序涉及不支持 cookie 的浏览器,应采取其他方法在应用程序中从一张页面向另一张页面传递信息。一种方式是从表单传递数据(有关表单和用户输入的内容,在前面已介绍过了)。

下面的表单在用户单击提交按钮时向 "welcome.php" 提交了用户输入:

<html>
<body>

<form action="welcome.php" method="post">
Name: <input type="text" name="name" />
Age: <input type="text" name="age" />
<input type="submit" />
</form>

</body>
</html>

取回 "welcome.php" 中的值,就像这样:

<html>
<body>

Welcome <?php echo $_POST["name"]; ?>.<br />
You are <?php echo $_POST["age"]; ?> years old.

</body>
</html>

9、PHP Sessions

PHP session 变量用于存储有关用户会话的信息,或更改用户会话的设置。Session 变量保存的信息是单一用户的,并且可供应用程序中的所有页面使用。

9.1 PHP Session 变量

当运行一个应用程序时,会打开它,做些更改,然后关闭它。这很像一次会话。计算机清楚你是谁。它知道你何时启动应用程序,并在何时终止。但是在因特网上,存在一个问题:服务器不知道你是谁以及你做什么,这是由于 HTTP 地址不能维持状态。

通过在服务器上存储用户信息以便随后使用,PHP session 解决了这个问题(比如用户名称、购买商品等)。不过,会话信息是临时的,在用户离开网站后将被删除。如果需要永久储存信息,可以把数据存储在数据库中。

Session 的工作机制是:为每个访问者创建一个唯一的 id (UID),并基于这个 UID 来存储变量。UID 存储在 cookie 中,亦或通过 URL 进行传导。

9.2 开始 PHP Session

在把用户信息存储到 PHP session 中之前,首先必须启动会话。

注释:session_start() 函数必须位于 <html> 标签之前:

<?php session_start(); ?>

<html>
<body>

</body>
</html>

上面的代码会向服务器注册用户的会话,以便您可以开始保存用户信息,同时会为用户会话分配一个 UID。

9.3 存储 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

在下面的例子中,我们创建了一个简单的 page-view 计数器。isset() 函数检测是否已设置 "views" 变量。如果已设置 "views" 变量,我们累加计数器。如果 "views" 不存在,则我们创建 "views" 变量,并把它设置为 1:

<?php
session_start();

if(isset($_SESSION[‘views‘]))
  $_SESSION[‘views‘]=$_SESSION[‘views‘]+1;

else
  $_SESSION[‘views‘]=1;
echo "Views=". $_SESSION[‘views‘];
?>

9.4 终结 Session

如果希望删除某些 session 数据,可以使用 unset() 或 session_destroy() 函数。

unset() 函数用于释放指定的 session 变量:

<?php
unset($_SESSION[‘views‘]);
?>

您也可以通过 session_destroy() 函数彻底终结 session:

<?php
session_destroy();
?>

注释:session_destroy() 将重置 session,您将失去所有已存储的 session 数据。

10、PHP 发送电子邮件

PHP 允许您从脚本直接发送电子邮件。

10.1 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 需要一个已安装且正在运行的邮件系统,以便使邮件函数可用。所用的程序通过在 php.ini 文件中的配置设置进行定义。

10.2 PHP 简易 E-Mail

通过 PHP 发送电子邮件的最简单的方式是发送一封文本 email。

在下面的例子中,我们首先声明变量($to, $subject, $message, $from, $headers),然后我们在 mail() 函数中使用这些变量来发送了一封 e-mail:

<?php

$to = "[email protected]";
$subject = "Test mail";
$message = "Hello! This is a simple email message.";
$from = "[email protected]";
$headers = "From: $from";
mail($to,$subject,$message,$headers);
echo "Mail Sent.";

?>

10.3 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( "[email protected]", "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>

例子解释:

  1. 首先,检查是否填写了邮件输入框
  2. 如果未填写(比如在页面被首次访问时),输出 HTML 表单
  3. 如果已填写(在表单被填写后),从表单发送邮件
  4. 当点击提交按钮后,重新载入页面,显示邮件发送成功的消息

11、PHP 安全的电子邮件

在前面的 PHP e-mail 脚本中,存在着一个漏洞。

11.1 PHP E-mail 注入

首先,请看前面的 PHP 代码:

<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("[email protected]", "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>

以上代码存在的问题是,未经授权的用户可通过输入表单在邮件头部插入数据。

假如用户在表单中的输入框内加入这些文本,会出现什么情况呢?

[email protected]%0ACc:[email protected]
%0ABcc:[email protected],[email protected],
[email protected],[email protected]
%0ABTo:[email protected]

与往常一样,mail() 函数把上面的文本放入邮件头部,那么现在头部有了额外的 Cc:, Bcc: 以及 To: 字段。当用户点击提交按钮时,这封 e-mail 会被发送到上面所有的地址!

11.2 PHP 防止 E-mail 注入

防止 e-mail 注入的最好方法是对输入进行验证。

下面的代码增加了检测表单中 email 字段的输入验证程序:

<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("[email protected]", "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 验证电子邮件地址

12、PHP 错误处理

在 PHP 中,默认的错误处理很简单。一条消息会被发送到浏览器,这条消息带有文件名、行号以及一条描述错误的消息。

12.1 PHP 错误处理

在创建脚本和 web 应用程序时,错误处理是一个重要的部分。如果代码缺少错误检测编码,那么程序看上去很不专业,也为安全风险敞开了大门。

下面介绍 PHP 中一些最为重要的错误检测方法。

介绍不同的错误处理方法:

  • 简单的 "die()" 语句
  • 自定义错误和错误触发器
  • 错误报告

12.2 基本的错误处理:使用 die() 函数

第一个例子展示了一个打开文本文件的简单脚本:

<?php
$file=fopen("welcome.txt","r");
?>

如果文件不存在,会获得类似这样的错误:

Warning: fopen(welcome.txt) [function.fopen]: failed to open stream:
No such file or directory in C:\webfolder\test.php on line 2

为了避免用户获得类似上面的错误消息,在访问文件之前检测该文件是否存在:

<?php
if(!file_exists("welcome.txt"))
 {
 die("File not found");
 }
else
 {
 $file=fopen("welcome.txt","r");
 }
?>

现在,假如文件不存在,会得到类似这样的错误消息:

File not found

比起之前的代码,上面的代码更有效,这是由于它采用了一个简单的错误处理机制在错误之后终止了脚本。

不过,简单地终止脚本并不总是恰当的方式。

12.3 创建自定义错误处理器

创建一个自定义的错误处理器非常简单。简单地创建了一个专用函数,可以在 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 可选。规定一个数组,包含了当错误发生时在用的每个变量以及它们的值。

12.4 错误报告级别

这些错误报告级别是错误处理程序旨在处理的错误的不同的类型:

错误报告级别
常量 描述
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();
 }

上面的代码是一个简单的错误处理函数。当它被触发时,它会取得错误级别和错误消息。然后它会输出错误级别和消息,并终止脚本。

现在,我们已经创建了一个错误处理函数,我们需要确定在何时触发该函数。

12.5 Set Error Handler

PHP 的默认错误处理程序是内建的错误处理程序。想把上面的函数改造为脚本运行期间的默认错误处理程序。

可以修改错误处理程序,使其仅应用到某些错误,这样脚本就可以不同的方式来处理不同的错误。不过,在本例中,针对所有错误来使用我们的自定义错误处理程序:

set_error_handler("customError");

由于希望自定义函数来处理所有错误,set_error_handler() 仅需要一个参数,可以添加第二个参数来规定错误级别。

实例

通过尝试输出不存在的变量,来测试这个错误处理程序:

<?php
//error handler function
function customError($errno, $errstr)
 {
 echo "<b>Error:</b> [$errno] $errstr";
 }

//set error handler
set_error_handler("customError");

//trigger error
echo($test);
?>

以上代码的输出应该类似这样:

Error: [8] Undefined variable: test

12.6 触发错误

在脚本中用户输入数据的位置,当用户的输入无效时触发错误的很有用的。在 PHP 中,这个任务由 trigger_error() 完成。

例子

在本例中,如果 "test" 变量大于 "1",就会发生错误:

<?php
$test=2;
if ($test>1)
{
trigger_error("Value must be 1 or below");
}
?>

以上代码的输出应该类似这样:

Notice: Value must be 1 or below
in C:\webfolder\test.php on line 6

可以在脚本中任何位置触发错误,通过添加的第二个参数,能够规定所触发的错误级别。

可能的错误类型:

  • E_USER_ERROR - 致命的用户生成的 run-time 错误。错误无法恢复。脚本执行被中断。
  • E_USER_WARNING - 非致命的用户生成的 run-time 警告。脚本执行不被中断。
  • E_USER_NOTICE - 默认。用户生成的 run-time 通知。脚本发现了可能的错误,也有可能在脚本运行正常时发生。

例子

在本例中,如果 "test" 变量大于 "1",则发生 E_USER_WARNING 错误。如果发生了 E_USER_WARNING,将使用自定义错误处理程序并结束脚本:

<?php
//error handler function
function customError($errno, $errstr)
 {
 echo "<b>Error:</b> [$errno] $errstr<br />";
 echo "Ending Script";
 die();
 }

//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
Ending Script

现在,已经介绍了如何创建自己的 error,以及如何触发它们,现在介绍一下错误记录。

12.7 错误记录

默认地,根据在 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,
 "[email protected]","From: [email protected]");
}

//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 记录系统在服务器上进行记录。

13、PHP 异常处理

异常(Exception)用于在指定的错误发生时改变脚本的正常流程。

13.1 什么是异常?

PHP 5 提供了一种新的面向对象的错误处理方法。

异常处理用于在指定的错误(异常)情况发生时改变脚本的正常流程。这种情况称为异常。

当异常被触发时,通常会发生:

  • 当前代码状态被保存
  • 代码执行被切换到预定义的异常处理器函数
  • 根据情况,处理器也许会从保存的代码状态重新开始执行代码,终止脚本执行,或从代码中另外的位置继续执行脚本

我们将介绍不同的错误处理方法:

  • 异常的基本使用
  • 创建自定义的异常处理器
  • 多个异常
  • 重新抛出异常
  • 设置顶层异常处理器

13.2 异常的基本使用

当异常被抛出时,其后的代码不会继续执行,PHP 会尝试查找匹配的 "catch" 代码块。

如果异常没有被捕获,而且又没用使用 set_exception_handler() 作相应的处理的话,那么将发生一个严重的错误(致命错误),并且输出 "Uncaught Exception" (未捕获异常)的错误消息。

尝试抛出一个异常,同时不去捕获它:

<?php
//create function with an exception
function checkNum($number)
 {
 if($number>1)
  {
  throw new Exception("Value must be 1 or below");
  }
 return true;
 }

//trigger exception
checkNum(2);
?>

上面的代码会获得类似这样的一个错误:

Fatal error: Uncaught exception ‘Exception‘
with message ‘Value must be 1 or below‘ in C:\webfolder\test.php:6
Stack trace: #0 C:\webfolder\test.php(12):
checkNum(28) #1 {main} thrown in C:\webfolder\test.php on line 6

13.3 Try, throw 和 catch

要避免上面例子出现的错误,我们需要创建适当的代码来处理异常。

正确的处理程序应当包括:

  1. Try - 使用异常的函数应该位于 "try" 代码块内。如果没有触发异常,则代码将照常继续执行。但是如果异常被触发,会抛出一个异常。
  2. Throw - 这里规定如何触发异常。每一个 "throw" 必须对应至少一个 "catch"
  3. Catch - "catch" 代码块会捕获异常,并创建一个包含异常信息的对象

让我们触发一个异常:

<?php
//创建可抛出一个异常的函数
function checkNum($number)
 {
 if($number>1)
  {
  throw new Exception("Value must be 1 or below");
  }
 return true;
 }

//在 "try" 代码块中触发异常
try
 {
 checkNum(2);
 //If the exception is thrown, this text will not be shown
 echo ‘If you see this, the number is 1 or below‘;
 }

//捕获异常
catch(Exception $e)
 {
 echo ‘Message: ‘ .$e->getMessage();
 }
?>

上面代码将获得类似这样一个错误:

Message: Value must be 1 or below 

例子解释:

上面的代码抛出了一个异常,并捕获了它:

  1. 创建 checkNum() 函数。它检测数字是否大于 1。如果是,则抛出一个异常。
  2. 在 "try" 代码块中调用 checkNum() 函数。
  3. checkNum() 函数中的异常被抛出
  4. "catch" 代码块接收到该异常,并创建一个包含异常信息的对象 ($e)。
  5. 通过从这个 exception 对象调用 $e->getMessage(),输出来自该异常的错误消息

不过,为了遵循“每个 throw 必须对应一个 catch”的原则,可以设置一个顶层的异常处理器来处理漏掉的错误。

13.4 创建一个自定义的 Exception 类

创建自定义的异常处理程序非常简单。简单地创建了一个专门的类,当 PHP 中发生异常时,可调用其函数。该类必须是 exception 类的一个扩展。

这个自定义的 exception 类继承了 PHP 的 exception 类的所有属性,您可向其添加自定义的函数。

开始创建 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 = "[email protected]";

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 类的副本,外加 errorMessage() 函数。正因为它是旧类的副本,因此它从旧类继承了属性和方法,可以使用 exception 类的方法,比如 getLine() 、 getFile() 以及 getMessage()。

例子解释:

上面的代码抛出了一个异常,并通过一个自定义的 exception 类来捕获它:

  1. customException() 类是作为旧的 exception 类的一个扩展来创建的。这样它就继承了旧类的所有属性和方法。
  2. 创建 errorMessage() 函数。如果 e-mail 地址不合法,则该函数返回一条错误消息
  3. 把 $email 变量设置为不合法的 e-mail 地址字符串
  4. 执行 "try" 代码块,由于 e-mail 地址不合法,因此抛出一个异常
  5. "catch" 代码块捕获异常,并显示错误消息

13.5 多个异常

可以为一段脚本使用多个异常,来检测多种情况。

可以使用多个 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 = "[email protected]";

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();
 }
?>

例子解释:

上面的代码测试了两种条件,如何任何条件不成立,则抛出一个异常:

  1. customException() 类是作为旧的 exception 类的一个扩展来创建的。这样它就继承了旧类的所有属性和方法。
  2. 创建 errorMessage() 函数。如果 e-mail 地址不合法,则该函数返回一个错误消息。
  3. 执行 "try" 代码块,在第一个条件下,不会抛出异常。
  4. 由于 e-mail 含有字符串 "example",第二个条件会触发异常。
  5. "catch" 代码块会捕获异常,并显示恰当的错误消息

如果没有捕获 customException,紧紧捕获了 base exception,则在那里处理异常。

13.6 重新抛出异常

有时,当异常被抛出时,希望以不同于标准的方式对它进行处理。可以在一个 "catch" 代码块中再次抛出异常。

脚本应该对用户隐藏系统错误。对程序员来说,系统错误也许很重要,但是用户对它们并不感兴趣。为了让用户更容易使用,您可以再次抛出带有对用户比较友好的消息的异常:

<?php
class customException extends Exception
 {
 public function errorMessage()
  {
  //error message
  $errorMsg = $this->getMessage().‘ is not a valid E-Mail address.‘;
  return $errorMsg;
  }
 }

$email = "[email protected]";

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"。如果有,则再次抛出异常:

  1. customException() 类是作为旧的 exception 类的一个扩展来创建的。这样它就继承了旧类的所有属性和方法。
  2. 创建 errorMessage() 函数。如果 e-mail 地址不合法,则该函数返回一个错误消息。
  3. 把 $email 变量设置为一个有效的邮件地址,但含有字符串 "example"。
  4. "try" 代码块包含另一个 "try" 代码块,这样就可以再次抛出异常。
  5. 由于 e-mail 包含字符串 "example",因此触发异常。
  6. "catch" 捕获到该异常,并重新抛出 "customException"。
  7. 捕获到 "customException",并显示一条错误消息。

如果在其目前的 "try" 代码块中异常没有被捕获,则它将在更高层级上查找 catch 代码块。

13.7 设置顶层异常处理器 (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" 代码块,而是触发顶层的异常处理程序。应该使用此函数来捕获所有未被捕获的异常。

13.8 异常的规则

  • 需要进行异常处理的代码应该放入 try 代码块内,以便捕获潜在的异常。
  • 每个 try 或 throw 代码块必须至少拥有一个对应的 catch 代码块。
  • 使用多个 catch 代码块可以捕获不同种类的异常。
  • 可以在 try 代码块内的 catch 代码块中再次抛出(re-thrown)异常。

简而言之:如果抛出了异常,就必须捕获它。

14、PHP 过滤器(Filter)

PHP 过滤器用于验证和过滤来自非安全来源的数据,比如用户的输入。

14.1 什么是 PHP 过滤器?

PHP 过滤器用于验证和过滤来自非安全来源的数据。

验证和过滤用户输入或自定义数据是任何 Web 应用程序的重要组成部分。

设计 PHP 的过滤器扩展的目的是使数据过滤更轻松快捷。

14.2 为什么使用过滤器?

几乎所有 web 应用程序都依赖外部的输入。这些数据通常来自用户或其他应用程序(比如 web 服务)。通过使用过滤器,您能够确保应有程序获得正确的输入类型。

您应该始终对外部数据进行过滤!

输入过滤是最重要的应用程序安全课题之一。

14.2.1 什么是外部数据?

  • 来自表单的输入数据
  • Cookies
  • 服务器变量
  • 数据库查询结果

14.3 函数和过滤器

如需过滤变量,请使用下面的过滤器函数之一:

  • 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");
 }
?>

上面的代码使用了 "FILTER_VALIDATE_INT" 过滤器来过滤变量。由于这个整数是合法的,因此代码的输出是:"Integer is valid"。

假如尝试使用一个非整数的变量,则输出是:"Integer is not valid"。

14.4 Validating 和 Sanitizing

有两种过滤器:

14.4.1 Validating 过滤器:

  • 用于验证用户输入
  • 严格的格式规则(比如 URL 或 E-Mail 验证)
  • 如果成功则返回预期的类型,如果失败则返回 FALSE

14.4.2 Sanitizing 过滤器:

  • 用于允许或禁止字符串中指定的字符
  • 无数据格式规则
  • 始终返回字符串

14.5 选项和标志

选项和标志用于向指定的过滤器添加额外的过滤选项。

不同的过滤器有不同的选项和标志。

在下面的例子中,我们用 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");
 }
?>

就像上面的代码一样,选项必须放入一个名为 "options" 的相关数组中。如果使用标志,则不需在数组内。

由于整数是 "300",它不在指定的范围内,以上代码的输出将是 "Integer is not valid"。

14.6 验证输入

验证来自表单的输入。

首先确认是否存在正在查找的输入数据。

然后用 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):

  1. 检测是否存在 "GET" 类型的 "email" 输入变量
  2. 如果存在输入变量,检测它是否是有效的邮件地址

14.7 净化输入

清理从表单传来的 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):

  1. 检测是否存在 "POST" 类型的 "url" 输入变量
  2. 如果存在此输入变量,对其进行净化(删除非法字符),并将其存储在 $url 变量中

假如输入变量类似这样:"http://www.W3非o法ol.com.c字符n/",则净化后的 $url 变量应该是这样的:

http://www.W3School.com.cn/

14.8 过滤多个输入

表单通常由多个输入字段组成。为了避免对 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)

  1. 设置一个数组,其中包含了输入变量的名称,以及用于指定的输入变量的过滤器
  2. 调用 filter_input_array 函数,参数包括 GET 输入变量及刚才设置的数组
  3. 检测 $result 变量中的 "age" 和 "email" 变量是否有非法的输入。(如果存在非法输入,)

filter_input_array() 函数的第二个参数可以是数组或单一过滤器的 ID。

如果该参数是单一过滤器的 ID,那么这个指定的过滤器会过滤输入数组中所有的值。

如果该参数是一个数组,那么此数组必须遵循下面的规则:

  • 必须是一个关联数组,其中包含的输入变量是数组的键(比如 "age" 输入变量)
  • 此数组的值必须是过滤器的 ID ,或者是规定了过滤器、标志以及选项的数组

14.9 使用 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!

例子解释:

上面的例子把所有 "_" 转换成空格:

  1. 创建一个把 "_" 替换为空格的函数
  2. 调用 filter_var() 函数,它的参数是 FILTER_CALLBACK 过滤器以及包含函数的数组
时间: 2024-10-05 08:54:35

Php高级知识 2的相关文章

【转载更新】Linux工具之AWK 3.高级知识

原文:http://blog.hexu.org/archives/41.shtml#id2874788 awk编程 14.1. 变量 在awk中,变量不需要定义就可以直接使用,变量类型可以是数字或字符串.赋值格式:Variable = expression,如$ awk ‘$1 ~/test/{count = $2 + $3; print count}’ test,上式的作用是,awk先扫描第一个域,一旦test匹配,就把第二个域的值加上第三个域的值,并把结果赋值给变量count,最后打印出来.

通俗理解序列化的高级知识

如果你只知道实现 Serializable 接口的对象,可以序列化为本地文件.那你最好再阅读该篇文章,文章对序列化进行了更深一步的讨论,用实际的例子代码讲述了序列化的高级认识,包括父类序列化的问题.静态变量问题.transient 关键字的影响.序列化 ID 问题.在笔者实际开发过程中,就多次遇到序列化的问题,在该文章中也会与读者分享. 引言 将Java对象序列化为二进制文件的 Java 序列化技术是 Java 系列技术中一个较为重要的技术点,在大部分情况下,开发人员只需要了解被序列化的类需要实

DataBase MongoDB高级知识

MongoDB高级知识 一.mongodb适合场景: 1.读写分离:MongoDB服务采用三节点副本集的高可用架构,三个数据节点位于不同的物理服务器上,自动同步数据.Primary和Secondary节点提供服务.两个节点分别提供独立域名,配合MongoDB Driver可自行实现读取压力分配. 2.业务灵活多变:由于MongoDB采用No-Schema的方式,对于初创型的业务非常适用,免去变更表结构的痛苦.用户可以将模式固定的结构化数据存储在RDS中,模式灵活的业务存储在 MongoDB中,高

DataBase MongoDB高级知识-扩展

MongoDB高级知识-易扩展 应用程序数据集的大小正在以不可思议的速度增长.随着可用宽带的增长和存储器价格的下跌,即使是一个小规模的应用程序,需要存储的数据也可能大的惊人,甚至超出了很多数据库的处理能力.过去非常罕见的T级别数据,现在已是司空见惯了. 由于需要存储的数据不断增长,开发者面临一个困难:应该如何扩展数据库?接下来完我们就来讲讲. 一.mongodb如何扩展? 1.纵向:纵向扩展就是使用计算能力更强的机器. 提升计算机的配置,但是配置高价格也随之上升,当上升到一定的程度就无法提升了.

MySQL高级知识(四)——Explain

前言:explain(执行计划),使用explain关键字可以模拟优化器执行sql查询语句,从而知道MySQL是如何处理sql语句.explain主要用于分析查询语句或表结构的性能瓶颈. 注:本系列随笔如无特殊说明都MySQL版本都为5.7.22. 1.explain的作用 通过explain+sql语句可以知道如下内容: ①表的读取顺序.(对应id) ②数据读取操作的操作类型.(对应select_type) ③哪些索引可以使用.(对应possible_keys) ④哪些索引被实际使用.(对应k

MySQL高级知识(五)——索引分析

前言:前面已经学习了explain(执行计划)的相关知识,这里利用explain对索引进行优化分析. 0.准备 首先创建三张表:tb_emp(职工表).tb_dept(部门表)和tb_desc(描述表) 1)tb_emp表. DROP TABLE IF EXISTS `tb_emp`; CREATE TABLE `tb_emp` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(20) NOT NULL,PRIMARY KEY

JavaScript的高级知识---词法分析

JavaScript的高级知识---词法分析 词法分析 词法分析方法: js运行前有一个类似编译的过程即词法分析,词法分析主要有三个步骤: 分析参数 再分析变量的声明 分析函数说明 函数在运行的瞬间,生成一个活动对象(Active Object),简称AO 分析参数 具体步骤如下: 函数接收形式参数,添加到AO的属性,并且这个时候值为undefine,例如AO.age=undefine 接收实参,添加到AO的属性,覆盖之前的undefine 分析变量声明,如var age;或var age=23

第十八篇 js高级知识---作用域链

一直有想法去写写js方面的东西,我个人是最喜欢js这门语言,喜欢的他的自由和强大,虽然作为脚本语言有很多限制的地方,但也不失为一个好的语言,尤其是在H5出现之后.下面开始说说js的方面的东西,由于自己的能力有现,有点地方说的不明白,还请高手指点.这个文章,如果有时间的话应该会写一个系列,包括js的高级方面的知识,最终希望能够说到js的引擎方面的东西.千里之行,始于足下,下面开始说说最简单的一个东西—js的作用域链,时常也比较容易弄错,也算是自己做一个纪录. 首先看一段代码: function t

MySQL高级知识- MySQL的架构介绍

[TOC] 1.MySQL 简介 概述 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,目前属于Oracle公司. MySQL是一种关联数据库管理系统,将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性. Mysql是开源的,所以你不需要支付额外的费用. Mysql支持大型的数据库.可以处理拥有上千万条记录的大型数据库. MySQL使用标准的SQL数据语言形式. Mysql可以允许于多个系统上,并且支持多种语言.这些编程语言包括C.C+

第20篇 js高级知识---深入原型链

前面把js作用域和词法分析都说了下,今天把原型链说下,写这个文章费了点时间,因为这个东西有点抽象,想用语言表达出来不是很容易,我想写的文章不是简单的是官方的API的copy,而是对自己的知识探索和总结的过程,以及在这个过程碰到的问题都一一写出来,我想大多数人应该也有这个疑惑,然后带着疑惑去找答案,当你把这个疑惑解决之后,才觉得很有成就感.下面不多说了,开始说说什么是原型链.要想了解原型链,还是要从简单的开始,什么是原型?首先看下代码: function funcA() { this.show =