一.前言
前面说了函数和流程控制那些,今天来说一些进阶一点的,错误处理之类的,上一节内容特别多,本章节内容将会少很多。
二.PHP的错误处理
很多时候,代码如果写的不太好,那么很容易报错。那么如果遇到了错误,我们应该想办法捕获到这个 错误并记录下来,而且最好不要用户看到,不然太尴尬了,而且容易暴漏自己服务端的一些敏感信息, 方便我们后续修改,并且尽量不要让整个程序因为一点小错误而崩溃。
2.1配置项管理
在php.ini配置文件中。我们可以控制php的错误显示状态。php.ini中有一个专门的配置项:
display_errors
这个选项设置是否将错误信息输出到网页,或者对用户隐藏而不显示。在生产上必须要关闭显示错误, 开发的时候可以打开方便调试。
这个值的状态为on 或者 off,也可以设值为1 或者0。
display_errors的值设为0或者off则不在页面中显示错误,如果设为1或者on则显示错误信息。
问题:如果没有修改服务器php.ini的状态权限怎么办?
那么可以在每个代码文件中使用ini_set方法来进行设置,其实php.ini中的各种配置都可以在代码中进行 动态控制。
<?php
ini_set('display_errors' , 0 );
//$a = $GET['xxxx']; 这个错误就不显示了。
?>
上面的代码也相当于修改了php.ini中display_errors的值。不过,仅仅在当前php代码中生效。
问题:想取得php.ini的配置项状态怎么办?
可以使用ini_get(参数项) 得到参数的值。
演示例子:
<?php
echo '服务器中display_errors的状态为' . ini_get('display_errors');
?>
注:如果我们修改完php.ini文件中的配置,想让配置生效的话,需要在修改完php.ini文件后重启服务器。
2.2 错误级别
【掌握级别的错误类型】 ,可以控制哪些级别的错误可以显示或者记录日志,哪些级别的错误不可以显示或者不记录日志。
错误类型 | 说明 |
---|---|
E_ERROR | 错误,文件直接中断 |
E_WARNING | 警告,问题比较严重。但是还会继续向下运行 |
E_NOTICE | 提示,有些小问题不会影响到程序。常发生在项目未定义 |
E_PARSE | 编译时语法解析错误。解析错误仅仅由分析器产生 |
E_ALL | 所有的错误 |
E_STRICT | 启用PHP对代码的修改建议,以确保代码具有最佳的互操作性和向前兼容性 |
E_DEPRECATED | 启用后将会对在未来版本中可能无法正常工作的代码给出警告 |
我们介绍一下其中几种:
error最严重,必须要解决。不然程序无法继续向下执行
warning也很重要。但也必须要解决。如果明确的、故意的可以不用处理。
notice 你可以不用管。但是在有些公司,项目标准特别高。在高标准要求的项目中也必须要解决。因为,notice会影响到PHP的执行效率。通常发生在函数未定义等。
parse错误,是指语法错写错了,必须要解决,代表全部类型的所有错误。
1、 在php.ini中error_reporting参数。如若error_reporting参数设置为0。整个PHP引擎发错误均不会 显示、输出、记录。在后面要讲的日志记录中,也不会记录。
如果我们想显示所有错误可以写上:
error_reporting = E_ALL
想要显示所有错误但排除提示,可以将这个参数写为:
error_reporting = E_ALL & ~ E_NOTICE
显示所有错误,但排除提示、兼容性和未来兼容性。可写为:
error_reporting = E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED
2、在有些情况下我们无权限操作php.ini文件,又想要控制error_reporting怎么办呢?在运行的xxxx.php文件中开始处,我们可以使用error_reporting()函数达到目标。
演示代码如下:
<?php
//关闭了所有的错误显示
error_reporting(0);
//显示所有错误
//error_reporting(E_ALL);
//显示所有错误,但不显示提示
//error_reporting(E_ALL & ~ E_NOTICE);
?>
2.3 错误记录日志
在一些公司里面,有专门的日志收集系统。日志收集系统会在背后默默的帮你收集错误、警告、提示。 也有些公司没有专门的日志收集系统,通过文件来服务器当中的运行日志。
其中:PHP的错误,警告这些是必须要收信的。那么问题来了——不让用户看到,设置好错误报告级别 好,如何将错误收集到日志系统中呢?
这里有需要使用到php.ini的相关配置项。这两个配置项为:
参数 | 配置项 | 说明 |
---|---|---|
log_errors | on/off | 是否开启错误日志记录功能 |
log_errors_max_len | 整型,默认1024B | 单条错误日志的最大记录长度 |
error_log | syslog或文件路径 | 指定错误日志输出到系统日志/文件 |
说明:
1.在表格中的log_errors和log_errors_max_len非常好理解。
2.而error_log 指定将错误存在什么路径上。配置项中的syslog可能有点不太好理解。syslog是指系统来 记录。windows系统在电脑的事件查看器--应用程序日志。里面。linux默认在: /etc/syslog.conf
[扩展] 了解知识点。若Linux系统启动或修改了日志收集。可能存储在第三方专用的日志收集服务器中。
此外,PHP还为我们专门准备了一个自定义的错误日志函数:
bool error_log ( string $错误消息 [, int $错误消息类型 = 0 [, string $存储目标]] )
这个函数可以把错误信息发送到web服务器的错误日志,或者到一个文件里。
常用的错误消息类型
错误消息类型 | 说明 |
---|---|
0 | 发送至默认的error_log指定位置 |
1 | 发送到指定的邮件位置 |
3 | 发送至指定的文件位置 |
示例:
<?php
//无法连接到数据库服务器,直接记录到php.ini中的error_log指定位置
error_log("无法连接到数据库服务器服务器");
//可以发送邮件,但是php.ini必须配置过邮件系统
error_log('可以用邮件报告错误,让运维人员半夜起床干活', 1, 'pig@php.cn');
//记录在指定的位置
error_log("我是一个错误哟", 3, "d:/test/my-errors.log");
?>
一般我们手动搭建的apache的默认日志路径是在,重点昂
linux: /etc/httpd/logs/access_log
windows: /Apache/logs/access_log
三.PHP中的正则表达式
正则表达示我们其实之前经常看到,它主要用在以下一些地方:匹配邮箱、手机号码、验证码、替换敏 感的关键词。例如:涉及政治和骂人的话。
3.1 定界符
PHP的正则表达示定界符的规定如下:
定界符,不能用a-zA-Z0-9\ 其他的都可以用。必须成对出现,有开始就有结束
类型 | 示例 | 状态 | 说明 |
---|---|---|---|
标准定界符 | /中间写正则/ |
✅正确 | 最常用标准格式(推荐优先使用) |
符号定界符 | $中间写正则$ |
✅正确 | 允许的特殊符号格式 |
%中间写正则% |
✅正确 | 非字母数字符号可作为定界符 | |
^中间写正则^ |
✅正确 | 特殊符号需成对出现 | |
错误示范 | (中间写正则) |
❌错误 | 括号类符号有特殊含义不可使用 |
A中间写正则A |
❌错误 | 字母数字不可作为定界符 |
注:\ 是转义字符,如果在以后正则表达示里面需要匹配/,需要把定界符里面的/ 用转义字符转义一 下,写成 / \/ / ,如果你觉得麻烦,遇到这种需要转义的字符的时候可以把两个正斜线(/ /)定界, 改为其他的定界符(# #)。
3.2 正则表达式的使用
preg_match ( string $正则 , string $字符串 [, array &$结果] )
功能:根据定界符,比如$正则变量,匹配$字符串变量。如果存在则返回匹配的个数,把匹配到的结果 放到$结果变量里。如果没有匹配到结果返回0。
<?php
// 正则匹配示例
$zz = '/wq/'; //正则表达式写在中间,'/正则表达式/'
$string = 'ssssswqaaawqaaa';
if(preg_match($zz, $string, $matches)) {
echo '匹配到了,结果为:';
var_dump($matches);
} else {
echo '没有匹配到';
}
// 正则替换示例
$a = 'hello jaden';
$b = preg_replace('/jaden/', 'wulaoban', $a);
echo $b; // 输出:hello wulaoban
?>
我们常用的正则函数有:
函数名 | 功能描述 |
---|---|
preg_filter | 执行正则表达式搜索和替换 |
preg_grep | 返回匹配模式的数组条目 |
preg_match | 执行正则表达式匹配(单次) |
preg_match_all | 执行全局正则表达式匹配(全部结果) |
preg_replace_callback_array | 传入数组,执行正则表达式搜索和替换(使用回调函数处理) |
preg_replace_callback | 执行正则表达式搜索并使用回调函数进行替换 |
preg_replace | 执行正则表达式的搜索和替换 |
preg_split | 通过正则表达式分隔字符串 |
大家针对这些函数,对着手册用一下。
四.反序列化函数
4.1 面向对象编程(类)
<?php
header("Content-Type: text/html; charset=utf-8"); // 设置响应头内容类型和字符集
class Fruit {
var $name1 = 'apple'; // 定义属性
var $name2 = 'orange';
function chi() { // 定义方法
echo '吃水果'.'<br>';
echo $this->name1.'<br>';
}
function bo() { // 普通方法
echo '剥皮'.'<br>';
}
// 魔术方法:对象销毁时自动执行
function __destruct() {
echo '对象被销毁了'.'<br>';
}
}
$f = new Fruit();
$f->chi(); // 调用方法
echo '哈哈'.'<br>';
// 被注释的函数
/*
function add() {
$f = new Fruit();
$f->chi();
}
*/
?>
4.2 序列化和反序列化
<?php
// 序列化,将其他的数据转换成字符串
$a = array('one', 33, 'two');
var_dump($a); // array(3) {[0]=> string(3) "one"[1]=> int(33) [2]=> string(3) "two"}
echo "<br>";
$b = serialize($a);
var_dump($b); // string(43) "a:3:{i:0;s:3:"one";i:1;i:33;i:2;s:3:"two";}"
// 反序列化将序列化的字符串还原成原来的数据类型
$c = unserialize($b);
var_dump($c);
// 类的序列化
class s {
var $name = "jaden";
function __destruct() {
echo $this->name;
//system('ipconfig');
//echo '<script>alert(123);</script>';
}
function chi() {
echo 'xxxxx';
}
}
$a = new S();
echo $a->name.'aaaa<br>';
echo $a->chi().'<br>';
$b = serialize($a); // 0:1:"s":1:{s:4:"name";s:5:"jaden";}
$c = unserialize($b);
?>
五.PHP操作mysql
创建表:
# 注意下面插入数据的时候,不要插入中文数据!!!,因为php连接mysql的编码没有设置,容易乱码。
-- 创建数据库
CREATE DATABASE jaden CHARSET utf8mb4;-- 创建数据表
CREATE TABLE user(
id INT NOT NULL AUTO_INCREMENT,
username CHAR(20),
password CHAR(32),
reg_time CHAR(36),
PRIMARY KEY (`id`)
);-- 插入测试数据
INSERT INTO user(username, password, reg_time)
VALUES('admin', '123456', CURRENT_TIMESTAMP());INSERT INTO user(username, password, reg_time)
VALUES('wulaoban', '123456', CURRENT_TIMESTAMP());
查询:
<?php
// 连接数据库
$db = mysqli_connect('localhost', 'root', 'root', 'jaden', 3306);
# 默认端口如果就是3306,那么其实不用写3306
// 定义SQL查询(安全写法)
$sql = "SELECT * FROM user WHERE username='wulaoban'";
// 被注释的变量写法(存在SQL注入风险)
/*
$u = 'wulaoban';
$sql = "SELECT * FROM user WHERE username='$u'";
*/
// 执行SQL语句
$a = mysqli_query($db, $sql);
// 遍历查询结果
while ($row = mysqli_fetch_assoc($a)) {
// var_dump($row); // 调试用
echo "用户名:" . $row['username'] . ",密码:" . $row['password'];
echo "<br>";
}
// 关闭连接
mysqli_close($db);
?>
其实php连接mysql有三种方式,phpstudy帮我们都内置了:mysql、mysqli、pdo,其中mysql淘汰 了,不安全。
插入数据:
<?php
// 连接MySQL数据库
$db = mysqli_connect('localhost', 'root', 'root', 'jaden');
// 定义插入语句
$sql = "INSERT INTO user(username, password) VALUES('laowang2', '111111')";
// 执行SQL语句
$a = mysqli_query($db, $sql);
// 检查执行结果
if (!$a) {
echo "SQL语句语法问题";
} else {
echo "SQL语句执行成功!";
}
// 关闭数据库连接
mysqli_close($db);
?>
删除数据,更新数据和插入数据步骤类似
六.cookie和session
登录认证。
只使用cookie
<?php
// 页面跳转(JavaScript方式)
echo "<script>location.href='login.php';</script>";
// 设置Cookie
setcookie('user', 'admin'); // 简单Cookie设置
/*
等效完整参数写法:
setcookie('user', 'admin', time()+3600, '/', 'example.com', false, true);
*/
// 读取Cookie
$username = $_COOKIE['user'] ?? '未登录';
echo "当前用户:".$username;
?>
cookie结合session
<?php
/* ========== 验证的地方 ========== */
session_start();
if(isset($_SESSION['user'])) {
// 用户已登录的逻辑处理
}
/* ========== 登录成功设置 ========== */
session_start();
$_SESSION['user'] = $_POST['su']; // 存储用户名
$_SESSION['login_time'] = time(); // 记录登录时间戳
$_SESSION['d'] = '123'; // 存储固定标识
$_SESSION['login_status'] = 1; // 设置登录状态
/*
* Session存储位置配置提示:
* 文件路径在php.ini中的session.save_path参数设置
*/
?>
七.总结
本期讲解了很多PHP稍微进阶的知识,内容不是很多,PHP基础知识就到此为止了,干货满满,期待大家的点赞关注加收藏,共勉。