MySql 数据库——后端

  • MySql是开源的,所以你不需要支付额外的费用。
  • MySql支持大型的数据库。可以处理拥有上千万条记录的大型数据库。
  • 可以存储文本数据!

不属于PHP程序,而是与PHP配合的一个软件,是PHP程序中,数据存储的来源!例如数组中调用文章,那么可以把文章存储到数据库,再用PHP去访问数据库,获取到文章,然后再展示到HTML中!

比如要在HTML中发布一篇文章,不可能让文章文本嵌入到HTML中,这样用户看文章,就要下载带有文章文本的HTML,如果文章字数多,全部下载到本地中,有点不方便,编程也不方便呀!

这个时候,就可以把文章存储到数据库,通过PHP代码,去动态调取文章!

一、MySql 基础知识

1、为什么要使用 MySql

2、MySql 介绍

  • MySQL是(关系型数据库管理系统)的应用软件之一
    • 数据以表格的形式出现
    • 每行:各种记录名称
    • 每列:记录名称所对应的数据域
    • 许多的行和列组成一张表单
    • 若干的表单组成database

3、MySql 环境

像宝塔、xampp、phpstudy等都集成了环境!

4、数据库管理软件

  1. 命令行管理数据库

  2. phpMyAdmin 网页管理数据库

  3. Navicat for MySql 软件管理数据库

采用XAMPP的集成的网页来管理!http://localhost/phpmyadmin/

5、MySql 创建库

image-20230430153136268

新建数据库-数据库名-字符集:utf8mb4

6、RDBMS 术语-关系型数据库!

  • 数据库: 数据库是一些关联表的集合。
  • 数据表: 表是数据的矩阵。在一个数据库中的表看起来像一个简单的电子表格。
  • 列: 一列(数据元素) 包含了相同的数据, 例如邮政编码的数据。
  • 行:一行(=元组,或记录)是一组相关的数据,例如一条文章的数据

二、MySql 数据类型

1、数值数据类型

类型 用途 范围(无符号) 范围(有符号)
tinyint 极小整数类型 (0,255) (-128,127)
smallint 小整数类型 (0,65535) (-32768,32767)
mediumint 中整数类型 (0,16777215) (-8388608,8388607)
int 大整数类型 (0,4294967295) (-2147483648,2147483647)
bigint 极大整数类型 (0,18446744073709551615) 均分成正负
float 浮点小数类型(单精度) 0,约1.17前面38个0,3.4后面38个零 双倍
double 浮点小数类型(双精度) 0,约2.22前308个0,1.79后面308个零 双倍
decimal 定点小数类型 依赖于M和D的值 依赖于M和D的值

注意:数值分为整数和小数,常用tinyintintdouble

decimal定点小数类型:可以规定小数点左边有几位,右边有几位!

2、字符串数据类型

  • BLOB 保存二进制数据
  • TEXT 保存字符数据
类型 用途 大小(字节)
char 定长字符串 0-255
varchar 变长字符串 0-65535
tinytext 短文本字符串 0-255
text 长文本数据 0-65535
mediumtext 中等长度文本数据 0-16777215
longtext 极大文本数据 0-4294967295
tinyblob 不超过 255 个字符的二进制字符串 0-255
blob 二进制形式的长文本数据 0-65535
mediumblob 二进制形式的中等长度文本数据 0-16777215
longblob 二进制形式的极大文本数据 0-4294967295

注意:保存图片时,是保存地址!常用数据类型:varchartext

3、日期/时间数据类型

类型 用途 大小(字节) 格式
year 3 YYYY
data 日期 3 YYYY-MM-DD
time 时间 3 HH:MM:SS
datatime 日期时间 8 YYYY-MM-DD HH:MM:SS
timestamp 时间戳 4 YYYYMMDD HHMMSS

三、MySql 数据表

1、创建数据表

image-20230430161113962

2、MySql 语句

  • mysql 所有操作都可以用命令操作

image-20230430161136790

3、手动添加数据

真实项目中,不允许手动添加数据的!


四、PHP 操作 MySQL

使用php编程,来操作数据库!

一、MySql 语句

1、查询语句

  • 一条mysql语句结束使用;号
select * from article;

二、PDO 操作数据库

1. 什么是 PDO

  • PDO: (Php Data Object) php数据对象
  • PDO 统一了PHP访问各种类型数据库的访问方式
  • 一句话, 不管什么类型数据库, PDO一招搞定

yue18_20230430_163735

2. PDO 连接

image-20230430164037325

<?php
//连接数据库
$pdo = new PDO('mysql:host=localhost;dbname=blog','root','123456');
//准备一条SQL语句
$stmt = $pdo->prepare('SELECT * FROM article');
//执行一条SQL语句
$stmt->execute();
$arr = $stmt->fetchAll();
//打印
var_dump($arr);
?>

image-20230430172202615

3. 编码

# 方法一
header('content-type:text/html;charset=utf-8');

# 方法二
$pdo = new PDO('mysql:host=localhost;dbname=boke', 'root' , 'root' , array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8';"));

# 方法三
$pdo->query('SET NAMES utf8');

4、php 复合数据类型

类型 描述
object 对象

修改完数据库账户密码,不能通过网页访问

解决办法:找到数据库的配置文件,添加刚才更改的密码!

  • 通过记事本或vscode打开文件:C:\xampp\phpMyAdmin\config.inc.php
  • 找到$cfg['Servers'][$i]['password'] = '';添加上刚才更改的密码即可!

尝试连接云服务器上的数据库,结果显示错误!无法访问,并且发现我的服务器数据库没有开启SSL传输!


案例:网页前端文件——通过PHP连接数据库

1、在数据库添加文章数据表

分析:操作数据库,在Mysql软件中,使用SQL语法,在数据库中执行下面代码!注意可以自定义表的名称

CREATE TABLE `article2` (
`title` varchar(300) CHARACTER SET utf8 DEFAULT NULL COMMENT '标题',
`img` varchar(300) CHARACTER SET utf8 DEFAULT NULL COMMENT '图片',
`content` text CHARACTER SET utf8 COMMENT '内容',
`date` date DEFAULT NULL COMMENT '时间',
`class` varchar(50) CHARACTER SET utf8 DEFAULT NULL COMMENT '类型'
) ENGINE=InnoDB DEFAULT CHARSET=sjis;

INSERT INTO `article2` VALUES ('php中文网原创视频:《天龙八部》公益php培训系列课程汇总!', 'https://img.php.cn/upload/course/000/000/001/5d242759adb88970.jpg', 'PHP中文网因专业的讲师水平和高效的视频质量,推出的各种视频课程系列一直以来都深受大家喜爱。特别是《天龙八部》系列、《独孤九贱》系列、《玉女心经》系列的原创课程在行业内更是具有强大的影响力,好评不断!为了让大家能更快速方便的寻找到相关教程资源,我们在这篇文章中特意将《天龙八部》系列课程整理出来供大家有针对性得学习!', '2021-02-18', 'PHP');
INSERT INTO `article2` VALUES ('php中文网《玉女心经》公益PHP WEB培训系列课程汇总', 'https://img.php.cn/upload/course/000/126/153/5aa23f0ded921649.jpg', 'php中文网近期推出的《独孤九贱》系列、《天龙八部》系列、《玉女心经》原创视频课程,好评如潮!由于《玉女心经》系列课程没有做成专题,所以大家找起来有点费劲,为了更好的服务广大php中文网粉丝们,特把课程整理汇总给大家!', '2021-02-11', 'PHP');
INSERT INTO `article2` VALUES ('html5中submit是按钮么', null, 'html5中submit是按钮,它是button的一个特例,它把提交这个动作自动集成了。submit会自动将表单的数据提交,使用submit时需要验证要加return', '2021-02-10', '前端');
INSERT INTO `article2` VALUES ('css如何去除下划线', null, 'css去除下划线的方法:首先创建一个HTML示例文件;然后在body中定义一个a标签;最后通过css属性为“a{text-decoration:none}”去除下划线即可。', '2021-02-01', '前端');
INSERT INTO `article2` VALUES ('linux如何查看进程', 'https://img.php.cn/upload/article/202102/24/2021022409272725770.jpg', 'windows defender是windows系统自带的一款杀毒软件,对于很多人来说,这款软件不仅没有起到保护电脑的作用,还增加了很多不必要的麻烦。比如我们安装了一些破解版软件,windows defender就会杀这些破解软件,很让人讨厌。', '2021-02-01', '服务器');
INSERT INTO `article2` VALUES ('Ubuntu20.04/18.04下安装或更新至PHP8', 'https://img.php.cn/upload/article/000/000/020/2c02ff679ec7afab974a691aac09d535-0.png', '本指南让你了解如何安装最新的 php 版本 8,并在你的任何 VPS、云服务器、专用主机上的 Ubuntu 20.0 或 18.04 系统中升级到最新版本,并将其配置为 Apache 和 Nginx。', '2021-02-01', 'PHP');
INSERT INTO `article2` VALUES ('PHP 8新特性之JIT对PHP应用性能的影响', null, '即将发布的 PHP 8 最受大家关注的新特性就是引入了对 JIT 的支持,我已经简单介绍了 JIT 是什么,以及与 Opcache 的区别', '2021-02-01', 'PHP');

2、连接数据库

前端文件中,用户访问网址时,PHP文件解析生成HTML文件,在这个过程中,PHP文件连接到数据库,从数据库获取信息!客户端网页文件一直连接着数据库!数据库崩了,那么网页也会崩了!

<?php
$pdo = new PDO('mysql:host=localhost;dbname=blog', 'root' , '123456' , array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8';"));
?>

注意:这个dbname,相当于连接到哪个数据库!

3、获取文章列表

注意:名字要和刚刚新建的数据列表名一致!

<?php
$stmt = $pdo->prepare('SELECT * FROM article2');
$stmt->execute();
$lists = $stmt->fetchAll();
?>

image-20230430201219028

注意:一旦连接成功,相当于表格中的数据可以通过数组$lists

这样就可以把之前手动书写的数据删除了!连接数据库后,获取的文章列表等价于下图信息!并用数组操作去打印数据内容!

image-20230502220210982

<?php
$lists = [
[
'title' => 'php中文网原创视频:《天龙八部》公益php培训系列课程汇总!',
'img' => 'https://img.php.cn/upload/course/000/000/001/5d242759adb88970.jpg',
'content' => 'PHP中文网因专业的讲师水平和高效的视频质量,推出的各种视频课程系列一直以来都深受大家喜爱。特别是《天龙八部》系列、《独孤九贱》系列、《玉女心经》系列的原创课程在行业内更是具有强大的影响力,好评不断!为了让大家能更快速方便的寻找到相关教程资源,我们在这篇文章中特意将《天龙八部》系列课程整理出来供大家有针对性得学习!',
'data' => '2021-02-18',
'class' => 'PHP'
],
[
'title' => 'php中文网原创视频:《天龙八部》公益php培训系列课程汇总!',
'content' => 'PHP中文网因专业的讲师水平和高效的视频质量,推出的各种视频课程系列一直以来都深受大家喜爱。特别是《天龙八部》系列、《独孤九贱》系列、《玉女心经》系列的原创课程在行业内更是具有强大的影响力,好评不断!为了让大家能更快速方便的寻找到相关教程资源,我们在这篇文章中特意将《天龙八部》系列课程整理出来供大家有针对性得学习!',
'data' => '2021-02-18',
'class' => 'PHP'
],
[
'title' => 'php中文网原创视频:《天龙八部》公益php培训系列课程汇总!',
'img' => 'https://img.php.cn/upload/course/000/000/001/5d242759adb88970.jpg',
'data' => '2021-02-18',
'class' => 'PHP'
],
[
'title' => 'php中文网原创视频:《天龙八部》公益php培训系列课程汇总!',
'img' => 'https://img.php.cn/upload/course/000/000/001/5d242759adb88970.jpg',
'content' => 'PHP中文网因专业的讲师水平和高效的视频质量,推出的各种视频课程系列一直以来都深受大家喜爱。特别是《天龙八部》系列、《独孤九贱》系列、《玉女心经》系列的原创课程在行业内更是具有强大的影响力,好评不断!为了让大家能更快速方便的寻找到相关教程资源,我们在这篇文章中特意将《天龙八部》系列课程整理出来供大家有针对性得学习!',
'data' => '2021-02-18',
],

]
?>

等价于

<?php
$pdo = new PDO('mysql:host=localhost;dbname=blog', 'root' , '123456' , array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8';"));
$stmt = $pdo->prepare('SELECT * FROM article2');
$stmt->execute();
$lists = $stmt->fetchAll();
?>

修改打印列表的代码!访问数据库得到一个二维数组!

//遍历数组,数组名是上面的代码$lists,在遍历过程,内层数组数据命令为$lists_v
<?php
foreach($lists as $lists_v){
?>

<article>
<header class="entry-header">
<h1 class="entry-title">
<a href="/details.html" title="<?php
if(isset($lists_v['title'])){
echo $lists_v['title'];
}
?>" rel="bookmark">

//注意,这里使用内层数组,且键名是'title',下面同理
<?php
if(isset($lists_v['title'])){
echo $lists_v['title'];
}
?>

</a>
</h1>
</header>

<div class="entry-content">
<?php
if(!empty($lists_v['content'])){
echo $lists_v['content'];
}
?>
</div>

<img src="
<?php
if(isset($lists_v['img'])){
echo $lists_v['img'];
}
?>
" alt="这是张图片">

<footer class="entry-meta">
发布于
<a href="/index.html?time=2020-10-02" title="2020-10-02" rel="bookmark">
<time class="entry-date" datetime="2020-10-02">

<?php
if(isset($lists_v['data'])){
echo $lists_v['data'];
}
?>

</time>
</a>。

属于
<a href="/index.html?cate=4" title="查看 Linux中的全部文章" rel="category">

<?php
if(isset($lists_v['class'])){
echo $lists_v['class'];
}
?>

</a>

分类
</footer>

</article>

<?php
}
?>

注意:这个列表赋值给数组变量$lists,内层数组名$lists_v,再使用键名指定数据!

4、创建分类表

image-20230502221229783

5、分类数据表

CREATE TABLE `class` (
`name` varchar(50) DEFAULT NULL COMMENT '分类名'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `class` VALUES ('Layui');
INSERT INTO `class` VALUES ('PHP');
INSERT INTO `class` VALUES ('ThinkPHP');
INSERT INTO `class` VALUES ('前端');
INSERT INTO `class` VALUES ('小程序');
INSERT INTO `class` VALUES ('服务器');
INSERT INTO `class` VALUES ('首页');

注意:注意数组名和键!数组名是class,键名是name

6、获取分类列表

<?php
$stmt = $pdo->prepare('SELECT * FROM class');
$stmt->execute();
$menu = $stmt->fetchAll();
?>

注意:这里把此列表调取后,创建的数组名是$menu,键名是name

调取和使用代码如下

	//连接数据库,获取别表
<?php
$pdo = new PDO('mysql:host=localhost;dbname=blog', 'root' , '123456' , array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8';"));
$stmt = $pdo->prepare('SELECT * FROM class');
$stmt->execute();
$menu = $stmt->fetchAll();
?>
//遍历数组
<?php
foreach($menu as $val){
?>
<li>
<a href='/index.html'><?php echo $val['name'] ?></a> //打印列表中的数据!
</li>

<?php
}
?>

注意,在创建列表时,数据顺序不同,所以这里调用列表时,显示的顺序不对,怎么解决数据的顺序问题?

五、MySql 增删查改——SQL语法!

关键词 描述
SELECT 查询
INSERT 添加
UPDSTE 修改
DELETE 删除

1、MySql 查询

获取列表内容时使用!

- WHERE 条件

SELECT * FROM article WHERE `class` = 'PHP';

image-20230502230109430

查询语句可以增加查询条件,WHERE 条件可以指定一条或多条语句!只查询分类PHP的!

- 返回值
SELECT title,img,date,class FROM article WHERE `class` = 'PHP';

查询语句默认返回值是全部字段,可以指定字段返回!把*替换成字段名,多个字段用逗号隔开!

- LIMIT 分页
SELECT title,img,date,class FROM article WHERE `class` = 'PHP' LIMIT 2;
SELECT title,img,date,class FROM article WHERE `class` = 'PHP' LIMIT 0,2;

查询语句默认把全部符合规定的数据都查询到,任务量很大时会卡死,使用分页,指定需要几条结果!

注意:有两种写法,指定前一个数,就是从第几条数据开始!后几个数据是显示几个查询结果!

- ORDER BY 排序语句
  • ASC 正序(默认)
  • DESC 倒序
SELECT * FROM article WHERE `class` = 'PHP' ORDER BY `date` DESC;

查询的结果是以正序显示,还是以倒叙显示,给列表增加排序字段,就可以排序了!日期也可以!


2、MySql 插入

发布文章、注册账号时使用!

INSERT INTO article (`title`,`img`,`content`,`date`,`class`)VALUES('PHP是很好的编程语言','','PHP是很好的编程语言','2021-03-03','PHP');

image-20230502232549663

注意:表名括号的字段,依次列出来,并且要和VALUES括号内的数据,一一对应!

3、MySql 修改

UPDATE article SET `title`='PHP中文网', `content`='PHP中文网' WHERE `title`='PHP是很好的编程语言';

image-20230502233130922

注意:SET里面设置要修改的数据,WHERE去指定哪一条要修改,与查询语句语法一致!

一定要指名修改哪一条数据,不然会修改整个表!

4、MySql 删除

DELETE FROM article WHERE `title`='PHP中文网';

image-20230502233754965

注意:必须增加条件,不然会删除整个表!

关于条件关键字的使用范围:
关键词 描述
WHERE 条件(查询、修改、删除)
LIMIT 分页(查询)返回的值
ORDER BY 排序(查询)返回的值
  • 修改和删除,必须增加条件

不增加条件,到时候删库,只能跑路了!


六、PHP 超全局变量——获取前端表单数据

  • 超级全局变量在PHP 4.1.0之后被启用, 是PHP系统中自带的变量,在一个脚本的全部作用域中都可用!

1、全局变量

变量 描述
$_GET 收集来自 method="get" 的表单中的值
$_POST 收集来自 method="post" 的表单中的值
$_REQUEST 包含 $_POST$_GET$_COOKIE
$GLOBALS 全部变量的全局组合数组
$_COOKIE 常用于识别用户
$_SESSION 存储关于用户会话(session)的信息
$_FILES 用来获取通过 POST 方法上传文件的相关信息
$_SERVER 服务器和执行环境信息
$_ENV 环境变量

注意:$_GET$_POST是收集,来自HTML提交的表单!$_REQUEST在php5.3后,默认不开启$_COOKIE

2、$_GET

<html>
<head>
<meta charset="utf-8">
<title>PHP中文网</title>
</head>
<body>
<form action="" method="get">
讲师: <input type="text" name="name">
学校: <input type="text" name="school">
<input type="submit" value="提交">
</form>
</body>
</html>
<?php
if(!empty($_GET)){
print_r($_GET);
}
?>

如果只想打印某条数据,可以通过数组键的方式来打印!

<?php
if(!empty($_GET['name'])){
print_r($_GET['name']);
}
?>

注意:$_GET接受的是URL上的值,直接修改浏览器上的URL也可以改变获取的$_GET值!也就是?后面的数据!

image-20230503000203712

  • get提交时,所有的变量名和值都会显示在 URL 中。所以在发送密码或其他敏感信息时,不要使用这个方法!
  • 方便在浏览器收藏夹收藏

3、$_POST

<html>
<head>
<meta charset="utf-8">
<title>PHP中文网</title>
</head>
<body>
<form action="" method="post">
讲师: <input type="text" name="name">
学校: <input type="text" name="school">
<input type="submit" value="提交">
</form>
</body>
</html>
<?php
if(!empty($_POST)){
print_r($_POST);
}
?>

注意:post提交的信息,不会显示在浏览器的URL中,适合秘密信息,适合大文件!在JS中AJAX也可以提交!

4、$_REQUEST

<html>
<head>
<meta charset="utf-8">
<title>PHP中文网</title>
</head>
<body>
<form action="" method="post">
讲师: <input type="text" name="name">
学校: <input type="text" name="school">
<input type="submit" value="提交">
</form>
</body>
</html>
<?php
if(!empty($_REQUEST)){
print_r($_REQUEST);
}
?>

5、GLOBALS

<html>
<head>
<meta charset="utf-8">
<title>PHP中文网</title>
</head>
<body>
<form action="" method="post">
讲师: <input type="text" name="name">
学校: <input type="text" name="school">
<input type="submit" value="提交">
</form>
</body>
</html>
<?php
$miejie = '灭绝师太';
print_r($GLOBALS);
?>

image-20230503001853297

显示提交的全部数据,包括GLOBALS本身!包括普通变量!当写完代码,调试代码时,想看用了多少变量,就可以使用这个语句!

二、数据分析——数据的调用与排序

传值(URL最好唯一)、筛选(拿传入的值作为筛选条件)、打印(拿到的数组)三步

案例1:点击文章标题,跳转到详情页!——核心是【传值】

分析:首页文件index.php中文章标题,链接到详情页details.php文件!相当于下载了个静态页面!

  • 问:可不可以跳转到详情页时,在详情页下,动态生成文章标题和内容!
  • 答:可以,详情页也连接数据库,并且在跳转时,增加$_GET传值,并筛选出是哪一篇文章,即根据提交的信息,到数据库找到对应的文章!

方法一:文本传值——URL中传入当前文章标题!

文本传值

<a href="/details.php?title=URL跳转">URL跳转</a>

注意:在跳转连接中添加信息,说明哪一篇文章(?后跟的信息),然后使用`$_GET,成为数据库筛选条件!

<h1 class="entry-title">
//完整代码如下,点击标题,跳转到详情页,传入的是文章标题!
<a href="/details.php?title=<?php echo $lists_v['title'] ?>">
//标题的内容
<?php
if(isset($lists_v['title'])){
echo $lists_v['title'];
}
?>
</a>
</h1>

注意:URL附加一段?信息,可以通过全局变量$_GET获取,作为连接数据库后,筛选文章的条件!

然后到文章详情页,展示文章内容!仅展示当前文章的内容!

<!-- 连接数据库,获取信息 -->
<?php
// 连接数据库
$pdo = new PDO('mysql:host=localhost;dbname=blog', 'root' , '123456' , array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8';"));
// 筛选对应文章
$stmt = $pdo->prepare('SELECT * FROM article WHERE `title` = "'.$_GET['title'].'"');
$stmt->execute();
$lists = $stmt->fetchAll();
// 第一篇文章,是索引为0对应的数组,这里把2层数组直接按当前索引的文章,赋值到新数组,成为一维数组!处理后,生成的是一个索引为0的二维数组!
$find = $lists[0];
?>

<article>
<header class="entry-header">
<h1 class="entry-title">

<?php
echo $find['title'];
?>

</h1>
</header>

<img src="<?php echo $find['img']; ?>" alt="这里是图片">

<div class="entry-content ql-editor" id="md-editor" style="padding: 0;">

<?php
echo $find['content'];
?>

</div>

注意:这里筛选文章用get传值,用WHERE条件筛选文章名,但是如果两个文章重名怎么办!
接下来用主键,来唯一分辨文章!

方法2:主键传值——URL中传入当前文章主键!

步骤一、创建主键

主键

  • RDBMS术语:主键是唯一的,一个数据表中只能包含一个主键,你可以使用主键来查询数据。
ALTER TABLE `article`
ADD COLUMN `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '文章主键' FIRST ,
ADD PRIMARY KEY (`id`);

image.png
在MySQL中,执行命令,给每篇文章,创建唯一主键!

步骤二、主键传值
<a href="/details.php?id=1">URL跳转</a>

刚才是用$_GET请求文章名,现在是传入主键!通过主键筛选数据库中唯一文章!

//把index.php文件中,标题链接附加请求键和值改为id
<a href="/details.php?id=<?php echo $lists_v['id'] ?>">
//把details.php文件中,数据库查询条件也改为id
$stmt = $pdo->prepare('SELECT * FROM article2 WHERE `id` = "'.$_GET['id'].'"');

步骤三、打印值,由于筛选,得到的文章一致,这里就不用更改打印了!

案例2:文章分类排序!

给分类创建主键!此时可以正序或者逆序排列!

ALTER TABLE `class`
ADD COLUMN `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' FIRST ,
ADD PRIMARY KEY (`id`);


同理:在分类表中,添加主键
问题:如何修改排序!

案例3、通过自定义值排序!

第一步:在数据库中创建排序字段,默认值为0

ALTER TABLE `class`
ADD COLUMN `sort` int(10) UNSIGNED NULL DEFAULT 0 COMMENT '排序' AFTER `name`;

第二步:给排序字段赋值

第三步:在index.php文件中,修改数据库命令筛选顺序!排序为倒序

$stmt = $pdo->prepare('SELECT * FROM class ORDER BY `sort` DESC');

这样生成的数组,按自定义顺序排列,直接打印输出即可!

案例4、点击分类,仅显示对应分类文章——核心【筛选】

分析:正常是显示全部文章,这里显示的文章为分类文章,也就是说,通过筛选,生成只有当前分类文章!

也就是说,分类分类下的文章 创建强联系,且简单、且传人的值强相关!

解决方法,把分类下的文章,都添加上分类对应的主键!

第一步:给文章修改一下分类的值,从分类的文本改为分类的主键!

ALTER TABLE `article`
ADD COLUMN `class_id` int(10) UNSIGNED NULL DEFAULT 0 COMMENT '分类ID' AFTER `date`;

第二步:传值,修改index.php文件中的文章表链接,添加附加信息!分类主键

<a href='/index.php?id=<?php echo $val['id'] ?>'>

第三步:筛选文章,添加筛选条件为传入的分类主键

<?php
if(!empty($_GET['id'])){
$stmt = $pdo->prepare('SELECT * FROM article2 WHERE `class_id` = '.$_GET['id']);
if($_GET['id']==7){
$stmt = $pdo->prepare('SELECT * FROM article2');
}
}else{
$stmt = $pdo->prepare('SELECT * FROM article2');
}
$stmt->execute();
$lists = $stmt->fetchAll();
?>

第四步:打印,与原代码一致

案例5、文章页显示分类名字——核心【打印】!

分析:文章数组中,没有分类的名称,只有分类的主键值!

通过获取全部分类,查找与之相关主键,然后打印分类的名称!

方法一:获取全部分类,打印

属于 
<a href="/index.html?cate=4" title="查看 Linux中的全部文章" rel="category">

<?php
$stmt = $pdo->prepare('SELECT * FROM class');
$stmt->execute();
$class_v = $stmt->fetchAll();
$class_num = (int)$lists_v['class_id'];

//如果文章存在分类!打印分类名
if(!empty($class_num)){
echo $class_v[$class_num-1]['name'];
}
?>

</a> 分类

注意:生成的分类列表是二维数组,索引为0,对应的id为1,打印时,要在外层数组中的索引减1

WHERE条件

  1. 比较运算符
符号 描述
= 等号
<> 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于
# `=` 等号
SELECT * FROM `article` WHERE `id` = 6;
# `<>` 不等于
SELECT * FROM `article` WHERE `id` <> 6;
# `>` 大于
SELECT * FROM `article` WHERE `id` > 6;
# `<` 小于
SELECT * FROM `article` WHERE `id` < 6;
# `>=` 大于等于
SELECT * FROM `article` WHERE `id` >= 6;
# `<=` 小于等于
SELECT * FROM `article` WHERE `id` <= 6;
  1. 逻辑运算符
符号 描述
NOT 逻辑非,取反
AND 逻辑与
OR 逻辑或
XOR 逻辑异或
# `NOT` 逻辑非
SELECT * FROM `article` WHERE NOT(`id` = 1);
# `AND` 逻辑与
SELECT * FROM `article` WHERE `class` = 2 AND `date` = '2021-02-01';
# `OR` 逻辑或
SELECT * FROM `article` WHERE `class` = 2 OR `date` = '2021-02-01';
# `XOR` 逻辑异或
SELECT * FROM `article` WHERE `id` = 1 XOR `id` = 2;
SELECT * FROM `article` WHERE `id` = 1 XOR `id` = 1;

  1. 比较运算符
符号 描述
BETWEEN 在两值之间
NOT BETWEEN 不在两值之间
IN 在集合中
NOT IN 不在集合中
LIKE 模糊匹配
# `BETWEEN` 在两值之间
SELECT * FROM `article` WHERE `id` BETWEEN 1 AND 10;
# `NOT BETWEEN` 不在两值之间
SELECT * FROM `article` WHERE `id` NOT BETWEEN 1 AND 5;
# `IN` 在集合中
SELECT * FROM `article` WHERE `id` IN (1,5);
# `NOT IN`不在集合中
SELECT * FROM `article` WHERE `id` NOT IN (1,5);
# `LIKE` 模糊匹配
SELECT * FROM `article` WHERE `title` LIKE '%PHP%';
SELECT * FROM `article` WHERE `title` LIKE '%PHP_';

注意:筛选数据!从数据库中,查找合适数据!

案例6、文章页显示分类名字

方法一:获取全部分类

属于 
<!-- 传入值,键为id,值为当前分类下的值,这样就可以调用已编好的通过id获取,文章分类 -->
<a href='/index.php?id=<?php echo $lists_v['class_id'] ?>' title="查看 Linux中的全部文章" rel="category">

<?php
$stmt = $pdo->prepare('SELECT * FROM class');
$stmt->execute();
$menu = $stmt->fetchAll();
//创建数组,专门用来存放分类名
$class_name = [];

foreach($menu as $class_value){
//数组存放分类名,并且分类名的索引与文章中class_id值保存一致,方便打印!
$class_name[ $class_value['id'] ] = $class_value['name'];
}
//如果文章中,存在分类,那么就打印该分类!
if(!empty($lists_v['class_id'])){
echo $class_name[$lists_v['class_id']];
}
?>

</a> 分类

注意:获取的是二维数组,每组中只有id和name有用,技巧通过遍历内部数组生成一个新数组,利用新数组去打印值!

方法二:方法类似,没有我的好!

$stmt = $pdo->prepare('SELECT * FROM class');
$stmt->execute();
$menu = $stmt->fetchAll();
$class = [];
if(!empty($menu)){
foreach($menu as $menu_v){
$class[$menu_v['id']] = $menu_v;
}
}
<a href="/index.php?id=<?php echo $article_v['class']; ?>"><?php echo $class[$article_v['class']]['name']; ?></a> 分类

最后:给链接URL附加数据,键为id,值为当前分类下的值,调用已编好的,通过id,仅显示对应分类文章!

案例7、首页

不属于分类,在数据库中删除首页,首页单独拿出来

<li>
<a href='/index.php'>首页</a>
</li>

案例8、搜索功能

可以通过HTML传值,也可以通过JS传值,然后利用之前的通过id筛选文章,这里改为传入的值来筛选文章!

<script type="text/javascript">
$(function (){
$("#searchsubmit").click(function (){
if($("#s").val() != '') {
location.href = "/index.php?s="+$("#s").val();
}
return false;
});
});
</script>

注意:通过JS传值!

<?php
if(!empty($_GET['id'])){
$stmt = $pdo->prepare('SELECT * FROM article2 WHERE `class_id` = '.$_GET['id']);
}else if(!empty($_GET['s'])){
$stmt = $pdo->prepare('SELECT * FROM article2 WHERE `title` LIKE "%'.$_GET['s'].'%"');
}
else{
$stmt = $pdo->prepare('SELECT * FROM article2');
}
$stmt->execute();
$lists = $stmt->fetchAll();

$stmt = $pdo->prepare('SELECT * FROM class');
$stmt->execute();
$class_menu = $stmt->fetchAll();
// print_r($class_menu);

// 由于是个二维数组,采用遍历的方式,获取里面数组的数据
$temp = [];
foreach($class_menu as $class_m){
$temp[ $class_m['id'] ] = $class_m;
}
?>

注意:这里以文章标题作为筛选条件,还可以添加内容作为条件,使用模糊搜索!

案例1:登录页面

第一步、创建管理员表

在数据库中执行下面代码,创建一个账户!

CREATE TABLE `admin` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '管理员ID',
`account` varchar(50) NOT NULL COMMENT '账号',
`password` char(32) NOT NULL COMMENT '密码',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

# 创建一个管理员账号
INSERT INTO admin(`account`,`password`)VALUES('admin','e10adc3949ba59abbe56e057f20f883e');

image-20230504000721581

第二步:在登陆页面中接受传值,连接数据库,查看与数据库中账户密码是否匹配!

<?php
$pdo = new PDO('mysql:host=localhost;dbname=blog', 'root' , '123456' , array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8';"));
$stmt = $pdo->prepare('SELECT * FROM admin WHERE `account` = "'.$_POST['account'].'"');
$stmt->execute();
$admin = $stmt->fetchAll();

//判断$admin值是否为空,如果查找不到结果,说明账户输入错误,或者没有输入
if(empty($admin)){
echo '你输入的账号不存在';
}
?>

image-20230504091236381

最后判断密码是否正确,然后才是跳转页面,完整代码逻辑

<?php
//首先判断是否有输入
if(!empty($_POST)){
# 判断传值
if(empty($_POST['account'])){
echo '<script>window.alert("请输入账号");history.back();</script>';
return false;
}
if(empty($_POST['password'])){
echo '<script>window.alert("请输入密码");history.back();</script>';
return false;
}

$pdo = new PDO('mysql:host=localhost;dbname=blog', 'root' , '123456' , array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8';"));
//用输入的账户作为数据库筛选条件,既能判断账户是否正常,又能查询出账户数据!
$stmt = $pdo->prepare('SELECT * FROM admin WHERE `account` = "'.$_POST['account'].'"');
$stmt->execute();
$admin = $stmt->fetchAll();
//判断$find值是否为空,如果查找不到结果,说明账户输入错误
if(empty($admin)){
echo '<script>window.alert("账号不存在");history.back();</script>';
return false;
}
//再把查询的账户密码,进行对比!
$find = $admin[0];
// 由于条件要同时满足,用多个if语句
if(md5($_POST['password']) != $find['password']){
echo '<script>window.alert("密码不正确");history.back();</script>';
return false;
}
echo '<script>window.alert("登录成功");window.location.href="article.php";</script>';
return false;

}
?>

超全局变量

可以跨页面访问,可以任意访问!

变量 描述
$_COOKIE 常用于识别用户
$_SESSION 存储关于用户会话(session)的信息
  • $_COOKIE
<?php
setcookie('user','admin');
print_r($_COOKIE);

注意:设置一个函数,用user获取键,用admin获取值!

第一次执行,只保存数据,第二次打印,才能打印数据!

  • $_SESSION
<?php
# 碰到C盘没权限,可以更改盘符目录
// session_save_path("D:/");
session_start();
$_SESSION['user'] = 'admin';
print_r($_SESSION);

注意:session_start();是必须要有的!一旦储存值,就可以跨页面访问!

这两者区别:$_COOKIE存储在浏览器中空间为4K,$_SESSION存在在服务器上!

案例2:登录后台页面中记录用户信息

思路:先在登录页面中,把正确的账户存在在COOKIE中,再到后台管理页面打印值

步骤一:保存账户到COOKIE中

//放在跳转页面之前,把账户id和账户名保存!
setcookie('id',$find['id']);
setcookie('account',$find['account']);

步骤二:判断登录状态

<?php 
//一旦登录的账户信息被清理,就退出后台页面,跳转到登录页面!
if(!empty($_COOKIE['id'])){
echo '<script>window.location.href="login.php";</script>';
return false;
}
?>

方法二:判断登录状态

<?php
//如果不存在cookie值,那么退出登录!
if(empty($_COOKIE)){
echo '<script>window.alert("请先登录");window.location.href="login.php"; </script>';
return false;
}
?>

步骤三:打印账号!

<a class="fly-nav-avatar">
<cite class="layui-hide-xs"><?php echo $_COOKIE['account'] ?></cite>
</a>

案例3、在后台页面中展示的文章列表

连接数据库,获取文章信息,获取的是数组,遍历数组,按HTML结构打印显示!之前前端显示文章做过

// 连接数据库,获取文章信息
$pdo = new PDO('mysql:host=localhost;dbname=blog', 'root' , '123456' , array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8';"));
$stmt = $pdo->prepare('SELECT * FROM article2');
$stmt->execute();
$lists = $stmt->fetchAll();

//获取文章的分类名
$stmt = $pdo->prepare('SELECT * FROM class');
$stmt->execute();
$menu = $stmt->fetchAll();
// print_r($menu);
$class_name = [];

foreach($menu as $class_value){
//利用遍历数组,来获取每一行中,分类的值,并且把键进行更改!匹配文章中的分类值!
$class_name[ $class_value['id'] ] = $class_value['name'];
}

遍历数组,在结构中打印

<?php
foreach($lists as $lists_v){
?>

<tr>
<td><?php
if(isset($lists_v['title'])){
echo $lists_v['title'];
}
?>
</td>
<td>
<?php
if(isset($lists_v['date'])){
echo $lists_v['date'];
}
?>
</td>
<td>


<?php
if(!empty($lists_v['class_id'])){
echo $class_name[$lists_v['class_id']];
}
?>
</td>
<td>
<button type="button" class="layui-btn layui-btn-normal layui-btn-xs">
<i class="layui-icon layui-icon-edit"></i>
</button>
<button type="button" class="layui-btn layui-btn-danger layui-btn-xs">
<i class="layui-icon layui-icon-delete"></i>
</button>
</td>
</tr>

<?php
}
?>

案例4、文章分页

整体思路:把文章分成多少页,每一页仅展示设置的多少条数据!循环HTML结构,页面下方显示多少个页数按钮,点击按钮时,按钮对应链接中传值,通过获取值,来展示第几页,默认为第一页

第一步:按钮结构,每一页的按钮,当前页高亮不可点击,其它页传值可以跳转

<div class="layui-box layui-laypage layui-laypage-default">
<!--当前页面不可点击-->
<span class="layui-laypage-curr">
<em class="layui-laypage-em"></em><em>1</em>
</span>
<!--其它页面可以点击-->
<a href="article.php?p=2">2</a>
</div>

第二步:接受值,设置初始值,这是当前页数

if(empty($_GET['p'])){
$p = 1;
}else{
$p = $_GET['p'];
}

第三步:获取全部文章的数量,设置页数

# 统计文章数量,通过函数count(),计算总的文章数量
$stmt = $pdo->prepare('select count(*) as count from `article2`');
$stmt->execute();
$count = $stmt->fetchAll();
//获取的是二维数组,第一层键值为0,第二层有两个数据,两个值一样,其中第一个数据可以自定义键名
$count = $count[0][0];
//$count = $count[0][count];

设置页数,也对应有几个页数按钮,我这里使用变量,来设置每页三条文章

# 计算页数,可以设置个变量来执行每页多少条数据
$page_num = 3;
//页数除不尽,向上取整!ceil()
$page = ceil($count/$page_num);

注意:p是当前页数,count是总条数,page是总页数

第四步:利用循环,来制作文章按钮,通过判断传入的值,来高亮当前按钮

<!-- 分页按钮,展示分页,并跳转分页 -->
<div class="layui-box layui-laypage layui-laypage-default">
<?php
//利用for循环来生成对应多个按钮
for($i = 1; $i <= $page; $i++){
?>
<?php
//判断是否为当前按钮,并高亮HTML
if($i == $p){
?>
<span class="layui-laypage-curr">
<em class="layui-laypage-em"></em>
<em><?php echo $i; ?></em>
</span>
<?php
//否则就生成可以点击的按钮,点击此按钮时,传入当前按钮的值!
}else{
?>
<a href="article.php?p=<?php echo $i; ?>"><?php echo $i; ?></a>
<?php
}
?>
<?php
}
?>
</div>

注意:可以把循环想象成赋值多少分,每一份中运用的中间变量,也生成明确的值!
第五步:点击按钮,生成对应页面
解决方法:通过提取文章的筛选,通过LIMIT 分页,来筛选文章,第一个参数是从第一个数据开始,第二个是筛选出几条数据!

// 通过设置页数和一页多少篇文章,来展示当前页下的文章
// 从第几篇文章开始展示,每页展示多少篇文章
$from_begin = $page_num*($p-1);
$stmt = $pdo->prepare('SELECT * FROM `article2` LIMIT '.$from_begin.",$page_num");

案例:发布文章

点击发布文章,跳转到新的页面,需要在新页面中判断是否登录,打印用户信息,实现上传文章到服务器,实现上传图片!
第一步:跳转到发布文章的页面

//给按钮添加点击事件
<button type="button" class="layui-btn" style="float:right;" onclick="add()">
<i class="layui-icon layui-icon-addition"></i>添加
</button>
//执行事件函数,跳转到发布文章的页面
function add(){
window.location.href='/admin/article_add.php';
}

第二步:判断登录状态、打印用户信息,这些做过!

<?php
//判断登录状态
if(empty($_COOKIE)){
echo '<script>window.alert("请先登录");window.location.href="login.php";</script>';
return false;
}
?>
<!-- 打印用户信息 -->
<a class="fly-nav-avatar">
<cite class="layui-hide-xs"><?php echo $_COOKIE['account'] ?></cite>
</a>

第三步:添加文章
步骤一、给页面添加表单,用来上传图片和文章等信息

<form class="layui-form">
<div class="layui-form-item">
<label class="layui-form-label">文章标题</label>
<div class="layui-input-block">
<input
type="text"
class="layui-input"
name="title"
placeholder="请输入文章标题"
/>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">图片</label>
<div class="layui-input-block layui-upload">
<button type="button" class="layui-btn" id="test1">上传图片</button>
<div class="layui-upload-list">
<img class="layui-upload-img" id="demo1" style="width:100px;" />
<p id="demoText"></p>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">详情</label>
<div class="layui-input-block">
<textarea
class="layui-textarea"
name="content"
placeholder="请输入详情"
></textarea>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">分类</label>
<div class="layui-input-block">
<select name="class" lay-verify="required" lay-search="">
<option value="">请选择分类</option>
<option value="1">layer</option>
</select>
</div>
</div>
</form>

$_POST变量来获取提交的数据

yue18_20230504_154521

步骤二、获取到的数组包含标题、内容、分类,分别用三个变量来存储!

// 提交文章数据后,用$_POST接受值,用变量来存储提交的数据,并且利于数据操作,没有单引号,也利于判断是否填入信息!
if(!empty($_POST)){
$title = $_POST['title'];
if(empty($title)){
echo '请输入标题';
exit;
}
$content = $_POST['content'];
if(empty($title)){
echo '请输入内容';
exit;
}
$class = $_POST['class'];
if(empty($title)){
echo '请选择分类';
exit;
}
}

步骤三、把获取到的数据插入到数据库中

// 上传文件到数据库
try{
// 连接数据库
$pdo = new PDO('mysql:host=localhost;dbname=blog', 'root' , '123456' , array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8';"));
// 数据库语句,插入文章
$sql = "INSERT INTO article2 (`title`,`img`,`content`,`date`,`class_id`)VALUES('{$title}','','{$content}','{$date}','{$class}');";
$stmt = $pdo->prepare($sql);
$stmt->execute();
// 返回值用的json格式
echo json_encode(['code'=>0,'msg'=>'添加成功']);

}catch (PDOException $e){
// 如果添加数据失败了,就执行这里面的命令,错误信息给$e
echo json_encode(['code'=>1,'msg'=>'添加失败']);
}
return false;

上传文章就成功了,接下来解决分类和上传图片!

案例:下拉分类选项

首先是从数据库中获取分类,然后遍历数组,打印分类!

//获取分类
$stmt = $pdo->prepare('SELECT * FROM class ORDER BY `sort` DESC');
$stmt->execute();
$menu = $stmt->fetchAll();

//打印分类
<?php
foreach($menu as $menu_class){
?>
<option value="<?php echo $menu_class['id'] ?>"><?php echo $menu_class['name'] ?></option>
<?php
}
?>

案例:上传图片!

步骤一、上传图片的JS代码

// 上传图片
layui.use(['layer','form','upload'],function(){
form = layui.form;
layer = layui.layer;
upload = layui.upload;
$ = layui.jquery;

var uploadInst = upload.render({
elem: '#test1'
,url: 'up_img.php'
,before: function(obj){
obj.preview(function(index, file, result){
$('#demo1').attr('src', result);
});
}
,done: function(res){
if(res.code > 0){
layer.msg('上传失败',{'icon':2});
}else{
layer.msg('上传成功',{'icon':1});
}
}
});
});

步骤二、写接口!新建个文件夹,取名为upload_img.php,在文件中,赋值下面的代码,使用全局变量上传文件

变量 描述
$_FILES 用来获取通过 POST 方法上传文件的相关信息
<?php
print_r($_FILES);
?>
  • 开启文件上传路径
# 碰到下面错误,开启上传路径
# <b>Warning</b>: File upload error - unable to create a temporary file in <b>Unknown</b> on line <b>0</b><br />
upload_tmp_dir = C:\Windows\temp

上传图片显示接口错误,打开调试,发现没有错误,上传的图片信息能看见,图片格式为临时文件

image-20230504165854392

步骤三、创建文件夹,并对改变上传文件的编码格式,把图片从临时文件移到创建的文件夹中

函数 描述
json_encode 对变量进行 JSON 编码
is_dir 检查指定的文件是否是目录
iconv 字符串按要求的字符编码来转换
mkdir 创建目录
move_uploaded_file 将上传的文件移动到新位置

在上传文件upload_img.php下,替换成下面的代码!

<?php
if ($_FILES['file']['error'] > 0){
echo json_encode(['code'=>1]);
}else{
if (!is_dir('upload/')){
$res = mkdir(iconv('UTF-8','GBK','upload/'),0777,true);
}
move_uploaded_file($_FILES['file']['tmp_name'],'upload/'.$_FILES['file']['name']);
echo json_encode(['code'=>0]);
}
?>

image-20230504171321559

图片上传成功!但是同一名字的图片,无法上传第二遍!设置上传图片时,自动改名字!

步骤四、更改上传的图片名称

$date = time();
$name = explode('.',$_FILES['file']['name']);
move_uploaded_file($_FILES['file']['tmp_name'],'upload/'.$date.'.'.$name[1]);
echo json_encode(['code'=>0]);

利用时间戳来自动生成名字!

image-20230504172125826

步骤五、增加返回值,在把保存的图片地址返回来,等下上传到数据库中,更改upload_img.php上传文件

<?php
// 先判断是否上传错误,大于0就是错误提示!
if ($_FILES['file']['error'] > 0){
echo json_encode(['code'=>1]);
}else{
// 判断上传目录是否存在,如果不存在,就创建目录mkdir,把文件类型转换下iconv,把'UTF-8'转换成'GBK',0777是权限,可读可写可执行
if (!is_dir('upload/')){
// 返回值
$res = mkdir(iconv('UTF-8','GBK','upload/'),0777,true);
}
// 把上传的文件,移动到刚创建的文件夹中
// move_uploaded_file($_FILES['file']['tmp_name'],'upload/'.$_FILES['file']['name']);
$date = time();
$name = explode('.',$_FILES['file']['name']);
move_uploaded_file($_FILES['file']['tmp_name'],'upload/'.$date.'.'.$name[1]);
// 增加返回值,把返回值放入到表单中,增加个隐藏表单,注意这里的图片返回的地址是相对地址,写全!
echo json_encode(['code'=>0,'data'=>'admin/upload/'.$date.'.'.$name[1]]);
}
?>

把返回值放入到表单中,增加个隐藏表单,注意这里的图片返回的地址是相对地址,再判断上传是否成功!

<div class="layui-upload-list">
<img class="layui-upload-img" id="demo1" style="width:100px;" />
<!-- 增加隐藏`input`框,存储上传后的图片地址 -->
<input type="hidden" class="layui-input" id="img" name="img" />
</div>
,done: function(res){
//如果上传失败
if(res.code > 0){
layer.msg('上传失败',{'icon':2});
}else{
//上传成功
$('#img').val(res.data);
layer.msg('上传成功',{'icon':1});
}
}
$file = 'upload/'.$date.'.'.$name[1];
move_uploaded_file($_FILES['file']['tmp_name'],$file);
echo json_encode(['code'=>0,'data'=>$file]);

步骤六、在提交页面中,增加图片的$_POST数据,在SQL语句中,增加{$img}!

// 增加个上传图片数据,到数据库
$img = $_POST['img'];
// 文件路径上传到数据库
$sql = "INSERT INTO article2 (`title`,`img`,`content`,`date`,`class_id`)VALUES('{$title}','{$img}','{$content}','{$date}','{$class}');";

数据结构——类与对象

  • 类是具有相同属性和操作的一组对象的集合

1、创建类

类就相当于,JS的对象,API等,带有方法和对象的模板,可以在此模板上去创建其它对象!

# 创建类
class Teacher{

}
# 调用类(实例化)
$ouyang = new Teacher();

注意:使用关键字——class创建类,使用关键字new创建于类相关的对象!实例化!

2、复合数据类型——对象

类型 描述
object 对象
var_dump($ouyang);
var_dump($miejue);
var_dump($ximen);

image-20230504200636850

三个实例化对象!

var_dump($ouyang == $miejue);
echo '<hr/>';
var_dump($miejue == $ximen);
echo '<hr/>';
var_dump($ouyang == $ximen);

注意:三个实例化对象的值相等,但并不全等!

3、成员变量——类属性

  • 成员变量,也叫: 类属性,和JS中对象的属性差不多,不过这个属性有关键字public
class Teacher{
public $name = '灭绝师太';
public $school = 'PHP中文网';
}
//实例化对象
$ouyang = new Teacher();
//访问属性值,通过->
echo $ouyang->name;
echo '<hr/>';
echo $ouyang->school;

image-20230504201423996

可以直接访问实例化对象的属性值,$ouyang->name

4、成员方法——方法

class Teacher{
public $name = '灭绝师太';
public $school = 'PHP中文网';

public function fun1(){
echo '姓名:灭绝师太,学校:PHP中文网<hr/>';
}
public function fun2(){
return '姓名:灭绝师太,学校:PHP中文网<hr/>';
}
public function fun3(){
// 在类中使用伪变量: "$this" 引用当前类的成员变量
return '姓名:'.$this->name.',学校:'.$this->school.'<hr/>';
}
public function fun4(){
// 在类中使用伪变量: "$this" 引用当前类的成员方法
return $this->fun3();
}
}
// 类实例化
$yangmi = new Teacher();
$yangmi->fun1();
echo $yangmi->fun2();
echo $yangmi->fun3();
echo $yangmi->fun4();
  • 类里成员有两种:属性(变量)和行为(方法)

注意:方法也要用关键字public创建,方法里面可以使用伪变量this访问内部成员!

魔术方法

方法 描述
__construct 构造方法
__destruct 析构方法
  • 构造方法
class Teacher{
public $name;
public $school;
// 构造方法
public function __construct($name, $school){
$this->name = $name;
$this->school = $school;
}
public function fun3(){
// 在类中使用伪变量: "$this" 引用当前类的成员变量
return '姓名:'.$this->name.',学校:'.$this->school.'<hr/>';
}
// 实例化
$obj = new Teacher('西门大官人','PHP中文网');
echo $obj->fun3();

允许在类内,使用关键字__construct,来构造方法!在实例化的时候,立即执行!

  • 析构方法
class Teacher{
// 析构方法
public function __destruct(){
echo '类执行完毕,要关闭了';
}
}

自动执行,用来释放数据!

  • 其他魔术方法
方法 描述
__call 在对象中调用一个不可访问方法时调用
__callStatic 用静态方式中调用一个不可访问方法时调用
__get 获得一个类的成员变量时调用
__set 设置一个类的成员变量时调用
__isset 当对不可访问属性调用isset()或empty()时调用
__unset 当对不可访问属性调用unset()时被调用
__sleep 执行serialize()时,先会调用这个函数
__wakeup 执行unserialize()时,先会调用这个函数
__toString 类被当成字符串时的回应方法
__invoke 调用函数的方式调用一个对象时的回应方法
__set_state 调用var_export()导出类时,此静态方法会被调用
__clone 当对象复制完成时调用
__autoload 尝试加载未定义的类
__debugInfo 打印所需调试信息

5、类的三大特性

  • 继承:可以让某个类型的对象获得另一个类型的对象的属性和方法
  • 封装:指将客观事物抽象成类,每个类对自身的数据和方法实行保护
  • 多态:指同一个实体同时具有多种形式,它主要体现在类的继承体系中
1、继承
  • extends 关键词继承父类
// 子类代码复用
class PHPTeacher extends Teacher{

}
// 实例化
$obj = new PHPTeacher('西门大官人','PHP中文网');
2、封装
  • public 默认的, 关键词定义类内、类外、子类都可见
  • protected 关键词定义类内、子类可见,类外不可见
  • private 关键词定义类内可见, 子类、类外不可见
class Teacher{
protected $name;
private $school;
public function fun7(){
return $this->name;
}
public function fun8(){
return $this->school;
}
}

// 实例化
$obj = new Teacher('西门大官人','PHP中文网');
//这两个都会报错,类外不可访问
echo $obj->name;
echo $obj->school;

echo $obj->fun7();//可以执行
echo $obj->fun8();//报错

用关键字定义变量或者方法的特点!

3、多态
  • 实现多态的前提是要先继承,在重写父类方法
class Teacher{
private function fun2(){
return '姓名:灭绝师太,学校:PHP中文网<hr/>';
}
}

// 子类代码复用
class PHPTeacher extends Teacher{
public function fun2(){
return '我是重写的方法';
}
}

$obj2 = new PHPTeacher('西门大官人','PHP中文网');
echo $obj2->fun2();

子类,可以重写父类的方法!

6、类进阶

1、静态成员
  • static 关键词定义静态成员
class Teacher{
public static $name;
public static $school;
}
Teacher::$name = '西门大官人';
echo Teacher::$name;

特点:不需要实例化,直接访问和修改内部属性!

2、抽象类
  • abstract 关键词定义抽象方法/抽象类
abstract class Teacher{
protected $name;
private $school;
// 构造方法
public function __construct($name, $school){
$this->name = $name;
$this->school = $school;
}
public function fun3(){
return '姓名:'.$this->name.',学校:'.$this->school.'<hr/>';
}
abstract public function fun4();
}

// 子类代码复用
class PHPTeacher extends Teacher{
public function fun5(){
return $this->fun3();
}
public function fun4(){
return '我是继承后重写的方法';
}
}

$obj2 = new PHPTeacher('西门大官人','PHP中文网');
echo $obj2->fun4();
echo $obj2->fun5();

注意:抽象类不能实例化,可以被继承!

3、接口
  • interface 关键词创建接口。要求类必须实现的方法,但不需要定义方法的具体实现过程
  • implements 关键词使用接口
interface file{
public function noTF($param);
public function noZY($param);
}

class Teacher implements file{
protected $name;
private $school;
public $noTF;
public $noZY;
// 构造方法
public function __construct($name, $school){
$this->name = $name;
$this->school = $school;
}
public function noTF($param){
$this->noTF = $param;
}
public function noZY($param){
$this->noZY = $param;
}
public function fun1(){
return '我是'.$this->name.','.$this->noTF.$this->noZY;
}
}

$obj = new Teacher('欧阳','PHP中文网');
$obj->noTF('我没有体罚学生,');
$obj->noZY('我没有布置作业。');
echo $obj->fun1();

注意:接口不能写完整函数,也就是不包括代码块!要在implements中对方法说明,才能使用!

4、接口常量
  • const 创建常量

常量是不允许被改变的量,定义就必须赋值,赋值后就无法改变!

5、常量
# 创建常量
// 前面是名称,后一个是值
define('HOST','127.0.0.1');
echo HOST;

echo '<hr/>';

# 创建常量
const NAME = 'PHP中文网';
echo NAME;
6、关键词
关键词 类外声明 声明类 声明属性 声明方法 解释
const 定义类常量
extends 扩展类,用一个类去扩展它的父类,继承
public 公用属性或方法
protected 私有属性或方法
private 受保护的属性或方法
static 静态成员
abstract 抽象类或方法
interface 创建接口
implements 实现接口
final 类不能被继承
parent:: 访问父类
$this-> 访问本类
self:: 访问本类静态
namespace 创建命名空间
  • final 类不能被继承
final class Teacher{
public $name = '西门';
}
// 子类代码复用
class PHPTeacher extends Teacher{
}

// 实例化
$obj = new PHPTeacher('西门大官人','PHP中文网');
echo $obj->name;//不能访问,报错
  • parent:: 访问父类
class Teacher{
public $name;
public $school;
// 构造方法
public function __construct($name, $school){
$this->name = $name;
$this->school = $school;
}
public function fun3(){
// 在类中使用伪变量: "$this" 引用当前类的成员变量
return '姓名:'.$this->name.',学校:'.$this->school.'<hr/>';
}
}
// 子类代码复用
class PHPTeacher extends Teacher{
public function fun3(){
return parent::fun3();
}
}
// 实例化
$obj = new PHPTeacher('西门大官人','PHP中文网');
echo $obj->fun3();
  • self:: 访问本类静态
class Teacher{
public static $name;
public static $school;
public static $gongfu = 'PHP';
public static function fun5(){
// 在类中使用伪变量: "$this" 引用当前类的成员变量
return '姓名:'.self::$name.',学校:'.self::$school.'<hr/>';
}
}
echo Teacher::$gongfu;
Teacher::$name = '西门大官人';
Teacher::$school = 'PHP中文网';
echo Teacher::fun5();

7、命名空间

  • 命名空间: 解决全局成员的命名冲突问题, 借鉴了文件目录的思想
  • 目录: 同一目录下不允许重名文件, 但不同目录下, 允许同名文件存在
  • 空间: 同一空间内不允许成员重名, 但不同空间内, 允许同名成员存在
1、命名空间
  • 解决全局成员的命名冲突问题
function php(){

}
function php(){

}

这会报错,不能同名,但可以解决!

2、创建命名空间
  • 命名空间使用 “namespace” 关键字声明
//使用花括号
namespace one{
function php(){

}
}
namespace two{
function php(){

}
}
//或者使用结束符,更倾向于第二种!
namespace three;
function php(){

}

namespace four;
function php(){

}
3、常量、函数、类

只能在对应的命名空间能直接使用,跨区域会报错,变量可以跨!

4、子命名空间
namespace{
const NAME = '灭绝师太';
function php(){

}
class phpcn{

}
}
namespace one{
const NAME = '西门大官人';
function php(){

}
class phpcn{

}
}
namespace one\two{
const NAME = '西门大官人';
function php(){

}
class phpcn{

}
}
5、访问命名空间
  • use 关键字引用命名空间
  • AS 解决类名过长、重名问题
namespace one;
const NAME = '灭绝师太的常量';
function php(){
echo '灭绝师太的函数';
}
class phpcn{
public function fun(){
echo '灭绝师太的类';
}
}

echo php();
echo '<hr>';
echo \two\php();
echo '<hr>';
echo \one\two\three\php();
echo '<hr>';
use \one\two\three as t;
echo t\php();
echo '<hr>';

namespace two;
const NAME = '西门大官人的常量';
function php(){
echo '西门大官人的函数';
}
class phpcn{
public function fun(){
echo '西门大官人的类';
}
}


namespace one\two\three;
const NAME = '欧阳的常量';
function php(){
echo '欧阳的函数';
}
class phpcn{
public function fun(){
echo '欧阳的类';
}
}
6、冲突——不同文件夹下同一命名空间,引入到同一文件中使用时,发生冲突!
  • 新建目录文件:/one/one.php
<?php
namespace one\one;
const NAME = '灭绝师太的常量';
function php(){
echo '灭绝师太的函数';
}
class phpcn{
public function fun(){
echo '灭绝师太的类';
}
}
  • 新建目录文件:/two/one.php
<?php
namespace two\one;
const NAME = '西门大官人的常量';
function php(){
echo '西门大官人的函数';
}
class phpcn{
public function fun(){
echo '西门大官人的类';
}
}
  • 解决冲突
<?php
require 'one\one.php';
require 'two\one.php';
use one\one as o;
use two\one as t;

$php = new t\phpcn();
$php->fun();
echo '<hr>';
echo o\php();

8、PHP8 类的新特性

1、构造器属性提升
<?php
namespace phpcn;
class Teacher{
public $name;
public $school;
// 构造方法
public function __construct($name, $school){
$this->name = $name;
$this->school = $school;
}
public function fun(){
// 在类中使用伪变量: "$this" 引用当前类的成员变量
return '姓名:'.$this->name.',学校:'.$this->school.'<hr/>';
}
}
// 实例化
$obj = new Teacher('灭绝师太','PHP中文网');
echo $obj->fun();
  • 更少的样板代码来定义并初始化属性
<?php
namespace phpcn;
class Teacher{
// 构造方法
public function __construct(
public $name,
public $school
){

}
public function fun(){
// 在类中使用伪变量: "$this" 引用当前类的成员变量
return '姓名:'.$this->name.',学校:'.$this->school.'<hr/>';
}
}
// 实例化
$obj = new Teacher('西门大官人','PHP中文网');
echo $obj->fun();

注意:这里允许,直接传参!

2、联合类型
类型 描述
bool 布尔型:truefalse
int 整型:负数 - 0 - 无限大
float 浮点型:带小数的数字(负数 - 0 - 无限大)
string 字符串:汉字、英文、符号、其它国家语言
array 数组:一组数据的集合
object 对象:存储数据和有关如何处理数据的信息
mixed 新增:任何类型
<?php
namespace phpcn;
class Teacher{
// 构造方法
public function __construct(
public string $name,
public string $school,
public int|float $num
){

}
public function fun(){
return '姓名:'.$this->name.',学校:'.$this->school.',今年是'.$this->num.'年<hr/>';
}
}
// 实例化
$obj = new Teacher('西门大官人','PHP中文网',2022);
echo $obj->fun();
3、mixed
类型 描述
mixed 新增:任何类型
<?php
namespace phpcn;
class Teacher{
// 构造方法
public function __construct(
public mixed $name,
public mixed $school,
public mixed $num
){

}
public function fun(){
return '姓名:'.$this->name.',学校:'.$this->school.',今年是'.$this->num.'年<hr/>';
}
}
// 实例化
$obj = new Teacher('西门大官人','PHP中文网',2022);
echo $obj->fun();