非原生开发

课堂完结后欲复习巩固也方便后续-重游-故写此篇
从实现功能过渡到涉及的相关知识点

前端模板功能

1、有点前后端分离的思想。写好前端模板代码后由后端语言去替换相应的部分达到模板的作用。一般有两种实现实现方式:原生与第三方。
2、code比如<h1 class="news-title">第{nums}个新闻:{title}</h1>(原生实现)
3、简单流程:引入模板 -> 导入数据库数据 -> 创建要替换的模板变量与替换值的对应关系 -> 依据关系赋值给指定模板(第1、2步可换位置)

原生

知识点

1、 前端模板代码就和普通html一样写,就是在需要替换的地方换成{only_name}就想上面一样。

2、 想要在 php 语言中实现框架的识别与引入,在替换前就得先设置好路径,语法如下:

1
2
3
4
5
//想写好模板,然后替换并在这里显示(执行eval
$template=file_get_contents("realative_path/name_framework.html");
//替换结束后还需要执行下面语句
//输出值将被赋给指定的模板变量
eval("?>".$template);

code

原生简单模拟的代码并不复杂,如下:

index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>新闻页面</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
padding: 0;
background-color: #f4f4f9;
}
.news-article {
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
overflow: hidden;
}
.news-header {
padding: 15px;
background-color: #007bff;
color: white;
}
.news-title {
font-size: 24px;
margin: 0;
}
.news-author {
font-size: 14px;
color: #ccc;
}
.news-content {
padding: 15px;
}
.news-image {
width: 100%;
height: auto;
}
</style>
</head>
<body>

<div class="news-article">
<div class="news-header">
<h1 class="news-title">第{nums}个新闻:{title}</h1>
<p class="news-author">作者:{author}</p>
</div>
<img src="{img}" alt="图片" class="news-image" height="300" width="100">
<div class="news-content">
<p>{content}</p>
</div>
</div>

</body>
</html>

index.php 如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
//链接数据库
include '../config.php';

//想写好模板,然后替换并在这里显示(执行eval
$template=file_get_contents("./index.html");

//语句
$id=$_GET['id'] ?? '2';
$sentence="select * from news where id=$id";
//执行并接收返回
if(!($news=mysqli_query($mysqli_connect,$sentence))){
echo "数据库链接失败!";
};
//显示
$search=["{nums}","{title}","{author}","{content}","{img}"];
while ($rows=mysqli_fetch_row($news)) {
// echo "<h1>标题:$rows[1]</h1>";
// echo "<h3>作者:$rows[2]</h3>";
// echo "<div>$rows[3]</div>";
// echo "<img src='$rows[4]' weight='200' height='400'>";
//直接替换和执行
$template=str_replace($search, $rows, $template);
eval("?>".$template);
}
?>

安全问题

1、 分析:自写的代码并连接数据库如果对安全问题不重视,容易产生 sql注入漏洞与任意代码执行


第三方模板(以smarty为例)

由于是简单使用,所以并没有了解很深,这里简单说下区别。
1、只需要在配置文件里设置数据库的配置就可以任意连接数据库等,自带一些过滤。
2、依据 smarty 语法写好的php代码在运行时会被解析成模板php文件供中间件解析与浏览器显示

代码都是一些实验的,并没有小项目之类的,就简单说一下一些语法:

1、 和原生一样的设变量 + 替换。

变量:{$only_name},就是里面加了个 $
单个替换:$smarty->assign("Name", "开炮!", true);

2、 这里用语法里的 display() 函数来复习运行php文件内部流程:

目录结构

目录结构

code:

1
2
// 在代码最后调用display(),里面是前端模板以template文件为根的相对路径
$smarty->display('index.tpl');

当调用 display() 函数时,Smarty将执行以下步骤:


1、尝试将传递给 display() 函数的模板路径解析为绝对路径。
2、尝试从缓存中获取已编译的模板,如果存在,则跳至第6步。
3、如果缓存中不存在已编译的模板,则Smarty会编译模板,生成PHP代码,并将其缓存到磁盘上。
4、Smarty会将编译后的代码包含在当前PHP脚本中,并执行它。
5、输出编译后的模板内容。
6、Smarty清理各种临时变量和句柄,完成页面渲染。


安全问题

1、 第三方模板,如果使用的是由历史漏洞的版本那么就会发生危险,比如 CVE-2021-26120 ,smarty-3.1.38就会有这个漏洞,smarty-3.1.39就修复了。

2、 如果并没有按照模板的语法来写而是自己写的话那么也可能会在一些地方产生漏洞。


框架(以 thinkphp 为例)

PHP Web框架是用于构建Web应用程序的工具和库集合,旨在简化开发过程,提高代码质量和开发效率。
也就是说不管是上篇的原生开发里的部分,还是上面的模板部分(内置有smarty),框架都可以很轻松的包含进去,并设置了特定语法,增强代码的安全性,让开发人员致力于代码开发而非其他地方。

这里由-文件上传功能-和-数据库操作-来引入复习内容

前置:路由访问(以小皮为例)

知识点

一、路径路由

1、 想要运行 thinkphp 得先在小皮里新建一个以 thinkphp/public 为根目录的网站,访问对应 ip和端口会自动访问 public/index.php 文件。

2、 或者在 application文件里新建 /controller/Index.php,在里面创建index方法,那么首页也会从index方法里读取返回值并显示。

3、 那么想要访问其他模板呢?

以上面首页为例,除了默认访问之外还可以通过 “模块名/控制器名/方法名” 来访问,所以是127.0.0.1:81/index.php/index/index/index,如图,第一个 index 为 application 下的模块名,第二个index为模块下 controller 里的首字母大写(规范写法)的控制器名:Index,最后是 index.php 里的方法名 index;

在这里插入图片描述

二、参数路由

1、 thinkphp 不但支持参数的 get方式传递?id=1,还支持路由传递/id/1,想实现这种方式code如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
//入口
namespace app\index\controller;
//引入
use think\Controller;
use think\Request;
//
class Index extends Controller
{
//首页
public function index()
{
//自控显示
return 123;
}
//框架传递参数方式
public function test1()
{
return $this->request->param('name');
}
//原生传递参数方式
public function test2()
{
$name=$_GET['name'];
return $name;
}
}

文件上传功能

大致流程:用表单简单写一个文件上传,同样的访问路径接收,然后保存文件

表单:

1
2
3
4
<form action="/index.php/test/test/upload" enctype="multipart/form-data" method="post">
<input type="file" name="image" /> <br>
<input type="submit" value="上传" />
</form>

接收:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
namespace app\test\controller;

use think\Controller;
use think\Request;

class Test extends controller
{
//文件上传
public function upload(){
// 获取表单上传文件 例如上传了001.jpg
$file = request()->file('image');
// 移动到框架应用根目录/uploads/ 目录下
//大小限制,类型限制
$info = $file->validate(['size'=>156780000,'ext'=>'jpg,png,gif'])->move( '../uploads');
if($info){
// 成功上传后 获取上传信息
// 输出 jpg
echo $info->getExtension()."<br>";
// 输出 20160820/42a79759f284b767dfcb2a0197904287.jpg
echo $info->getSaveName()."<br>";
// 输出 42a79759f284b767dfcb2a0197904287.jpg
echo $info->getFilename();
}else{
// 上传失败获取错误信息
echo $file->getError();
}
}
}

数据库操作

也容易猜,只需配置文件里设置就好了:在 主文件下/config/database.php里,如下图:
还有就是如果需要引用数据库,那么就在上面加上 use think\Db; 引入就好了。

在这里插入图片描述

示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
namespace app\index\controller;

use think\Db;

use think\Controller;
use think\Request;

class Index extends Controller
{
public function index()
{
//不用——全是漏洞!
$id=$_GET['id'];
$data=Db::query("select *from news where id=$id");

//用一半,有漏洞
$ids=$this->request->param('id');
// 1、安全点写法——参数通过数组形式传递,可防sql注入
$data=Db::query("SELECT * FROM news WHERE id=:ids",['ids'=>$ids]);
// 2、原始写法
// $data=Db::query("select *from news where id=$id");

//内置写法,无漏洞()
// $id=$this->request->param('id');
// $data=Db::table('news')->where('id',$id)->find();

// return $data;
return json($data);
// return 123;
}
}

MVC模型

MVC 是一种 设计/开发 模式。
MVC 是一种软件架构模式,将应用程序分为三个主要部分:
模型(Model):负责数据的处理和业务逻辑。
视图(View):负责数据的展示和用户界面。
控制器(Controller):负责接收用户输入,调用模型和视图完成用户请求。

自我理解:
    上面说路由的时候说到了如何访问,浅谈框架的时候也说明了内置有 smarty,那么如何使用 smarty呢?

    市面上普遍使用的是 MVC模式,就是下图。模块里面 controller 和 view,每一个控制器都有一个 view 模块,里面就是相对应的 html 前端文件。

在这里插入图片描述

这里举一个 test 模块里 Test.php 控制器里 vv 方法的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//view:框架上的html与php的配合
public function vv()
{
// 模板变量赋值
// $this->assign('name','ThinkPHP');
// $this->assign('email','thinkphp@qq.com');

// 或者批量赋值
$this->assign([
'name' => 'ThinkPHP',
'email' => 'thinkphp@qq.com'
]);
//模板输出:默认为空就是方法名,可修改
return $this->fetch('index');
}

安全问题

1、 不使用内置代码写法

    比如数据库操作里接收 id 值,如果你用原生的$_GET[‘id’]的话就会有sql注入的问题。因为框架是有内部过滤的,如果不用定义语法就无法进行过滤。

2、 thinkphp还有老的连接数据库的语句,原理也是拼接。

    老/危险的:

1
2
3
4
5
//最原始
Db.query("select * from news where id=$ids");
//升级语句,参数通过数组形式传递
Db::query("SELECT * FROM news WHERE id=:ids",['ids'=>$ids]);
//:ids是命名占位符,用于绑定参数,防止 SQL 注入

    新/安全的:Db::table('news')->where('id',$id)->find();

3、 版本漏洞

    作为第三方开源的产品,可能会有历史漏洞,造成安全问题。

(如有不恰当的地方欢迎指正哦 \x7eo(●’◡’●)o)


参考blogs:

smarty模板中display函数的原理

PHP中使用Smarty模板目录结构配置

thinkPHP框架详解+部署

smarty完全中文手册