第5章内容管理系统 内容管理系统(Content Management System,CMS)是互联网上对信息进行分类管理,并快捷更新的Web应用系统。它能够将杂乱无章的信息,及时、准确、有序地呈现在网络用户面前,使信息的共享更加快捷和方便。 本章通过一个简单的内容管理系统的开发,向读者介绍PHP Web应用程序开发的基本方法、技术规范,以及相关的开发技术。 视频讲解 5.1项 目 简 介 CMS应用非常广泛,例如企业网站、政府信息平台等。在网络中,常见的门户、新闻、博客、文章等类型的网站,以及各类信息、数据查询系统,都可以利用CMS进行开发。 5.1.1功能描述 作为第一个项目,通过该项目的开发,熟悉PHP Web应用项目开发的各项技术,进一步巩固PHP程序设计语言的语法及编程规范并能综合应用基础理论知识,解决实际的工程、技术或应用问题。鉴于此目的,本项目采用面向过程的程序设计方法,实现内容管理系统的基本功能,包括前台展示功能与后台管理功能。 前台功能包括内容的列表展示、内容的分类展示、内容的详情展示、内容的搜索,以及用户的注册与登录等。 后台功能包括用户管理、内容管理、分类管理等。 5.1.2运行预览 本章项目的完整运行效果,请读者自行运行本书提供的源码,项目目录名称为chap05。这里只展示前台首页、内容详情、分类查询、后台主页、后台用户管理页面的运行效果,如图5.1~图5.5所示。 图5.1前台主页 图5.2内容详情 图5.3分类查询 图5.4后台主页 图5.5用户管理 其他页面效果请运行源码,本章项目源码目录为chap05。运行时请先阅读案例项目运行说明。 5.2项 目 准 备 Web项目的开发是一项复杂的系统工程,一般包括系统分析、系统设计、系统实现,以及系统测试等诸多环节,其中,系统分析与系统设计需要在项目的准备阶段完成。 视频讲解 图5.6项目目录结构 由于篇幅的限制,这里只简单地介绍一下系统设计,项目的系统分析,例如需求分析、可行性分析、项目计划书的编写等工作,读者可自行参考其他技术文档学习完成。 5.2.1系统初步设计 系统初始设计包括确定系统目标、系统功能、数据库类型,以及系统开发框架等内容。下面简单介绍项目的创建、静态资源的准备以及初始化文件设计等内容。 1. 创建PHP项目 创建一个PHP本地项目,项目名称为“微梦内容管理系统”,项目目录为chap05,对应的虚拟主机为book.php.chp05。项目目录结构如图5.6所示。 该项目分为前台与后台两个模块,其中,前台文件存放在项目根目录下的home子目录中,后台模块文件存放在admin目录下。项目根目录下的common与public子目录中存放前后台模块的公用文件。项目结构中的目录及文件说明如表5.1所示。 表5.1项目目录及文件说明 属性 说明 admin 后台模块目录 admin/ 后台模块中的页面文件目录 admin/view 后台模块视图文件目录 common 前后台公共文件目录 common/captcha/ 图形验证码文件目录 common/lib/ 自定义库文件目录 error 错误页面文件目录 frame 系统配置与初始化目录 home 前台模块目录 public 系统公共静态资源目录 Index.php 系统入口文件 这里只介绍了主要目录与文件,详情请参见源码。 2. 准备公共资源 项目的公共资源,主要包括项目前后台模块使用的公共CSS样式文件、JavaScript脚本文件、图像文件,以及共同使用的自定义和第三方开发的库文件等。 1) 引入CSS和JS文件 本项目前端使用Layui及jQuery前端框架。下载Layui和jQuery资源,并将其复制到项目根目录下的public\static子目录中。 2) 加载自定义函数库 在项目根目录下的common目录中创建子目录lib,并在其中新建一个名为function.php的PHP文件。该文件是自定义库文件,存放项目模块的公共函数。 函数库文件function.php的加载,一般在项目的初始化文件中完成。下面创建项目的初始化文件init.php。 3. 创建初始化文件 项目的初始化文件主要用于完成定义常量、加载资源,以及启动SESSION等工作。在项目根目录下的frame子目录中,新建init.php文件并编写如下代码。 <?php /** * 项目初始化文件 * 定义常量、加载资源、启动SESSION * @author weiwenping */ define('APP_NAME', '微梦内容管理系统'); define('ADMIN_NAME', '微梦后台管理系统'); define('DOC_ROOT', $_SERVER['DOCUMENT_ROOT']); define('DOC_COMMON', DOC_ROOT.'/common/'); define('DOC_LIB', DOC_COMMON.'lib/'); define('CAPTCHA_FONT_PATH', DOC_COMMON.'captcha/'); define('CONFIG_PATH', DOC_ROOT.'/frame/'); //前台文件目录常量 define('HOME_ROOT', DOC_ROOT.'/home/'); define('HOME_VIEW_PATH', HOME_ROOT.'/view/'); //后台文件目录常量 define('ADMIN_ROOT', DOC_ROOT.'/admin/'); define('ADMIN_VIEW_PATH', ADMIN_ROOT.'/view/'); //公共资源引用目录常量 define('WEB_ROOT', 'http://book.php.chp05/'); define('WEB_STATIC', WEB_ROOT.'public/static/'); define('LAYUI_PATH', WEB_STATIC.'layui/'); define('LAYUI_CSS_PATH', LAYUI_PATH.'css/'); define('LAYUI_JS_PATH', LAYUI_PATH); define('JQUERY_PATH', WEB_STATIC.'jquery/'); define('CSS_PATH', WEB_STATIC.'css/'); define('JS_PATH', WEB_STATIC.'js/'); define('UPLOAD_PATH', WEB_ROOT.'public/upload/'); //后台模块目录常量 define('WEB_ADMIN', WEB_ROOT.'admin/'); //加载公共资源函数库 require DOC_LIB.'function.php'; //开启SESSION session_start(); /** * 项目启动函数 * @return string[]|unknown[] */ function run(){ //获取请求的URI $request_uri = $_SERVER['REQUEST_URI']; //获取请求的入口文件 $script_name = $_SERVER['SCRIPT_NAME']; //获取URL中的模块、方法和查询字符串 $request = str_replace($script_name, '', $request_uri); $request = ltrim($request, '/'); //将查询字符串分离 $request_array = explode('?', $request); //将模块和方法存放在数组中 $module_action = $request_array[0]; if (empty($module_action)) { $module = 'home'; $action = 'index'; }else{ $module_action = explode('/', $module_action); //获取模块 if (isset($module_action[0]) && !empty($module_action[0])) { $module = $module_action[0]; }else{ $module = 'home'; } //获取方法 if (isset($module_action[1]) && !empty($module_action[1])) { $action = $module_action[1]; }else{ $action = 'index'; } } //请求的文件 $require = DOC_ROOT.'/'.$module.'/'.$action.'.php'; if (file_exists($require)) { require_once $require; }else{ require_once DOC_ROOT.'/error/error.html'; } } 在系统初始化文件中,除定义一些必要的常量外,还定义了一个名为run()的函数,该函数是系统的启动函数,起着一个简单的路由作用。 5.2.2系统流程设计 系统功能确定以后,需要设计系统架构,也就是系统的整体框架。本系统是一个简单的PHP设计项目,所以项目功能不复杂。本项目系统架构模拟MVC设计模式。 下面通过测试页面,对项目前台模块执行流程进行设计。首先设计系统入口文件。在项目根目录下创建index.php文件,代码如下。 <?php /** * 系统入口文件 * @author weiwenping */ //加载项目初始化文件 require './frame/init.php'; //启动项目 run(); 接着,在前台模块home目录中新建测试文件,分别为test.php和view\test.php,代码如下。 <?php defined('APP_NAME') or exit('非法访问'); /** * 前台测试文件test.php */ $data['test'] = array( [ 'id' => '1', 'name' => '面向对象程序设计(C++语言描述)', 'author' => '马石安 魏文平', 'press' => '清华大学出版社' ], … ); //加载视图 require HOME_VIEW_PATH.'v_test.php'; <!-- 前台测试视图文件home\view\test.php --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>前台测试页面</title> <link rel="stylesheet" href="<?php echo LAYUI_CSS_PATH;?>layui.css" /> </head> <body class="layui-body"> <h2>前台测试页面</h2> <hr> <div class="layui-table"> <table> <thead> <tr><th>序号</th><th>教材名称</th><th>作者</th><th>出版社</th></tr> </thead> <tbody> <?php foreach($data['test'] as $v): ?> <tr><td><?php echo $v['id'];?></td><td><?php echo $v['name'];?></td> <td><?php echo $v['author'];?></td><td><?php echo $v['press'];?></td> </tr> <?php endforeach; ?> </tbody> </table> </div> </body> </html> 打开浏览器,在地址栏中输入“http://book.php.chp05/index.php/home/test”,运行效果如图5.7所示。 图5.7前台测试页面运行效果 在上述URL中,“index.php”表示系统入口文件; “home”表示系统前台模块; “test”表示需要访问的前台文件。如果与MVC模式项目进行类比,可以看出,前台模块中的PHP文件相当于MVC的控制器; 视图目录view中的PHP文件相当于MVC的视图; 而控制器中的数据准备则相当于MVC的模型。 所以,本系统的访问流程确定为: 系统域名→入口文件→模块→页面文件→页面视图。 在上述测试页面中,测试数据是通过数组的方式直接准备的,在后续的开发过程中,页面中的数据要从数据库中通过“模型”来获取。 5.2.3数据库设计 数据库设计是PHP Web项目开发的重要环节,数据库设计的质量直接影响着系统运行的效率与速度。 为项目创建一个名为wmchap05db的MySQL数据库,并在其中创建数据表,数据表名均使用“wm_”前缀。由于篇幅的限制,这里只展示系统管理员数据表、文章数据表和菜单数据表,其他数据表请参见源码包中的相关资源。 项目管理员数据表wm_admin的结构及字段含义分别如图5.8和表5.2所示。 图5.8数据表wm_admin的结构 表5.2数据表wm_admin字段说明 字段 说明 id 序号。主键 username 用户名 password 密码。MD5加密 truename 用户真实姓名 gid 用户类型分组ID。对应数据表tb_admin_groups中的GID status 管理员账号状态。1表示禁用,0表示正常 add_time 注册时间 项目文章数据表wm_article的结构及字段含义分别如图5.9和表5.3所示。 图5.9数据表wm_article的结构 表5.3数据表wm_article字段说明 字段 说明 id 序号,主键 title 文章标题 title_img 文章标题图片,在前台主页列表显示时使用,如图5.1所示 is_hot 是否是热门文章 is_top 是否将文章置顶 cate_id 文章类型ID user_id 作者ID content 文章内容 pv 文章浏览次数 status 文章显示状态 create_time 文章提交时间 update_time 文章修改时间 项目菜单数据表wm_menu的结构及字段含义分别如图5.10和表5.4所示。 图5.10数据表wm_menu的结构 表5.4数据表wm_menu字段说明 字段 说明 id 序号。主键 name 菜单名称 href 菜单URL position 菜单位置 pid 菜单的父菜单ID status 菜单状态 order 菜单排列顺序 上述对数据库的操作与管理,使用的是SQLyog工具软件。请读者选择自己熟悉的数据库管理工具进行操作。 5.3后台功能实现 Web项目的开发往往都是从后台开发开始的。下面实现项目后台管理系统的部分功能,包括管理员信息显示,管理员登录验证,管理员添加、编辑与删除; 内容分类管理、内容详情管理等。 视频讲解 5.3.1主页设计 系统后台主页运行效果如图5.4所示。 1. 后台布局 系统后台模块主要负责系统数据的管理,例如,管理员的添加、删除、信息修改,以及信息显示; 管理员权限设置; 内容的添加、编辑、删除、审核等。 把后台模块的所有操作集中到页面左侧的菜单,操作内容则在页面的主显示区域中进行显示,如图5.5所示。 单击页面中侧边栏“用户管理”菜单下的“用户列表”子菜单,则会在页面的主显示区内,显示所有的系统用户信息,同时显示各种操作按钮。 单击页面左上角的主页图标及文本,可以重新加载后台模块封面页面; 单击页面右上角的“退出系统”,则可以退出系统的后台管理,如图5.11所示。 图5.11系统后台主页 2. 侧边栏设计 侧边栏中的导航菜单信息不是直接固定在页面代码中的,它们来自数据库中的wm_menus数据表。 1) 数据库操作 在系统自定义库文件目录common\lib中新建db.php文件,在该文件中编写数据库连接、数据表查询等函数,代码如下。 <?php /** * 数据库连接 * @return NULL|mixed */ function db_connect() { static $link = null; if (!$link) { $link = call_user_func_array('mysqli_connect', getConfigItem('DB_CONNECT')); if (!$link) { exit('数据库连接错误'); } } return $link; } /** * 数据查询 * @param string $sql * @param string $type * @param array $data * @return object */ function db_query($sql, $type='', $data=[]) { $link = db_connect(); $stmt = mysqli_prepare($link, $sql); if (!$stmt) { $error = mysqli_error($link).'<br>SQL语句:'.$sql; exit('数据库操作错误!'.$error); } if ($data == []) { mysqli_stmt_execute($stmt); }else{ $data = (array)$data; db_bind_param($stmt, $type, $data); mysqli_stmt_execute($stmt); } return $stmt; } /** * 查询数据绑定 * @param object $stmt * @param string $tyle * @param array $data */ function db_bind_param($stmt, $tyle, &$data) { $params = [$stmt, $tyle]; foreach ($data as &$params[]) { } call_user_func_array('mysqli_stmt_bind_param', $params); } define('DB_ALL', 0); define('DB_ROW', 1); define('DB_COLUMN', 2); define('DB_AFFECTED', 3); define('DB_LASTED', 4); /** * 查询结果处理 * @param int $mode * @param string $sql * @param string $type * @param array $data * @return array */ function db_fetch($mode, $sql, $type='', $data=[]) { $stmt = db_query($sql,$type,$data); $result = mysqli_stmt_get_result($stmt); switch ($mode) { case DB_ROW: return mysqli_fetch_assoc($result); ; break; case DB_COLUMN: return current((array)mysqli_fetch_row($result)); break; default: return mysqli_fetch_all($result, MYSQLI_ASSOC); break; } } /** * 数据查询,没有结果集的查询 * @param int $mode * @param string $sql * @param string $type * @param array $data * @return int */ function db_exec($mode, $sql, $type='', $data=[]) { $stmt = db_query($sql, $type, $data); switch ($mode) { case DB_LASTED: return mysqli_stmt_insert_id($stmt); break; default: return mysqli_stmt_affected_rows($stmt); break; } } function db_connect() { static $link = null; if (!$link) { $link = call_user_func_array('mysqli_connect', getConfigItem('DB_CONNECT')); if (!$link) { exit('数据库连接错误'); } } return $link; } 上述代码中的getConfigItem()是自定义函数,用于获取配置文件中的数据库连接信息。数据库连接数据存放在系统根目录下的frame子目录中,文件名为config.php。 数据库操作文件db.php中的功能函数,由于代码都比较简单,这里不再详细说明,请使用源码自行学习。 2) 获取菜单数据 在系统common\lib\function.php文件中,编写菜单处理函数。其中,getMenus()函数返回某个模块、某个位置中的全部菜单; getSubMenus()函数返回某个菜单项的二级菜单。为了简单一些,本项目菜单只分为二级,代码如下。 function getMenus($module, $position) { //从数据库中获取菜单信息 $sql = "select * from wm_menus where module = '". $module."' and position = '".$position."'" .' order by order'; $menus = db_fetch(DB_ALL, $sql); return $menus ? $menus : null; } function getSubMenus($menus, $menus_id) { $subMenus = array(); foreach ($menus as $v) { if ($v['pid'] == $menus_id) { array_unshift($subMenus, $v); } } return $subMenus ? $subMenus : null; } 在后台页面的PHP文件中,调用上述方法,获取菜单数据,代码如下。 //获取侧边栏导航菜单 $side_navs = getMenus('admin','side'); foreach ($side_navs as $k => $v) { $data['side_navs'][$k] = $v; $data['side_navs'][$k]['sub'] = getSubMenus($side_navs, $v['id']); } 最后,设计侧边栏视图。文件为admin\view\side.php,代码如下。 <?php defined('APP_NAME') or exit('非法访问');?> <div class="layui-collapse" lay-accordion> <?php foreach ($data['side_navs'] as $v):?> <?php if($v['pid']==0):?> <div class="layui-colla-item" style="padding-left:10px;"> <h2 class="layui-colla-title"><?=$v['name']?></h2> <div class="layui-colla-content"> <?php if($v['sub'] === null): ?> <span style="padding:5px;"><a href="<?=$v['href']?>">管理主页</a></span> <?php else: ?> <ul> <?php foreach($v['sub'] as $sub): ?> <li style="padding:5px;border-bottom: 1px dashed #FF5722;"> <a href="<?=$sub['href']?>"><?=$sub['name']?></a> </li> <?php endforeach; ?> </ul> <?php endif;?> </div> </div> <?php endif;?> <?php endforeach;?> </div> 侧边栏运行效果如图5.12所示。 图5.12后台页面中的侧边栏 这里使用了Layui的面板组件,单击一级菜单名称,展开二级菜单列表; 单击二级菜单,在页面右侧的区域显示主内容。 3. 后台主页设计 用户访问系统后台主页,就是加载系统的admin\index.php文件,该文件代码如下。 <?php defined('APP_NAME') or exit('非法访问'); /** * 系统后台首页文件 * admin\index.php */ //视图数据 $data = array( 'title'=>'后台首页', 'css_files' =>array( LAYUI_CSS_PATH.'layui.css', CSS_PATH.'admin_index.css', ), 'js_files' =>array( JQUERY_PATH.'jquery-3.3.1.min.js', LAYUI_JS_PATH.'layui.js', ), … ); //加载视图 require ADMIN_VIEW_PATH.'v_index.php'; 接着,编写视图文件admin\view\v_index.php,代码如下。 <?php defined('APP_NAME') or exit('非法访问');?> <?php include ADMIN_VIEW_PATH.'header.php';?> <div class="layui-fluid"> <div class="layui-row layui-bg-cyan header"> <?php include ADMIN_VIEW_PATH.'top.php';?> </div> <div class="layui-row" style="border: 1px solid #2F4056;"> <div class="layui-col-md3 side"> <?php include ADMIN_VIEW_PATH.'side.php';?> </div> <div class="layui-col-md9 content"> <h3>系统后台首页</h3> </div> </div> <div class="layui-row layui-bg-cyan footer"> <?php include ADMIN_VIEW_PATH.'bottom.php';?> </div> </div> <?php include ADMIN_VIEW_PATH.'footer.php';?> <script> $(document).ready(function() { layui.use('element', function(){ var element = layui.element; }); }); </script> 视图由公共部分和特别部分组成,公共部分文件也是存放在admin\view目录中,各部分代码详见源码。 4. 后台封面设计 为系统后台设计一个封面页面,用于承载系统介绍、使用说明、用户登录,以及广告信息等内容,如图5.11所示。 在系统admin目录下新建welcome.php文件,代码如下。 <?php defined('APP_NAME') or exit('非法访问'); /** * 系统后台欢迎页面 * admin\welcome.php */ //视图数据 $data = array( 'title'=>'后台管理系统', 'css_files' =>array( LAYUI_CSS_PATH.'layui.css', CSS_PATH.'admin_welcome.css', ), 'js_files' =>array( JQUERY_PATH.'jquery-3.3.1.min.js', LAYUI_JS_PATH.'layui.js', ), 'content' => array( 'title' => '微梦后台管理系统', 'author' => '开发者: 马石安 魏文平', 'time' => '2020 年 1 月' ), ); //加载视图 require ADMIN_VIEW_PATH.'v_welcome.php'; 在admin/view目录中,新建视图文件v_welcome.php。该视图文件非常简单,请参考项目源码。 视频讲解 5.3.2登录与登出 用户的登录与登出,是任何Web项目都必须具有的功能。用户登录功能实现时,重点注意用户输入数据的验证。 1. 登录表单设计 1) 创建页面 在系统后台模块中,添加管理员登录视图文件admin\view\v_login.php,页面效果如图5.13所示。 图5.13后台用户登录表单 系统后台管理员登录页面,通过单击图5.11页面中的“用户登录”超级链接来实现。加载该页面的PHP文件为admin\login.php,其代码与系统后台模块中的其他PHP文件相似,请参见源码。 在如图5.13所示的页面中有一个图形验证码,用于加强用户登录验证。下面实现验证码图片的显示,以及单击验证码图片更新验证码的功能。 2) 生成验证码 在项目根目录下的common\lib子目录中添加captcha.php文件,用于存放生成图形验证码、输出图形验证码、检验验证码是否正确的函数,代码如下。 <?php /** * 生成验证码 * @param int $count 验证码长度 * @return string */ function create_captcha($count=5) { $code = ''; $charset = 'ABCDEFGHJKLMNPQRSTUVWXY23456789'; $len = strlen($charset) - 1; for ($i = 0; $i < $count; $i++) { $code .= $charset[mt_rand(0, $len)]; } return $code; } /** * 显示图形验证码 * @param string $code */ function captcha_img($code) { $width = 120;//验证码图片宽度 $height = 35; //验证码图片高度 $img = imagecreate($width, $height); //创建验证码图像 //设置验证码图像的背景颜色 imagecolorallocate($img, mt_rand(50,255), mt_rand(0,155), mt_rand(0,155)); $fontSize = 18; //验证码文字大小 $fontColor = imagecolorallocate($img, 255, 255, 255); //验证码文字颜色 $fontStyle = CAPTCHA_FONT_PATH.'font.TTF'; //验证码文字样式 $len = strlen($code); //生成指定长度的验证码 for($i=0; $i<$len; ++$i){ imagettftext( $img, $fontSize, mt_rand(0,20) - mt_rand(0,25),//设置验证码文字倾斜角度 //随机设置验证码文字显示坐标 $fontSize * $i + 12, mt_rand($height/2, $height), $fontColor, $fontStyle, $code[$i] ); } //为验证码图片生成彩色噪点 for($i=0; $i<200; ++$i){ //随机生成颜色 $color = imagecolorallocate($img,mt_rand(0,255),mt_rand(0,255),mt_rand(0,255)); //随机绘制干扰点 imagesetpixel($img,mt_rand(0,$width),mt_rand(0,$height),$color); } //绘制10条干扰线 for($i=0; $i<5; ++$i){ //随机生成干扰线颜色 $color = imagecolorallocate($img,mt_rand(0,255),mt_rand(0,255),mt_rand(0,255)); //随机绘制干扰线imageline($img,mt_rand(0,$width),0,mt_rand(0,$width),$height,$color); } header('Content-Type: image/png'); imagepng($img); //输出图像 imagedestroy($img); //释放内存 } /** * 检查验证码是否正确 * @param string $captcha * @return boolean */ function captcha_check($captcha) { if ($captcha == $_SESSION['wmcms']['captcha']) { return true; } return false; } 验证码需要以某种样式显示,所以需要扩展名为“.ttf”的字体样式文件。该文件可以在操作系统的字体库中复制。这里将其存放在项目common\captcha子目录中。 上述代码生成了图形验证码,下面将其在用户登录页面中显示出来。在项目的admin目录下,新建一个名为captcha.php文件,代码如下。 <?php /** * 生成图形验证码并输出 * @author weiwenping */ //加载验证码函数文件 require DOC_LIB.'captcha.php'; //生成验证码 $code = create_captcha(); //输出验证码图像 captcha_img($code); //将验证码保存到SESSION中 $_SESSION['wmcms']['captcha'] = $code; 最后,修改登录表单中的验证码图片的HTML元素属性,代码如下。 <div class="layui-form-item"> <label for="captcha" class="layui-form-label">验证码</label> <div class="layui-input-inline"> <input type="text" name="captcha" id="captcha" class="layui-input"> </div> <img src="captcha " id="captchaImg" /> </div> 3) 验证码更新 在用户输入登录数据时,页面上的验证码有时会看不清楚,这时要让用户单击验证码图片来进行重置。这个功能可以用jQuery轻松实现,代码如下。 //单击图形验证码进行重置 $('#captchaImg').click(function(event) { $(this).attr('src', 'captcha?rand='+Math.random()); }); 代码中的“captchaImg”是显示验证码图片的img标签ID。 2. 测试数据准备 为了测试用户登录功能,需要在数据库中添加一些测试数据。登录MySQL数据库服务器,在项目数据库wmchapt05db的wm_admin数据表中插入测试数据。例如,用户名admin,用户密码md5('123456')等。 3. 数据验证 表单数据的验证分为前端验证与后端验证。前端验证就是在页面上通过JavaScript代码进行验证,而后端验证是通过PHP与数据库的交互来对用户输入数据进行检验。 1) 前端验证 新建public\static\js\admin_login.js文件,并在文件中添加onlogin()函数,用于处理表单提交,代码如下。 //处理登录表单提交 function onlogin() { //获取表单数据 var username = $.trim($('#username').val()); var password = $.trim($('#password').val()); var captcha = $.trim($('#captcha').val()); //检查输入框是否为空 if (username == '') { layer.alert('请输入用户名!', {'icon': 2 }); return; } if (password == '') { layer.alert('请输入密码!', { 'icon': 2 }); return; } if (captcha == '') { layer.alert('请输入验证码!', { 'icon': 2 }); return; } //提交表单数据 $.post( $('form').first().attr('action'), { 'username': username, 'password': password, 'captcha': captcha }, function(res) { if (res.code > 0) { //重置验证码 $('#captcha').val(''); reloadImg(); //错误信息提示 layer.alert(res.msg, { icon: 2 }); } else { //登录成功信息提示 layer.msg(res.msg); //1秒后跳转到后台主页 setTimeout(function() { window.location.href = 'index' }, 1000); } }, 'json'); } 这里只简单地验证表单数据是否为空。其他验证,如用户名长度不能少于3位,密码长度不能少于6位等,请自行实现。页面效果如图5.14所示。 图5.14表单前端验证 图5.14是用户直接单击“登录”按钮后的效果。用户单击“登录”按钮后,页面中的jQuery代码会调用上述的onlogin()函数,代码如下。 //用户单击“登录”按钮,提交数据登录 $('#submit').click(function(event) { //处理表单提交 onlogin(); }); 注意: 由于表单的提交按钮“登录”位于form标签内,需要阻止该按钮的默认表单提交事件发生。 2) 后端验证 在前端的验证中,只是验证了用户输入的验证码是否为空,并没有判断它的正确性。下面在后端编写代码,检查用户输入的验证码是否正确。 在系统后台模块中添加admin\loginExc.php文件,并编写代码。 <?php /** * 微梦后台管理系统 * 管理员登录处理 * @author weiwenping */ //加载验证码函数文件 require_once DOC_LIB.'captcha.php'; //接收表单数据 $username = trim($_POST['username']); $password = trim($_POST['password']); $captcha = trim($_POST['captcha']); //验证输入是否为空 if ($username == '') { exit(json_encode(array('code'=>1,'msg'=>'用户名不能为空!'))); } if ($password == '') { exit(json_encode(array('code'=>1,'msg'=>'密码不能为空!'))); } if ($captcha == '') { exit(json_encode(array('code'=>1,'msg'=>'验证码不能为空!'))); } //验证验证码 if (!captcha_check(strtoupper($captcha))) { exit(json_encode(array('code'=>1,'msg'=>'验证码错误!'))); } 页面效果如图5.15所示。 图5.15验证码后端验证 后端验证码检查完毕后,接着进行用户输入数据的后端验证,也就是与数据库中的数据进行比对。 在admin\loginExc.php文件中添加代码,完成数据库验证,代码如下。 //数据库验证,用户验证 $sql = 'select * from wm_admin where username = ?'; $admin = db_fetch(DB_ROW, $sql, 's', array('username'=> htmlentities($username))); //用户验证 if (!$admin) { exit(json_encode(array('code'=>1,'msg'=>'该用户不存在!'))); } //验证密码 if (md5($admin['username'].$password) != $admin['password']) { exit(json_encode(array('code'=>1,'msg'=>'密码错误!'))); } //账号是否被禁用 if ($admin['status'] == 1) { exit(json_encode(array('code'=>1,'msg'=>'该用户已被禁用!'))); } //设置SESSION $_SESSION['wmcms']['admin'] = $admin; //登录成功返回信息 exit(json_encode(array('code'=>0,'msg'=>'恭喜,登录成功!'))); 测试效果如图5.16所示。 图5.16用户登录数据库验证 图中展示的是“用户名”输入错误时的返回信息。注意,这里表单提交采用的是AJAX请求方式,详细代码请参见源码。 4. 管理员退出系统 管理员退出系统功能的实现非常简单,只需要删除SESSION中的管理员数据即可。 首先,在页面中添加代码,监听用户是否单击了“退出系统”按钮,代码如下。 //退出系统处理 $('#logout').click(function(event) { var url = $(this).attr(‘href’); layer.confirm('您确定要退出吗?', { btn: ['确定', '取消'] , icon: 3, title: '温馨提示' }, function(index, layero){ onlogout(url); }); }); 上述代码中的“logout”是“退出系统”按钮标签的ID,当用户单击提示框中的“确定”按钮时,调用onlogout()函数完成用户退出功能。onlogout()函数代码如下。 function onlogout(url) { $.post(url, {}, function(res) { if (res.code > 0) { layer.alert(res.msg, { icon: 2 }); } else { layer.msg(res.msg); setTimeout(function() { window.location.href = 'index'; }, 1000); } }, 'json'); } 从上述代码可以看出,用户退出系统的处理逻辑是在admin\logout.php文件中实现的。该文件代码如下。 <?php /** * 管理员退出系统处理 * @author weiwenping */ //退出系统 if (isset($_SESSION['wmcms']['admin'])) { unset($_SESSION['wmcms']['admin']); } //返回提示信息 exit(json_encode(array('code'=>0,'msg'=>'您已退出后台管理系统!'))); 从上述代码可以看出,用户退出系统时,直接删除SESSION中的用户数据即可。用户退出系统后,不能再访问系统后台内页,需要对用户权限进行控制。 在自定义函数库common\lib\function.php中,新建函数privilege(),代码如下。 //用户权限控制 function privilege() { $res = false; //用户是否登录 $res = isset($_SESSION['wmcms']['user']) ? true : false; return $res; } 在系统后台主页admin\index.php中添加代码,进行用户访问控制,代码如下。 //判断用户是否有权限访问 if (!privilege()) { header('Location: admin/welcome'); exit; } 如果用户没有访问权限,跳转到系统后台欢迎页面。 视频讲解 5.3.3用户信息管理 系统用户分为系统管理员和普通用户,系统管理员可以登录到系统后台,而普通用户只能使用系统前台功能。 用户信息管理,包括用户信息列表显示、用户的添加/编辑和删除、用户权限管理等。下面以管理员用户信息管理为例来进行介绍。 1. 信息显示 要对系统用户进行管理,首先必须将所有的用户信息在页面中显示出来,然后再针对不同的用户账号进行相应的操作。用户信息列表如图5.5所示。 页面中显示的管理员信息来自数据表wm_admin和wm_admin_groups。数据表wm_admin_groups中存储系统管理员的分组,不同组管理员具有不同的操作权限。 在系统后台模块中添加admin\user_list.php文件,在文件中编写代码从数据库获取数据,代码如下。 <?php … //从数据库中读取全部管理员信息 $sql = 'select * from wm_admin'; $user_lists = db_fetch(DB_ALL, $sql); //将管理员的GID转换成名称 $sql = 'select * from wm_admin_groups'; $roles = db_fetch(DB_ALL, $sql); foreach ($user_lists as $key => $v) { foreach ($roles as $vr) { if ($v['gid'] == $vr['gid']) { $user_lists[$key]['role'] = $vr['title']; } } } … 管理员数据表wm_admin中的分组gid记录的是数据表wm_admin_group中的序号gid,它是一个整型数据,所以必须将其替换成相应的名称,如系统管理员、开发人员、文章编辑等。 最后,编写视图文件admin\view\v_user_list.php代码。其中数据循环输出代码如下。 <?php foreach ($data['user_lists'] as $v): ?> <tr> <td><?php echo $v['id']?></td> <td><?php echo $v['username']?></td> <td><?php echo $v['truename']?></td> <td><?php echo $v['role']?></td> <td><?php echo $v['status'] ? '<span style="color:red">禁用<span>' : '正常'; ?></td> <td><?php echo date('Y-m-d H:i:s',$v['add_time'])?></td> <td> <button class="layui-btn layui-btn-xs" onclick="edit()">编辑</button> <button class="layui-btn layui-btn-danger layui-btn-xs" onclick="del()">删除</button> </td> </tr> <?php endforeach;?> 完整代码请参见源码。 2. 添加管理员 管理员的添加功能,通过单击如图5.5所示页面中的“添加”按钮来实现。表单页面如图5.17所示。 图5.17添加管理员表单 该表单页面文件为admin\view\v_admin_add.php,视图通过Layui的弹窗来渲染。在文件admin\view\v_user_list.php中添加JS代码。 //处理添加事件 $('#add').click(function(event) { add(); }); /** * 加载管理员添加表单页面 */ function add() { layer.open({ type: 2, title: '添加管理员', shade: 0.3, area: ['480px', '420px'], content: 'admin_add?rand='+Math.random(), }); } 编写上述表单页面的PHP文件admin\admin_add.php代码。 <?php … //从数据库中读取管理员分组信息 $sql = 'select * from tb_admin_groups'; $data['role'] = db_fetch(DB_ALL, $sql); … //加载视图 require ADMIN_VIEW_PATH.'v_admin_add.php'; 处理表单提交,在admin\view\v_admin_add.php文件中添加JS代码,如下所示。 //使用户名输入框获得输入焦点 $('input[name="username"]').focus(); //处理表单提交 $('#submit').click(function(event) { add_submit($('form').first().attr('action')); }); function add_submit(action) { var username = $.trim($('input[name="username"]').val()); var password = $.trim($('input[name="password"]').val()); var gid = $.trim($('select[name="gid"]').val()); var truename = $.trim($('input[name="truename"]').val()); if (username == '') { layer.alert('请输入用户名', { icon: 2 }); return; } if (gid == '0') { layer.alert('请选择角色', { icon: 2 }); return; } if (password == '') { layer.alert('请输入密码', { icon: 2 }); return; } if (truename == '') { layer.alert('请输入真实姓名', { icon: 2 }); return; } $.post(action, $('form').serialize(), function(res) { if (res.code > 0) { layer.alert(res.msg, { icon: 2 }); } else { layer.msg(res.msg); setTimeout(function() { parent.window.location.reload(); }, 1000); } }, 'json'); } 编写表单提交PHP处理文件admin\insertExc.php,代码如下。 <?php … //获取表单数据 $data['username'] = trim(htmlspecialchars($_POST['username'])); $password = trim(htmlspecialchars($_POST['password'])); $data['truename'] = trim(htmlspecialchars($_POST['truename'])); $data['gid'] = (int)trim(htmlspecialchars($_POST['gid'])); $data['status'] = isset($_POST['status']) ? (int)trim(htmlspecialchars($_POST['status'])) : 0; $data['add_time'] = time(); //数据非空验证 if (!$data['username']) { exit(json_encode(array('code'=>1,'msg'=>'用户名不能为空!'))); } if (!$password) { exit(json_encode(array('code'=>1,'msg'=>'密码不能为空!'))); } if (!$data['truename']) { exit(json_encode(array('code'=>1,'msg'=>'真实姓名不能为空!'))); } if (!$data['gid']) { exit(json_encode(array('code'=>1,'msg'=>'角色不能为空!'))); } //检查用户名是否已被注册 $sql = 'select username from wm_admin where username = ?'; $itme = db_fetch(DB_ROW, $sql,'s',$data['username']); if ($itme) { exit(json_encode(array('code'=>1,'msg'=>'用户名已经被注册!')));; } //密码加密 $data['password'] = md5($data['username'].$password); //完成数据插入 $sql = "INSERT INTO wm_admin (username, truename, gid, status, add_time, password) VALUES (?,?,?,?,?,?)"; $id = db_exec(DB_LASTED, $sql, 'ssisis', array_values($data)); if ($id) { exit(json_encode(array('code'=>0,'msg'=>'管理员添加成功!'))); }else{ exit(json_encode(array('code'=>1,'msg'=>'管理员添加失败!'))); } 管理员添加页面效果,如图5.18所示。 图5.18管理员添加页面效果 从图中输出结果可以看出,新管理员被成功插入数据表wm_admin中。这里采用了AJAX和Layui的弹窗来共同实现管理员的添加功能,以获得最佳的用户体验。 3. 编辑管理员 管理员的编辑功能,通过单击如图5.5所示页面中的“编辑”按钮来实现。表单页面如图5.19所示。 图5.19管理员编辑表单 该表单页面其实就是图5.17中管理员的添加页面,只是在窗口弹出时,在表单元素中显示了需要编辑的某个管理员的信息。 单击图5.19页面中的“编辑”按钮,触发按钮单击事件,调用edit()函数实现编辑窗口的显示以及数据的初始化。在文件admin\view\v_user_list.php中,给“编辑”按钮绑定事件,代码如下。 <button class="layui-btn layui-btn-xs" onclick="edit(<?php echo $v['id']?>)">编辑</button> 在admin/js/admin_lists.php文件中,新建edit()函数,代码如下。 function edit(id) { layer.open({ type: 2, title: '编辑管理员信息', shade: 0.3, area: ['480px', '420px'], content: 'admin_add?id=' + id, }); } 修改管理员添加功能模块的PHP文件admin\admin_add.php,在加载视图之前获取需要编辑的管理员信息,代码如下。 //获取需要编辑的管理员数据 if (isset($_GET['id']) && (int)$_GET['id'] > 0) { //获取需要编辑的管理员信息 $sql = 'select * from wm_admin where id = ?'; $admin = db_fetch(DB_ROW, $sql, 'i', [(int)$_GET['id']]); } 修改管理员添加功能模块的视图文件admin\view\v_admin_add.php,使其适合添加、编辑两种情况。详细代码请参见源码。 修改表单提交文件insertExc.php,使其适合添加、编辑两种情况。完整代码如下。 <?php … //获取表单数据 $id = isset($_POST['id']) ? (int)trim(htmlspecialchars($_POST['id'])) : 0; $data['username'] = trim(htmlspecialchars($_POST['username'])); $password = trim(htmlspecialchars($_POST['password'])); $data['truename'] = trim(htmlspecialchars($_POST['truename'])); $data['gid'] = (int)trim(htmlspecialchars($_POST['gid'])); $data['status'] = isset($_POST['status']) ? (int)trim(htmlspecialchars($_POST['status'])) : 0; $data['add_time'] = time(); //数据非空验证 if (!$data['username']) { exit(json_encode(array('code'=>1,'msg'=>'用户名不能为空!'))); } //添加管理员时判断 if ($id==0 && !$password) { exit(json_encode(array('code'=>1,'msg'=>'密码不能为空!'))); } //编辑时,若用户没有修改密码,则使用原密码 if ($id > 0) { if (!$password){ $data['password'] = $_POST['password1']; }else{ //密码加密 $data['password'] = md5($data['username'].$password); } }else{ //密码加密 $data['password'] = md5($data['username'].$password); } if (!$data['truename']) { exit(json_encode(array('code'=>1,'msg'=>'真实姓名不能为空!'))); } if (!$data['gid']) { exit(json_encode(array('code'=>1,'msg'=>'角色不能为空!'))); } //执行添加或编辑操作 if ($id > 0) { //完成信息编辑 $sql = "update wm_admin set truename = ?, gid = ?, status = ?, password =? where id = ?"; $eid = db_exec(DB_AFFECTED, $sql, 'siisi', [$data['truename'],$data['gid'],$data['status'],$data['password'],$id]); if ($eid) { exit(json_encode(array('code'=>0,'msg'=>'管理员编辑成功!'))); }else{ exit(json_encode(array('code'=>1,'msg'=>'管理员编辑失败!'))); } }else{ //检查用户名是否已被注册 $sql = 'select username from wm_admin where username = ?'; $itme = db_fetch(DB_ROW, $sql,'s',$data['username']); if ($itme) { exit(json_encode(array('code'=>1,'msg'=>'用户名已经被注册!')));; } //完成数据插入 $sql = "INSERT INTO wm_admin (username, truename, gid, status, add_time, password) VALUES (?,?,?,?,?,?)"; $nid = db_exec(DB_LASTED, $sql, 'ssisis', array_values($data)); if ($nid) { exit(json_encode(array('code'=>0,'msg'=>'管理员添加成功!'))); }else{ exit(json_encode(array('code'=>1,'msg'=>'管理员添加失败!'))); } } 注意: 编辑时表单中的“用户名”元素是只读的,也就是不允许修改管理员的用户名。编辑时,若密码框为空,则默认为用户不修改密码。 运行效果如图5.20所示。 图5.20管理员编辑页面效果 从图中可以看出,第6条记录中的“角色”与“状态”数据已被成功修改。 4. 删除管理员 删除管理员功能的实现非常简单,只需要给管理员列表页面中的“删除”按钮绑定一个单击函数del(),并在admin\deleteExc.php文件中将数据从数据表中删除即可。 页面中的JS函数del()代码如下。 function del(id) { layer.confirm( '确定要删除吗?', { btn: ['确定', '取消'], icon: 3 }, function() { $.post( './deleteExc', { 'id': id }, function(res) { if (res.code > 0) { layer.alert(res.msg, { icon: 2 }); } else { layer.msg(res.msg); setTimeout(function() { window.location.reload(); }, 1000); } }, 'json'); }); } 删除之前需要再次询问用户是否确定删除,这里用Layui的“确认”框来实现,如图5.21所示。 图5.21管理员删除确认 实现数据删除的文件为admin\deleteExc.php,代码如下。 <?php … //获取表单数据 $id = isset($_POST['id']) ? (int)trim(htmlspecialchars($_POST['id'])) : 0; if ($id > 0) { $sql = 'delete from wm_admin where id = ?'; $did = db_exec(DB_AFFECTED, $sql, 'i', [$id]); if ($did) { exit(json_encode(array('code'=>0,'msg'=>'删除成功!'))); } else { exit(json_encode(array('code'=>1,'msg'=>'删除失败!'))); } } exit(json_encode(array('code'=>1,'msg'=>'删除失败!'))); 由于篇幅的限制,用户信息管理模块功能就介绍这些,请读者依照本节方法完善该模块的其他功能。例如,信息显示时的翻页、用户头像的上传等。 视频讲解 5.3.4内容管理 系统后台的内容管理与前述的用户管理相似,主要实现内容的添加、修改和删除等功能。 1. 内容显示 文章内容的列表在系统后台的主页上显示,如图5.4所示。该功能的实现非常简单,只需要在admin\index.php文件中从数据表wm_article中获取到全部文章即可,代码如下。 //获取全部文章 $sql = 'select id,title,create_time from wm_article'; $articles = db_fetch(DB_ALL, $sql); 在视图文件admin\view\v_index.php中循环输出这样文章的ID、标题和添加时间,代码如下。 <?php foreach ($data['articles'] as $k=>$v): ?> <tr> <td><?php echo $k+1;?></td> <td><?php echo $v['title']?></td> <td><?php echo date('Y-m-d H:i:s',$v['create_time'])?></td> <td> <button class="layui-btn layui-btn-xs" onclick="edit(<?php echo $v['id']?>)"> 编辑</button> <button class="layui-btn layui-btn-danger layui-btn-xs" onclick= "del(<?php echo $v['id']?>)">删除</button> </td> </tr> <?php endforeach;?> 完整代码请参见源码。 2. 内容添加 单击后台页面侧边栏中的“添加文章”菜单,或者单击页面右侧的“添加”按钮,即可打开文章添加页面,如图5.22所示。 图5.22添加文章表单 页面中的文章类型数据来自数据库中的wm_article_category数据表。选择框展开后的效果如图5.23所示。 图5.23文章类型选择 添加文章表单页面设计完成后,就可以编写代码完成数据的插入了。实现该功能的代码与上述添加管理员代码相同,只是将操作的数据表更改为wm_article即可。这里不再赘述。 视频讲解 5.4前台功能实现 PHP Web应用项目的前台一般用于展示系统信息,因此,主要使用的是数据库的查询。本节实现案例项目前台的部分功能,包括首页、详情,以及分类查询等。 5.4.1前台首页 系统前台首页用于概要性地展示系统发布的信息,页面效果如图5.1所示。 1. 主菜单 系统前台首页顶部的导航菜单,与5.3.1节中的侧边栏导航菜单一样,其数据也是来自数据库中的wm_menus表。因此,获取菜单数据的方式也与前述相同,只是这里获取的是home模块中位置为top的菜单项,代码如下。 //获取菜单 $top_navs = getMenus('home','top'); foreach ($top_navs as $k => $v) { $data['top_navs'][$k] = $v; $data['top_navs'][$k]['sub'] = getSubMenus($top_navs, $v['id']); } 菜单效果如图5.24所示。 图5.24前台主菜单 菜单视图采用Layui的水平菜单,请参见源码。 2. 全部文章 在系统前台主页的左侧,显示了系统中的全部文章概要,包括图标、标题、作者、发布日期,以及内容缩略。 系统文章数据存放在数据库中的wm_article数据表中,将其取出显示即可,代码如下。 //获取全部文章 $sql = 'select * from wm_article as a join wm_user as u where a.user_id = u.id'; $articles = db_fetch(DB_ALL, $sql); 注意: 这里使用了数据表的联合查询,因为需要从wm_user表中读取作者的姓名。在wm_article表中,只记录了作者的ID,也就是wm_user表中的id字段的值。 3. 热门浏览 在系统前台主页的右侧,显示了最近的热门文章概要,包括文章标题和浏览次数。热门文章是从上面获取到的全部文章中筛选出来的,代码如下。 //获取全部文章 $sql = 'select * from wm_article as a join wm_user as u where a.user_id = u.id'; $articles = db_fetch(DB_ALL, $sql); //获取热门文章 $hot_articles = array(); foreach ($articles as $a){ if ($a['is_hot'] == 1) { array_push($hot_articles, $a); } } 热门文章在数据表中存储时,其is_hot字段的值为1。 5.4.2内容详情 单击主页中显示的文章标题,即可查看该篇文章的详情,如图5.2所示。 1. 获取数据 根据文章标题链接传递过来的文章ID,从数据表wm_article中查询该篇文章的详细内容,代码如下。 //获取文章ID $article_id = isset($_GET['id']) ? (int)$_GET['id'] : null; if ($article_id === null) { header('Location: /'); exit; } //获取该篇文章 $sql = 'select * from wm_article where id = '.$article_id; $article = db_fetch(DB_ALL, $sql); //获取作者姓名 $sql = 'select name from wm_user where id = '.$article[0]['user_id']; $user = db_fetch(DB_ALL, $sql); $article[0]['uname']= $user[0]['name']; //获取热门文章 $sql = 'select * from wm_article where is_hot = 1'; $hot_articles = db_fetch(DB_ALL, $sql); 与主页一样,在文章详情页面的右侧也显示了最近的热门文章,所以这里也要再次获取到这些文章的标题及浏览次数。 2. 显示详情 在视图中显示文章详情,代码如下。 <div class="layui-col-md8"> <div class="layui-card main-title" > <div class="layui-card-header">文章详情</div> </div> <div class="layui-row" style="height:130px;border-bottom: 1px solid #eee;"> <h2 style="color:#009688"><?=$data['article']['title']?></h2> <p style="padding-top:5px;line-height: 25px;color:#aaa;"> <span style="padding-right: 20px;">作者: <?=$data['article']['uname']?></span> <span>发布时间: <?=date('Y-m-d',$data['article']['create_time'])?></span></p> <p style="border-top: 1px dashed #eee;padding-top: 8px; "> <?php echo htmlspecialchars($data['article']['content']); ?></p> </div> </div> 注意: 在文章详情页面,单击右侧的热门文章标题,也可以在页面左侧显示该文章详情。实现代码参见源码。 5.4.3分类查询 本项目中文章的分类查询通过主菜单来实现。也就是说,系统前台主菜单中的PHP、JAVA、CSS等实际上是文章的分类名称。 例如,单击PHP菜单,则会查询出所有类型为PHP的文章,如图5.25所示。 图5.25分类查询 注意: 主页中原来的“全部文章”文本,更改为“php”,说明查询到的是“php”分类的文章。 查询代码如下。 //获取分类名称 $article_category = isset($_GET['cate_name']) ? htmlentities(trim($_GET['cate_name'])): null; if ($article_category === null) { header('Location: /'); exit; } $sql = "select id from wm_article_category where name = '".$article_category."'"; $category_id = db_fetch(DB_ALL, $sql); //获取分类文章 $sql = 'select a.id as aid,a.title,u.name,a.create_time,a.content,a.title_img,a.is_hot,a.pv from wm_article as a join wm_user as u where a.user_id = u.id and a.cate_id = '.$category_id[0]['id']; $articles = db_fetch(DB_ALL, $sql); //获取热门文章 $sql = 'select * from wm_article where is_hot = 1'; $hot_articles = db_fetch(DB_ALL, $sql); 注意: 分类名称由菜单的href属性传递,代码如下。 <li class="layui-nav-item"><a href="<?php echo $m['href'].'?cate_name='.strtolower($m['name'])?>"><?=$m['name']?></a></li> 详细代码请参见源码。 5.4.4文章搜索 文章的搜索通过主菜单右侧的搜索表单来实现,这里搜索的是文章标题中的关键字,采用模糊查询方式。运行效果如图5.26所示。 图5.26文章搜索 数据查询代码如下。 //获取文章标题中的关键字 $keyword = isset($_POST['keyword']) ? htmlentities(trim($_POST['keyword'])): null; if ($keyword === null) { header('Location: /'); exit; } //获取查询到的全部文章 $sql = "select a.id as aid,a.title,u.name,a.create_time,a.content,a.title_img,a.is_hot,a.pv from wm_article as a join wm_user as u where a.user_id = u.id and a.title like '%".$keyword."%'"; $articles = db_fetch(DB_ALL, $sql); 页面头部右侧的搜索框视图代码存放在home\view\top_search.php文件中,代码如下。 <?php defined('APP_NAME') or exit('非法访问');?> <form class="layui-form" action="/index.php/home/search" method="post"> <div class="layui-inline" style="padding:10px;"> <div class="layui-input-inline"> <input type="text" name="keyword" required lay-verify="required" placeholder="请输关键字" autocomplete="off" class="layui-input"> </div> <div class="layui-inline"> <div class="layui-input-inline"> <input type="submit" value="搜索" class="layui-btn layui-btn-primary" /> </div> </div> </div> </form> 5.5本 章 小 结 本章详细介绍了PHP语言面向过程的编程方法,以及开发一个简单的内容管理系统的过程。由于篇幅的限制,这里重点讲述了系统前/后台一些基本功能的实现。关于系统中的一些其他功能,或者是读者觉得案例中不是很满意的功能的实现,留给读者作为本章学习的课后作业。希望读者充分发挥自己的想象力与创造力,使本章案例项目变得更加完美。