新建立一个类检测php错误,PHP-自定义异常类处理上传错误--2019年10月12日

10月12日:

1. 写一个自定义异常类来处理上传过程以及各种错误

2. (选做) 写一个与指定数据表绑定的类, 实现基本的模型功能,例如查询, 新增, 更新,删除等操作

【1】自定义异常类来处理上传过程以及各种错误

有时候我们需要使用自定义的异常类,对特定类型的异常进行处理。

自定义异常类需要继承自Exception类,并添加自定义的成员属性和方法即可。接下来通过一个文件上传实例进行学习。

一般按如下格式使用自定义异常类:

/* 自定义的一个异常处理类,但必须是扩展内异常处理类的子类 */

class MyException extends Exception{

//重定义构造器使第一个参数 message 变为必须被指定的属性

public function __construct($message, $code=0){

//可以在这里定义一些自己的代码

parent::__construct($message, $code);

}

public function __toString() {

//重写父类方法,自定义字符串输出的样式

return __CLASS__.":[".$this->code."]:".$this->message."
";

}

public function errorInfo() {

//为这个异常自定义一个处理方法

}

}

try { //使用自定义的异常类捕获一个异常,并处理异常

//主程序,如果发生异常,通过throw语句抛出

} catch (MyException $e) {        //捕获自定义的异常对象

echo $e->errorInfo();  //通过自定义的异常对象中的方法处理异常

}

?>

文件上传过程说明:

通常一个文件以HTTP协议进行上传时,将以POST请求发送至Web服务器,Web服务器接收到请求并同意后,用户与Web服务器将建立连接,并传输数据。一般文件上传过程中将会经过如下几个检测步骤:javascript校验;

服务端MIME类型检测

服务端目录路径检测

服务端文件扩展名检测

服务端文件内容检测

1、PHP使用超全局变量$_FILES来处理文件上传

$_FILES数组内容如下:

$_FILES['myFile']['name'] 客户端文件的原名称。

$_FILES['myFile']['type'] 文件的 MIME 类型,需要浏览器提供该信息的支持,例如"image/gif"。

$_FILES['myFile']['size'] 已上传文件的大小,单位为字节。

$_FILES['myFile']['tmp_name'] 文件被上传后在服务端储存的临时文件名,一般是系统默认。

$_FILES['myFile']['error'] 和该文件上传相关的错误代码。

UPLOAD_ERR_OK

值:0; 没有错误发生,文件上传成功。

UPLOAD_ERR_INI_SIZE

值:1; 上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值。

UPLOAD_ERR_FORM_SIZE

值:2; 上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值。

UPLOAD_ERR_PARTIAL

值:3; 文件只有部分被上传。

UPLOAD_ERR_NO_FILE

值:4; 没有文件被上传。

值:5; 上传文件大小为0.

2、文件被上传结束后,默认地被存储在了临时目录中,这时必须将它从临时目录中删除或移动到其它地方,如果没有,则会被删除。也就是不管是否上传成功,脚本执行完后临时目录里的文件肯定会被删除。

所以在删除之前要用PHP的 copy() 函数将它复制到其它位置,此时,才算完成了上传文件过程。

3、本例中使用自定义异常类给出上传过程中的结果 和 错误信息,在上传文件的客户端页面中设置一个隐藏的ifram,用来接收结果 或 错误信息。通过一个定时轮询ifram中body内容的变化,来决定是否显示iframe,从而实现页面无跳转的上传与信息提示。

最终的运行效果如下图:

d00a5ef004cc022f5e5f227fc2b4331c.png

catch(Exception $e)可以接受系统类exception和自定义的异常类。

catch(customException $e)只能接受throw抛出的自定义的异常类,不能接受系统类exception

代码实现如下:实例 --- 用自定义异常类 处理上传文件的错误信息

class MyException extends Exception {

public function __construct($message, $code = 0) {

parent::__construct($message, $code);

}

public function errorInfo() {

include 'info.php';  //显示错误信息

}

}

try {

//使用自定义的异常类捕获一个异常,并处理异常

// 配置上传参数

$fileType = ['jpg', 'jpeg', 'png', 'gif'];

$fileSize = 3145728;

$filePath = '\uploads\\';

$fileName = $_FILES['myfile']['name'];

$tempFile = $_FILES['myfile']['tmp_name'];

$uploadError = $_FILES['myfile']['error'];

if ($uploadError != 0) {

switch ($uploadError) {

case 1:throw new MyException("上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值", 1001);

case 2:throw new MyException('上传文档不允许超过3M', 1002);

case 3:throw new MyException('上传文件不完整', 1003);

case 4:throw new MyException('没有文件被上传', 1004);

case 5:throw new MyException("文件大小为0", 1005);

default:throw new MyException('未知错误', 1000);

}

}

//通过扩展名判断文件类型

@$extension = end(explode('.', $fileName));

if (!in_array($extension, $fileType)) {

throw new MyException('不允许上传' . $extension . ' 文件类型', 1006);

}

//为了防止同名覆盖, 将上传的文件重命名: md5+时间戳

$fileName = date('YmdHis', time()) . md5(mt_rand(1, 99)) . '.' . $extension;

//传文件

$uploadPath = __DIR__ . $filePath;

if (is_uploaded_file($tempFile)) {

if (!file_exists($uploadPath) || !is_writable($uploadPath)) {

throw new MyException('指定目录不存在且无法创建, 请检查目录', 1007);

}

if (move_uploaded_file($uploadPath . $fileName)) {

echo '文件上传成功';

} else {

throw new MyException('文件无法移动到指定目录, 请检查目录权限', 1008);

}

} else {

throw new MyException('非法操作', 1009);

}

} catch (MyException $e) { //捕获自定义的异常对象

echo $e->errorInfo(); //通过自定义的异常对象中的方法处理异常

}

?>

运行实例 »

点击 "运行实例" 按钮查看在线实例实例  --- 客户端 上传页面 代码

html>

文件上传

#tg {

position: absolute;

left:0;

right:0;

top:0;

bottom:0;

margin: auto;

}

function upload() {

$("#form1").submit();

var t = setInterval(function() {

//获取iframe标签里body元素里的文字。即服务器响应过来的"上传成功"或"上传失败"

var word = $("#tg").contents().find("body").text();

if (word != "") {

$("#tg").show();

setTimeout(function(){$("#tg").hide();},1500);

clearInterval(t);   //清除定时器

}

}, 1000);

}

运行实例 »

点击 "运行实例" 按钮查看在线实例

【2】写一个与指定数据表绑定的类, 实现基本的模型功能,例如查询, 新增, 更新,删除等操作

按照数据表的字段结构编写一个同名的类,在使用PDO对数据库操作时,可以把表中查询到的一条记录映射到类的成员属性上,从而可以用类的属性操作方法来处理表中数据。一条数据记录对应一个类对象,不再是通常的默认的数组元素。

代码实例如下:实例

// 类名与表名对应

class Staff {

// 属性与表中的字段对应

private $staff_id;

private $name;

private $age;

private $sex;

private $position;

private $hiredate;

// 属性重载

public function __get($name) {

return $this->$name;

}

public function __set($name, $value) {

$this->$name = $value;

}

// 构造方法

public function __construct() {

$this->hiredate = date('Y/m/d', $this->hiredate);

$this->sex = $this->sex ? '男' : '女';

}

}

$pdo = new PDO('mysql:dbname=test', '*', '*');

$stmt = $pdo->prepare('SELECT * FROM `staff`');

$stmt->setFetchMode(PDO::FETCH_CLASS, Staff::class);

$stmt->execute();

$staff = $stmt->fetchAll();

var_dump($staff[0]->name);

?>

运行实例 »

点击 "运行实例" 按钮查看在线实例

对于数据内容的查询显示,使用场景在数据库外部,采用上述映射到类的方法有助于数据的操作。而修改、新增和删除操作是把数据放入数据表中,目标场景是在数据库内部,采用映射到类的方式并没有提升操作优势,这些操作本就有专用的库类或函数模块来实现。

总结:

1、通过本次练习,了解了文件上传的过程与方法,了解了自定义异常类的使用方法;

2、文件上传安全漏洞不容忽视,实际项目中的检测和防范知识还需更进一步学习;

3、接本例练习了一种上传后页面不 发生跳转 并给出信息的实现方法;

4、数据表绑定类的关键操作是:setFetchMode(PDO::FETCH_CLASS, Staff::class);

5、练习中发现:映射类不需要显式实例化 就可以直接使用。上例中:$staff[0]->name;

6、在此基础上,可以扩展学习PHP的数据映射模式内容来看看。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值