php thinkphp3 开发新闻网站+后台管理系统

一:需求分析

ThinkPHP(3.2.3完整版)了解:mvc开发框架.

1.主目录结构:

index.php访问入口配置文件

Application应用目录里面放的是每个模块文件。

Public资源文件目录,里面存放的是css,js,image等静态文件

ThinkPHP里面是框架的核心内容

php thinkphp3 开发新闻网站+后台管理系统_第1张图片


2:ThinkPHP目录

php thinkphp3 开发新闻网站+后台管理系统_第2张图片

Common存放的函数,在任何地方都可以直接使用,所以是公共函数目录

Conf里面是核心配置目录

thinkphp.php是框架入口文件,其它目录就不再深入了解了。

结合Thinkphp文档学习。

3.框架的运行原理

首先运行项目时会先到index.php入口配置文件.

php thinkphp3 开发新闻网站+后台管理系统_第3张图片

进入入口文件首先 require './ThinkPHP/ThinkPHP.php'; 这样就会加载Thinkphp目录下的核心内容功能。

第一次执行这个项目后Application目录(一开始里面没内容)下会自动生成这三个目录。Common(公用目录),Home目录是模块目录。应用模块下的目录Common公共函数模块,Conf配置模块,Controller(实现业务模块)控制器模块,Model模型模块,View视图模块。

数据库:(需要索引的字段要创建索引)

cms_admin(后台用户表):admin_id(主键),username(创建索引),password,lastloginip,lastlogintime,email,realname,status;

cms_menu(菜单表):menu_id(主键),name,parentid(创建索引),m,c,f,listorder(创建索引),status,type.

cms_news(文章表主表):news_id.........等

cms_news_content(文章详情表):id,......等----主要存放文章主表的文章内容。

cms_position(推荐位表):id,name,status,descripation,createtime,update_time等

cms_postion_content(推荐位详情表):id,postion_id,title,thumb,url,news_id,listorder,status...等----主要存放推荐位里面存放的文章内容。

根据自己的需要设计文章内容。


后台管理系统

在Application下创建目录Admin:


首先创建后台登录url:localhost/thinkphp/index.php?m=admin&c=login&f=index

php thinkphp3 开发新闻网站+后台管理系统_第4张图片

提交按钮的表单内容:




   






上面要记得引入这些js文件才能实现对应的逻辑。__PUBLIC__指的是public目录。

dialog.js的内容为:

var dialog = {
    // 错误弹出层
    error: function(message) {
        layer.open({
            content:message,
            icon:2,
            title : '错误提示',
        });
    },


    //成功弹出层
    success : function(message,url) {
        layer.open({
            content : message,
            icon : 1,
            yes : function(){
                location.href=url;
            },
        });
    },


    // 确认弹出层
    confirm : function(message, url) {
        layer.open({
            content : message,
            icon:3,
            btn : ['是','否'],
            yes : function(){
                location.href=url;
            },
        });
    },


    //无需跳转到指定页面的确认弹出层
    toconfirm : function(message) {
        layer.open({
            content : message,
            icon:3,
            btn : ['确定'],
        });
    },
}



login.js的内容为

/**
 * 前端登录业务类
 * @author singwa
 */
var login = {   //声明login类 ,方法check:function(){....}
    check : function() {
        // 获取登录页面中的用户名 和 密码
        var username = $('input[name="username"]').val();
        var password = $('input[name="password"]').val();


        if(!username) {

            dialog.error('用户名不能为空');   //弹出窗口,一般我们使用alter,这里对弹出做了美化.使用Layer(网)layer.layui.cpm

        }
        if(!password) {
            dialog.error('密码不能为空');  //同上。dialog.js
        }


        var url = "/thinkphp/admin.php?&c=login&a=check"; //请求地址是m=admin,c=login,a=check
        var data = {'username':username,'password':password};//请求的数据内容
        // 执行异步请求  $.post
        $.post(url,data,function(result){    /jquery的方法,post异步请求,请求后收到服务器的返回结果result.
            if(result.status == 0) {//判断返回状态
                return dialog.error(result.message);//弹出错误信息
            }
            if(result.status == 1) {
                return dialog.success(result.message, '/thinkphp/admin.php?');//跳转到后台m=admin,c=index,f=index.
            }


        },'JSON');//JSON数据格式发送。


    }
}

在Controller创建控制器LoginController.class.php文件内容为:

namespace Admin\Controller;  //声明类的命名空间通过路径加载类
use Think\Controller;     //控制器需要继承的父类引入
class LoginController extends Controller {
 
    public function index(){   //引入方法名index
       if(session('adminUser')){//检查session 判断用户是否已经登陆了,如果未登录回到登录页面。如果登录跳转到后台页面

           $this->redirect('/thinkphp/admin.php?c=index');

         //这里也可以写/thinkphp/index.php?m=admin&c=index&a=index

       }
       $this ->display();//如果已经登录跳转到View目录下的Login目录下的index.html
            // admin.php?c=index
    }
    public function check(){//点击登录页面后将数据提交到这个方法里,ajax,异步加载发送过来的数据.
        $username=$_POST['username'];
        $password=$_POST['password'];
        if(!trim($username)){
          return show(0,'用户名不能为空');//由于要返回一个result到前台页面,下面的逻辑是一样的,判断发送的数据是否合法。并且返回状态码 ,0相当result.status  用户不能为空相当于result,message.
            
        }
        if(!trim($password)){
           return show(0,'密码不能为空');
        }
        $ret=D('Admin')->getAdminByUsername($username);//用户表模型查找
        if(!$ret){
           return show(0,'该用户不存在');

        }

       //getMd5Password是Commont公共函数写的MD5加密函数。

        if($ret['password']!=getMd5Password($password)){
            return show(0,'密码错误');

        }

      //登录后更新登录时间

        D('Admin')->updateByAdminId($ret['admin_id'],array('lastlogintime'=>time()));
        session('adminUser',$ret);
        return show(1,'登录成功');
    }
    public function loginout(){
         session('adminUser', null);
        $this->redirect('/thinkphp/admin.php?c=login');
    }

}

show函数的编写  (在公共模块下编写)

function show($status,$message,$data=array()){  //传入状态 信息 数组默认空数组
    $result=array(   //result数组对应信息编写。
        'status'=>$status,
        'message'=>$message,
        'data'=>$data,
    );
    exit(json_encode($result));//json数据格式返回前台。

}

配置文件db.php(因为数据库是前后台都要访问的所以写在Common目录下,db.php是配置数据的配置文件)

 return array(
     'DB_TYPE'=>'mysql',
     'DB_HOST'=>'127.0.0.1',
     'DB_USER'=>'root',
     'DB_PWD'=>'root',
     'DB_PORT'=>3306,
     'DB_NAME'=>'singcms',
     'DB_CHARSET'=>'utf8',
     'DB_PREFIX'=>'cms_',//数据表前缀
 );
?>

配置文件config.php

return array(
//'配置项'=>'配置值'
'URL_CASE_INSENSITIVE'=>true,
    'URL_MODEL'=>0,
    'LOAD_EXT_CONFIG'=>'db',   //上面配置的数据库配置文件加载进来。
    'MD5_PRE'=>'sing_cms',
    'HTML_FILE_SUFFIX'=>'.html',

);


Common模块下创建Model文件夹(操作数据库)

namespace Common\Model;
use Think\Model;


/**
 * 用户组操作
 * @author  singwa
 */
class AdminModel extends Model {
private $_db = '';

       //构造函数
public function __construct() {
$this->_db = M('admin');
}
   //根据用户名查找用户下面根据对应函数名了解其中的含义
    public function getAdminByUsername($username='') {
        $res = $this->_db->where(array(
            'username'=>$username,
            'status'=>1,
        ))->find();
        return $res;
    }
    public function getAdminByAdminId($adminId=0) {
        $res = $this->_db->where('admin_id='.$adminId)->find();
        return $res;
    }


    public function updateByAdminId($id, $data) {


        if(!$id || !is_numeric($id)) {
            throw_exception("ID不合法");
        }
        if(!$data || !is_array($data)) {
            throw_exception('更新的数据不合法');
        }
        return  $this->_db->where('admin_id='.$id)->save($data); // 根据条件更新记录
    }


    public function insert($data = array()) {
        if(!$data || !is_array($data)) {
            return 0;
        }
        return $this->_db->add($data);
    }


    public function getAdmins() {
        $data = array(
            'status' => array('neq',-1),
        );
        return $this->_db->where($data)->order('admin_id desc')->select();
    }
    /**
     * 通过id更新的状态
     * @param $id
     * @param $status
     * @return bool
     */
    public function updateStatusById($id, $status) {
        if(!is_numeric($status)) {
            throw_exception("status不能为非数字");
        }
        if(!$id || !is_numeric($id)) {
            throw_exception("ID不合法");
        }
        $data['status'] = $status;
        return  $this->_db->where('admin_id='.$id)->save($data); // 根据条件更新记录


    }


    public function getLastLoginUsers() {
        $time = mktime(0,0,0,date("m"),date("d"),date("Y"));
        $data = array(
            'status' => 1,
            'lastlogintime' => array("gt",$time),
        );


        $res = $this->_db->where($data)->count();
        return $res['tp_count'];
    }


}

在目录下添加一个后台url  admin.php内容为 这样设置访问localhost/thinkphp/admin.php

相当于localhost/thinkphp/admin.php?m=admin&c=index&a=index


// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st
// +----------------------------------------------------------------------


// 应用入口文件


// 检测PHP环境
if(version_compare(PHP_VERSION,'5.3.0','<'))  die('require PHP > 5.3.0 !');


// 开启调试模式 建议开发阶段开启 部署阶段注释或者设为false
define('APP_DEBUG',True);
$_GET['m'] = (!isset($_GET['m']) || !$_GET['m']) ? 'admin' : $_GET['m'];
$_GET['c'] = (!isset($_GET['c']) || !$_GET['c'])  ? 'index' : $_GET['c'];
$_GET['a'] = (!isset($_GET['a']) || !$_GET['a']) ? 'index' : $_GET['a'];
// 定义应用目录
define('APP_PATH','./Application/');


// 引入ThinkPHP入口文件
require './ThinkPHP/ThinkPHP.php';


// 亲^_^ 后面不需要任何代码了 就是如此简单

以上就完成了后台用户的登录。

接下来需要完成菜单管理功能:url localhost/thinkphp/index.php?m=admin&c=menu&a=index

这个页面应该显示默认存在的菜单内容,但是第一次创建是没有数据的,这时候在这个页面添加一个添加按钮。

这个按钮跳转到添加菜单内容。

$("#button-add").click(function(){

    var url = SCOPE.add_url; //这个url是写在菜单管理的默认index.html内,url为localhost/thinkphp/index.php?m=admin&c=menu&a=add

    window.location.href=url;

});

按钮添加点击事件后,点击按钮就跳转的页面SCOPE.add_url。跳转到这个页面后,填入表单提交的数据内容。

后台控制器对应方法接收数据,并处理,这里使用ajax异步发送数据。

$("#singcms-button-submit").click(function(){
    var data = $("#singcms-form").serializeArray(); //表单数据序列化后。
    postData = {};
    $(data).each(function(i){//把这个表单序列化数据转换成数组
       postData[this.name] = this.value;
    });
    //console.log(postData);
    // 将获取到的数据post给服务器
    url = SCOPE.save_url;
    jump_url = SCOPE.jump_url;
    $.post(url,postData,function(result){
        if(result.status == 1) {
            //成功后跳转回菜单管理默认页面
            return dialog.success(result.message,jump_url);
        }else if(result.status == 0) {
            // 失败
            return dialog.error(result.message);
        }
    },"JSON");
});

namespace Admin\Controller;
use Think\Controller;
use Think\Exception;
class MenuController extends  CommonController{
 
    public function index(){       //菜单默认页面现在先不需要看
        $data=array();
        if(isset($_REQUEST['type'])&&in_array($_REQUEST['type'],array(0,1))){
            $data['type']=intval($_REQUEST['type']);
            $this->assign('type',$data['type']);
        }
        else{
            $this->assign('type',-1);
        }
       /**
        * 分页操作逻辑
        */
      
       $page=$_REQUEST['p']? $_REQUEST['p']:1;
       $pageSize=$_REQUEST['pageSize']? $_REQUEST['pageSize']:3;
       $menus=D('Menu')->getMenus($data,$page,$pageSize);
       $menusCount=D('Menu')->getMenusCount($data);
       $res=new \Think\Page($menusCount,$pageSize); //Thinkphp自带分页函数传入数量和每页大小会生成对应的分页效果
       $pageRes=$res->show();
       $this->assign('pageRes',$pageRes);//向页面传递数据
       $this->assign('menus',$menus);//向页面传递数据
       $this ->display();//跳转到对应的文件名
    }
    public function add(){//这里就是add的方法,把数据发送到这里
        if($_POST){//如果提交的数据不为空
            if(!isset($_POST['name'])|| !$_POST['name']){
                return show(0,'菜单名不能为空');
            }
            if(!isset($_POST['m'])|| !$_POST['m']){
                return show(0,'模块名不能为空');
            }
            if(!isset($_POST['c'])|| !$_POST['c']){
                return show(0,'控制器名不能为空');
            }
            if(!isset($_POST['f'])|| !$_POST['f']){
                return show(0,'方法名不能为空');
            }
            if($_POST['menu_id']){
                return $this->save($_POST);
            }
            $menuId=D('Menu')->insert($_POST);
            if($menuId){
                return show(1,'新增成功',$menuId);
            }
            return show(0,'新增失败',$menuId);
        }
        else{
            $this->display();
        }
    }
    public function edit(){
        $menuId=$_GET['id'];
        $menu=D('Menu')->find($menuId);
        $this->assign('menu',$menu);
        $this->display();
    }
    public function save($data){
        $menuId=$data['menu_id'];
        unset($data['menu_id']);
        try{
        $id=D('Menu')->updateMenuById($menuId,$data);
            if($id === false){
                return show(0,'更新失败');
            }
            return show(1,'更新成功');
        }catch(Exception $e){
            return show(0,$e->getMessage());
        }
        
    }
    
    public function setStatus(){
        try{
        if($_POST){
           $id=$_POST['id'];
           $status=$_POST['status'];
           //执行数据更新操作;
           $res=D('Menu')->updateStatusById($id,$status);
           if($res){
               return show(1,'操作成功');
           }
           else{
               return show(0,'操作失败');
           }
        }
        }catch(Exception $e){
            return show(0,$e->getMessage());
        }
        return show(0,'没有提交数据');
    }
    public function listorder(){
       $listorder=$_POST['listorder'];
      // return show(0,$jumpUrl);
       $jumpUrl = $_SERVER['HTTP_REFERER'];
       $errors=array();
       if($listorder){
           try{
           foreach ($listorder as $menuId=>$v){
               //执行更新
              $id= D('Menu')->updateMenuListorderById($menuId,$v);
              if($id === false){
                  $errors[]=$menuId;
              }
           }
           }catch (Exception $e){
               return show(0,$e->getMessage(),array('jump_url' => $jumpUrl));
           }
           if($errors){
               return show(0,'排序失败-'.implode(',',$errors),array('jump_url' => $jumpUrl));
           }
           return show(1,'排序成功',array('jump_url' => $jumpUrl));
       }
       return show(0,'排序数据失败',array('jump_url' => $jumpUrl));
    }

}

这是一个例子,接下来的内容类似的,其它模块的编写相似,这里就不一一重复了。

这里来详细了解一下文章的添加,其中的富文本编辑,已经图片上传功能。这里使用了party插件

/**
 * 图片上传功能
 */
$(function() {
    $('#file_upload').uploadify({
        'swf'      : SCOPE.ajax_upload_swf, 
        'uploader' : SCOPE.ajax_upload_image_url,   //url=localhost/thinkphp/admin.php?c=image&a=ajaxuploadimage
        'buttonText': '上传图片',
        'fileTypeDesc': 'Image Files',
        'fileObjName' : 'file',
        //允许上传的文件后缀
        'fileTypeExts': '*.gif; *.jpg; *.png',
        'onUploadSuccess' : function(file,data,response) {
            // response true ,false
            if(response) {
                var obj = JSON.parse(data); //由JSON字符串转换为JSON对象
                 
                //console.log(data);
                //console.log(obj);
               
                $('#' + file.id).find('.data').html(' 上传完毕');


                $("#upload_org_code_img").attr("src",obj.data);//把返回的url填入表单
                $("#file_upload_image").attr('value',obj.data);//把返回的url填入表单
                $("#upload_org_code_img").show();//图片展示,一开始隐藏图片位置
            }else{
                alert('上传失败');
            }
        },
    });
});


model图片上传类:

namespace Common\Model;
use Think\Model;


/**
 * 上传图片类
 * @author  singwa
 */
class UploadImageModel extends Model {
    private $_uploadObj = '';
    private $_uploadImageData = '';


    const UPLOAD = 'upload';


    public function __construct() {
        $this->_uploadObj = new  \Think\Upload();  //Thinkphp自带上传功能


        $this->_uploadObj->rootPath = './'.self::UPLOAD.'/';    //上传根路径
        $this->_uploadObj->subName = date(Y) . '/' . date(m) .'/' . date(d); //上传子文件名字
    }


    public function upload() {//上传方法上传成功后返回url路径
        $res = $this->_uploadObj->upload();
        if($res) {
            return '/thinkphp/' .self::UPLOAD . '/' . $res['imgFile']['savepath'] . $res['imgFile']['savename'];
        }else{
            return false;
        }
    }


    public function imageUpload() {//上传方法上传成功后返回url路径
        $res = $this->_uploadObj->upload();
        if($res) {
            return '/thinkphp/' .self::UPLOAD . '/' . $res['file']['savepath'] . $res['file']['savename'];
        }else{
            return false;
        }
    }
}

控制器

/**
 * 图片相关
 */
namespace Admin\Controller;
use Think\Controller;
use Think\Upload;


/**
 * 文章内容管理
 */
class ImageController extends CommonController {
    private $_uploadObj;
    public function __construct() {


    }
    public function ajaxuploadimage() {
        $upload = D("UploadImage");
        $res = $upload->imageUpload();
        if($res===false) {
            return show(0,'上传失败','');
        }else{
            return show(1,'上传成功',$res);
        }


    }
    public function kindupload(){
        $upload = D("UploadImage");
        $res = $upload->upload();
        
        if($res === false) {
            return showKind(1,'上传失败');
        }
        return showKind(0,$res);
    }


}


接下来是富文本内容的上传

后台内容就差不多这样类似的编写结束了,接下来是前台的展示。

有些模块为了防止未登陆就进入这里需要设置一个控制类

namespace Admin\Controller;
use Think\Controller;
/**
 * use Common\Model 这块可以不需要使用,框架默认会加载里面的内容
 */
class CommonController extends Controller {




public function __construct() {

parent::__construct();
$this->_init();
}
/**
* 初始化
* @return
*/
private function _init() {
// 如果已经登录
$isLogin = $this->isLogin();
if(!$isLogin) {
// 跳转到登录页面
$this->redirect('/thinkphp/admin.php?c=login');
}
}


/**
* 获取登录用户信息
* @return array
*/
public function getLoginUser() {
return session("adminUser");
}


/**
* 判定是否登录
* @return boolean 
*/
public function isLogin() {
$user = $this->getLoginUser();
if($user && is_array($user)) {
return true;
}


return false;
}


public function setStatus($data, $models) {
try {
if ($_POST) {
$id = $data['id'];
$status = $data['status'];
if (!$id) {
return show(0, 'ID不存在');
}
$res = D($models)->updateStatusById($id, $status);
if ($res) {
return show(1, '操作成功');
} else {
return show(0, '操作失败');
}
}
return show(0, '没有提交的内容');
}catch(Exception $e) {
return show(0, $e->getMessage());
}
}


public function listorder($model='') {
$listorder = $_POST['listorder'];
$jumpUrl = $_SERVER['HTTP_REFERER'];
$errors = array();
try {
if ($listorder) {
foreach ($listorder as $id => $v) {
// 执行更新
$id = D($model)->updateListorderById($id, $v);
if ($id === false) {
$errors[] = $id;
}
}
if ($errors) {
return show(0, '排序失败-' . implode(',', $errors), array('jump_url' => $jumpUrl));
}
return show(1, '排序成功', array('jump_url' => $jumpUrl));
}
}catch (Exception $e) {
return show(0, $e->getMessage());
}
return show(0,'排序数据失败',array('jump_url' => $jumpUrl));
}


}

需要登陆才能访问的页面要继承这个类。

前台展示系统

前台登录的主页控制器类

namespace Home\Controller;
use Think\Controller;
class IndexController extends CommonController {
    public function index($type=''){
        //获取首页大图数据
        $rankNews = $this->getRank();
        $topPicNews=D('PositionContent')->select(array('status'=>1,'position_id'=>3),1);
       // print_r( $topPicNews);
       // exit;
        //首页3张小图
        $topSmailNews=D('PositionContent')->select(array('status'=>1,'position_id'=>4),3);
        $listNews = D("News")->select(array('status'=>1,'thumb'=>array('neq','')),30);
        $advNews = D("PositionContent")->select(array('status'=>1,'position_id'=>5),2);
        $this->assign('result',array(
            'topPicNews'=>$topPicNews,
            'topSmailNews'=>$topSmailNews,
            'listNews'=>$listNews,
            'advNews' => $advNews,
            'rankNews' => $rankNews,
            
        ));
        /*
         * 
         * 生成页面静态化
         */
        if($type== 'buildHtml'){
            $this->buildHtml('index',HTML_PATH,'Index/index');  //系统生成静态页面的方法 ,index名字, 路径,模板
          
        }
        else{
            $this->display();
        }
       
    }
    public function build_html(){
        $this->index('buildHtml');
        return show(1,'首页缓存生成成功');
    }
    public function crontab_build_html(){
       if(APP_CRONTAB != 1) {
            die("the_file_must_exec_crontab");
        }
        $result = D("Basic")->select();
        if(!$result['cacheindex']) {
            die('系统没有设置开启自动生成首页缓存的内容');
        }
        $this->index('buildHtml');
    }
    public function getCount() {
        if(!$_POST) {
            return show(0, '没有任何内容');
        }
    
        $newsIds =  array_unique($_POST);
    
        try{
            $list = D("News")->getNewsByNewsIdIn($newsIds);
        }catch (Exception $e) {
            return show(0, $e->getMessage());
        }
    
        if(!$list) {
            return show(0, 'notdataa');
        }
    
        $data = array();
        foreach($list as $k=>$v) {
            $data[$v['news_id']] = $v['count'];
        }
        return show(1, 'success', $data);
    }
   

}

其它的类似都是负责展示页面的逻辑

你可能感兴趣的:(php thinkphp3 开发新闻网站+后台管理系统)