一、开发模式
现在的开发模式主要分为两种:
1.二次开发:
如果已经有一个产品,和要开发的项目比较相似,就使用二次开发。
在已经存在的产品上改动, 即使不做任何改动也能使用,改动时根据需求。
2.框架开发:
如果没有现有的产品可改,就选择一个好的框架进行自主框架开发。
新产品=50%功能+一些实用的类库+ 自己补充的新产品
二、下载安装
1.下载
登录phpcms官网:http://www.phpcms.cn 即可找到下载入口。下载时推荐下载UTF-8字符集版本的。
2.安装
下载后解压,即可见到两个目录,其中install_package目录内的文件为需要安装的文件,readme里的文件为帮助文档和.htaccess文件(做伪静态时的规则)。
将install_package内的所有文件和目录拷贝到项目目录内,然后通过浏览器访问项目目录中的install目录,即可打开安装界面(如下图所示)。
第一步:同意许可协议
第二步:运行环境检测
如果运行环境中有哪些没开启,表格最后一列就表现为×,需要通过调整开启。若设备未联网,最后一行DNS解析则表现为×,但不影响在本机安装。
第三步:选择模块
注意PHPSSO设置中必须选择一项才能进行下一步。
第四步:文件权限设置
表格所列出的文件和目录都需要可写才行。
第五步:账号设置
第六步:系统安装
第七步:安装完成
安装完成后,要把项目中的install目录删掉,系统默认是在安装完后自动删掉的,如果没删,要手动删掉。
浏览器访问项目目录下/index.php则访问前台页面,访问项目目录下/admin.php则访问后台管理页面。
三、后台功能
1.我的面板
(1)修改个人信息
其中Language语言一项,改完之后要刷新,则整个界面就改成其他语言。
(2)修改密码
可以修改管理员登录密码。
(3)生成首页
点击则可以生成首页的静态化html文件,加快外界访问速度。
2.设置
(1)站点管理
点击修改
可以在此进行修改网站相关设置。
(2)管理员管理
可以在此进行管理员管理。
1)口令卡
点击申请口令卡
口令卡申请成功,一定要牢牢保存好口令卡图片。
按照图中所示,根据口令卡对照着输入正确数字才能登陆。
(3)角色管理
phpcms中支持对用户进行角色管理,如下图,角色管理中的权限分为管理权限和使用权限:
1)管理权限:通过点击图中的‘权限设置’来设置角色在哪个站点的后台能参与哪些管理,如‘设置’、‘模块’、‘内容’等…
2)栏目权限:通过点击图中的‘栏目权限’来设置角色在哪个站点的前台能对哪些栏目进行哪些操作。
3)成员管理:管理注册的用户。
3.模块
(1)模块管理
1)模块管理
通过管理操作中的禁止、卸载和安装可以操作所列的这些模块,操作完之后需要更新一下缓存。
上图所示的这些模块就在项目目录/phpcms/modules/
中的各个目录。
2)友情链接
①添加类别
②添加友情链接
该友情链接模块还能够通过进行前台申请,只有通过后台管理员通过以后才会显示在前台的友情链接中。
4.内容
(1)管理栏目
上图展示了目前网站所有栏目的结构。
1)添加类别
(2)模型管理
1)添加模型
点击字段管理可以更改字段相关属性,还能够添加你所需要的字段,修改字段的排序就可以更改其在模板中显示的位置。
在此处设置好模型之后,在栏目管理中就可以使用了。
(3)采集管理及其使用方法
1)添加采集点:上图中采集页面编码是采集对象网站使用的是什么字符集编码。
i序列网址:在网址类型选择序列网址之后,在其下面的文本框中,输入列表页的URL,并将代表分页的数字用通配符
(*)
来代替(可以点击测试看看采集的网址是否正确),还可以在下面设置采集页面的数量和“步”的大小。ii网址配置:通过设置采集网址的规则,如采集的url中必须包含什么和不能包含什么,来控制过滤采集的URL以符合自己需要的标准。
iiiBase设置:有的网站使用了Base(<base href="www.baidu.com">),有的则没有,Base则是将网址中公共的前段部分提取出来,然后自动加到页面中的a标签的跳转URL的前面,即基础部分网址,如果目标网站设置了Base则需要在这里设置填写,没设置Base则不用理会此项。
iiii获取网址: 在网页源代码中寻找要获取连接部分,通过填写获取部分前后的唯一代码来进行该部分的定位。
iiiii内容规则:内容规则则是通过选取被采集网站中的html源代码,进行内容的选取,选取方式就是寻找两边独特的html代码,将被采取的内容区域飙升
[内容]
标签。过滤中填写的内容,不会采集到内容当中。iiiiii提交:点击提交即可提交此采集点。
2)采集管理:
1)测试:点击列表中某一条的测试,可以测试该采集点的获取的内容如下图所示。
2)采集网址:点击采集网址,则可以将上述测试中的内容全部采集到。
3)采集内容:采集网址完成之后,要采集内容才能将内容采集到。
4)内容发布:点击之后,可以将选中的条目导入相应的栏目之中,然后将采集到的东西归类到相应的本站数据库字段中,点击提交即可。
四、模板引擎
1.phpcms的模板
模板目录在项目目录/phpcms/templates/
中,里面的目录就是模板。
default目录是默认模板,default目录中的目录都是各个模块。在templates目录中新建目录即为创建一套前台模板,在目录中创建模块目录,在模块目录中新建页面,前台模板中需要但是没有创建的页面,系统会自动从default目录相应的位置继承。
建好页面之后,要将default中的config.php粘贴到新建的模板目录中,然后根据自己的目录结构来修改该config.php,这个文件中的文件结构根据default中的结构建立即可,在此修改后,还可以根据后台中的界面菜单->模板风格中进行设置。
注意:需要修改项目目录/caches/configs/system.php
文件,将“是否允许在线编辑模板”的值改为1,才能通过后台编辑模板文件。
模板中的页面:
1.index.html——首页;
2.category.html——频道页;
3.list.html——列表页;
4.show.html——内容页;
2.phpcms模板引擎语法
(1)phpcms模板引擎支持在模板html文件中写php代码(不推荐使用)。
(2)使用{php
}
定界符,可以在其中直接书写php语法的语句(推荐使用)。
(3)使用{}
定界符之中可以直接调用phpcms对应后端中的常量和变量并显示输出(常用的常量请参考PHPCMS V9手册)。
(4)使用{}
定界符可以在其中调用绝大部分的php函数和phpcms自带函数,在处理完变量和常量后再输出(不推荐使用php函数而推荐使用系统函数)。
(5)if判断
举例:如果$num的值为1或者0,就输出aaaaa,如果等于2就输出bbbbb,否则就输出ccccc。
{php $num=1}
{if $num==1 || $num==0}
aaaaa<br/>
{elseif $num==2}
bbbbb<br/>
{else}
ccccc<br/>
{/if}
(6)数组遍历
循环只有一种,就是遍历数组:
假设后台一个数组:$data = array("1"=>1,"2"=>2,"3"=>3,"4"=>4,"5"=>5,"6"=>6,"7"=>7,"8"=>8,"9"=>9);
,将其遍历。
{loop $data $k $r}
{$k}=========>{$r}<br/>
{/loop}
注:loop标签中有一个默认$n的变量(不显示,可以直接用),用于循环计数。
(7)pc标签
{pc:模块名 action='获取的内容操作' [参数1='参数1值' [参数2='参数2值' [...] ] ] [return='变量名(默认是data)']}
{$变量名(对其操作)}
{/pc}
所有有pc标签的地方,在后台=>界面=>相应模板=>点击[可视化]=>修改,可以在弹出的页面上点击获取想要的内容,在此修改相当于在页面上修改代码。如下图:
1)get模块
{pc:get sql='sql语句' }
{$变量名(对其操作)[参数1='参数1值' [参数2='参数2值' [...]]] }
{/pc}
2)碎片
{pc:block pos='碎片名'}
{/pc}
进入后台,现在模板相应页面的可视化界面中点击“添加碎片”,进行简单的编辑,如下图:然后进入后台=>内容=>碎片管理,即可看到在页面中添加的碎片,并对其进行管理。
(8)template标签
{temlplate "模板名1" [,"模板名2" [,"模板名3" [,...]]}
该标签可以将页面中共同的部分直接引入到本页面中。
五、实战
1、模板的导入
(1)按照项目目录下phpcms目录下templates目录下的default目录的结构创建一个目录并重命名,然后按照default目录中的config.php的格式,创建一个config.php文件,并修改其中目录路径有关的地方(也可以在后台→设置→站点管理中设置)。
以东亚新闻网为例,其目模板的结构为:
dynews
|-phpcms
|-templates
|-default
|-config.php
|-content
|-……
|-index.html
|-dynews
|-config.php
|-content
|-……
(2)将静态资源(如js、css和图片等)打包存入项目目录下的statics目录中,这样比较好管理不同模板的静态资源。以东亚新闻网为例:
dynews
|-statics
|-css
|-js
|-images
|-dynews
|-css
|-js
|-img
|-fonts
|-……
(3)进入后台,在设置→站点管理中切换模板风格设置。设置完之后更新缓存,然后页面即可切换过来。
2、模板内容基本信息的替换
(1)兼容设置
<!--[if IE 8 ]><html class="ie ie8" lang="en"> <![endif]-->
<!--[if (gte IE 9) | !(IE)]><!-->
<html class="not-ie" lang="zh-CN">
<!--<![endif]-->
以上文本放在<!DOCTYPE html>
下,意思为:如果是ie8浏览器,就加载<html class="ie ie8" lang="en">
,如果ie版本大于ie9,或者非ie浏览器,就加载<html class="not-ie" lang="zh-CN">
.
(2)head头部分使用模板引擎加载
按照缺省模板中相同的部分,粘贴过来。
标题:
<title>{if isset($SEO['title']) && !empty($SEO['title'])}{$SEO['title']}{/if}{$SEO['site_title']}</title>
以上文本的意思:如果后台设置了$SEO的标题并且标题不为空,就使用这个标题,否则就使用网站标题。
关键词:
<meta name="keywords" content="{$SEO['keyword']}">
描述:
<meta name="description" content="{$SEO['description']}">
css、js文件的引入:
<!-- 常规情况下是用:-->
<link href="{CSS_PATH}bootstrap.min.css" rel="stylesheet">
<!-- 但是本案例在{CSS_PATH}的上一级目录中又新建了目录,
因此直接使用网站根目录来获取路径:-->
<link href="{WEB_PATH}statics/dynews/css/bootstrap.min.css" rel="stylesheet">
<!-- 推荐使用第二种方法,js文件与css原理相同 -->
搜索框的代码:
<form action="{APP_PATH}index.php" method="get" target="_blank">
<div class="input-group">
<input type="hidden" name="m" value="search"/>
<input type="hidden" name="c" value="index"/>
<input type="hidden" name="a" value="init"/>
<input type="hidden" name="typeid" value="{$typeid}" id="typeid"/>
<input type="hidden" name="siteid" value="{$siteid}" id="siteid"/>
<input type="text" class="form-control text" name="q" id="q" placeholder="Search for...">
<span class="input-group-btn">
<button class="btn btn-default" type="submit">检索</button>
</span>
</div><!-- /input-group -->
</form>
导航栏的遍历:
<div class="menu1 .container-fluid">
<div class="menuState row">
<ul>
<!-- 使用pc标签获取栏目数组 -->
<!-- action="category"表示获取内容栏目列表的值
siteid是站点id
catid="0"是栏目id为0,即最根层栏目
num="12"表示获取12个值组成数组赋给默认值$data -->
{pc:content action="category" siteid="1" catid="0" num="12"}
<!-- 将$data依靠$v遍历出来 -->
{loop $data $v}
<div class="col-xs-1 col-sm-1 col-md-1 col-lg-1">
<li>
<a target="_blank" href="{$v['url']}">{$v['catname']}</a>
</li>
</div>
{/loop}
{/pc}
<ul>
</div>
</div>
<div class="menu2 .container-fluid">
<div class="menuType row">
<ul>
{pc:content action="category" siteid="1" catid="0" num="18"}
{loop $data $v}
<!-- 因为从经济频道是从13个开始,所以遍历的时候加上判断,只有在catid大于等于13的时候才显示 -->
{if $n>=13}
<div class="col-xs-2 col-sm-2 col-md-2 col-lg-2">
<li>
<a target="_blank" href="{$v['url']}">{$v['catname']}</a>
</li>
</div>
{/if}
{/loop}
{/pc}
<ul>
</div>
</div>
注:subcat()
这个pc函数,传入一个catid,就能将子类的catid都取出来,返回一个数组。
首页焦点图的遍历:
<!-- 头条图片 -->
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12" id="topline">
<!-- 此处可以使用页面可视化进行设置,在推荐栏位处后的下拉选项选择“首页焦点图推荐” -->
{pc:content action="position" posid="1" order="id DESC" num="5"}
<article class="jq22-container">
<ul class="hiSlider hiSlider2">
{loop $data $r}
<li class="hiSlider-item">
<a href="{$r['url']}" target="_blank">
<img src="{thumb($r['thumb'],671,300)}" alt="{$r['title']}">
</a>
</li>
{/loop}
</ul>
</article>
{/pc}
</div>
注:thumb()
这个pc函数,有三个参数,第一个参数是缩略图地址,第二个参数是指定的宽度,第三个参数是指定的高度,返回一个指定宽高的缩略图地址。
六、项目建设理论
1、项目的组成
项目由多个模块组成;
模块采用MVC架构;
MVC中最重要的就是控制器;
控制器中包含若干操作;
2、操作
可以理解为操作系统中的邮件菜单中的功能,它是用户在系统中要执行的动作,例如添加、修改、删除和查看等。每个操作都由步骤组成。
3、phpcms的主入口文件
phpcms的整个项目都只访问一个文件,这个文件就是主入口文件。通过参数来判断你要访问的是哪个模块和做的哪个操作。
域名参数组成:
http://域名/index.php/m=模块名&c=控制器类&a=操作(事件)名&id=XXX
模块文件的目录:
X:\项目名\phpcms\modules\
该目录下,每个文件夹是一个模块。每个文件夹中都有php类文件(.php文件),每个类文件,或者说每个类都是一个控制器。类中的每个方法就是一个操作(或事件)。
通常来说,每个模块中,控制前台的类文件都起名为index.php
,控制后台的类的文件名称和模块名相同。
当我们访问网站的首页时,虽然在地址栏中只是访问了index.php
,但实际上访问的全称是index.php/m=content&c=index&a=init
这个事件。
这种自动跳转在X:\项目名\caches\configs\route
这个文件中做了定义,定义规则如下:
路由配置文件
默认配置为default如下:
'default'=>array(
'm'=>'phpcms',
'c'=>'index',
'a'=>'init',
'data'=>array(
'POST'=>array(
'catid'=>1
),
'GET'=>array(
'contentid'=>1
)
)
)
基中“m”为模型,“c”为控制器,“a”为事件,“data”为其他附加参数。
data为一个二维数组,可设置POST和GET的默认参数。POST和GET分别对应PHP中的$_POST和$_GET两个超全局变量。在程序中您可以使用$_POST['catid']来得到data下面POST中的数组的值。
data中的所设置的参数等级比较低。如果外部程序有提交相同的名字的变量,将会覆盖配置文件中所设置的值。如:
外部程序POST了一个变量catid=2那么你在程序中使用$_POST取到的值是2,而不是配置文件中所设置的1。
4、前后台模块控制器的控制
(1)对后台模块的访问控制
模块目录中,凡是后台类文件中必须做到两点:
1.最开始要写上这条代码:
defined('IN_PHPCMS') or exit('No permission resources.');
其意思为:用户必须通过主入口来访问此控制器类文件,直接访问此文件是不行的。即通过地址栏输入http://域名/phpcms/modules/模块目录名/后台类控制器文件名
来访问就会返回No permission resources.这个信息。
IN_PHPCMS
这个变量在base.php文件中已经定义为true
只有通过主入口文件,才能加载base.php文件,才不会返回No permission resources.这个信息。
2.要继承admin
这个类,此admin类为admin模块目录下的classes目录下的admin.class.php文件,因此要在文件第二行写上这条代码:
pc_base::load_app_class('admin','admin',0);
表示引入admin
模块中的admin
类。
(2)base.php详解
base.php中的类名为‘pc_base’,其中定义的静态方法均用pc_base::方法名()
来调用,下面就详细讲解一下这个类中常用的几个静态方法:
1)pc_base::load_app_class()
加载应用中的类,这些类通常只在模块当中加载。
它有3个参数:
①类名:其所加载的是X:\项目名\phpcms\modules\
目录中每个模块目录下的classes
目录中的类。
②模块名:如果不写的话,缺省加载本模块中的类。
③是否初始化类:如果不写的话,缺省是初始化创建对象付给变量的,如果写0
或者false
,就是只加载,相当于引入文件。
2)pc_base::load_sys_class()
加载系统中的类,这些类是phpcms的系统类,里面的方法都是全局函数,在项目中的任何地方都可以使用。
它有3个参数:
①类名:其所加载的是X:\项目名\phpcms\libs\classes
中的类目录中每个模块目录下的classes
目录中的类。
②扩展路径名:????????????
③是否初始化类:如果不写的话,缺省是初始化创建对象付给变量的,如果写0
或者false
,就是只加载,相当于引入文件。
3)pc_base::load_app_func()
加载应用函数库。
它有两个参数:
①函数库名:其所加载的是X:\项目名\phpcms\modules\
目录中每个模块目录下的functions
目录中的函数库。
②模块名:如果不写的话,缺省加载本模块中的函数库。
4)pc_base::load_sys_func()
加载系统函数库。
它有两个参数:
①函数库名:其所加载的是X:\项目名\phpcms\libs\
目录中每个模块目录下的functions
目录中的函数库。
②扩展路径名:?????????????。
(3)模块的安装和卸载
1)简洁办法
只要在X:\项目名\phpcms\modules\
目录中拷入已有模块中的install
和uninstall
目录,即可实现自建模块的安装和卸载功能。
2)土办法
在该phpcms项目的数据库中,找到module
表,在表中插入一条数据,模块名一定要和创建的模块目录名相同,插入之后,刷新后台,即显示自己创建的模块已经安装。
注意:用这个方法会出现一个Hash错误,需要点击“扩展”->“菜单管理”后,在面板中点击自己添加的模块然后???(视频中未说明)
(4)后台模块的配置
进入后台“扩展”->“菜单管理”->“添加菜单”中添加菜单,可以将新功能置于任何后台菜单目录之下,如图:
按照文本框后的提示将其全部填完,点击提交后更新缓存即可安装写好模块的功能。会在左边栏最下方显示。
5、通过前台模块加载模板
前台模板在templates目录下,当前网站正在使用的模板目录下(以东亚新闻网为例),添加相应要使用的使用目录,比如加一个test测试目录。
dynews
|-phpcms
|-templates
|-default
|-config.php
|-content
|-……
|-index.html
|-dynews
|-config.php
|-content
|-test
|-demo.html
|-……
该test目录中放入要使用的模板文件(html文件),其文件名为“demo.html”若模块想调用该模板,则需要在控制器类文件(php文件)的相应方法中写入下面这行代码:
include templae("test","demo");
调用此控制器中的该方法即可显示demo模板。
6、通过后台模块加载模板
而后台的模板则需要在模块目录下建立一个templates
目录,该目录下的模板文件一定是.tpl.php
格式。以东亚新闻网为例,在其后台目录www/dynews/phpcms/modules
中创建一个test
模块,那么它的模板文件就在其templates
目录下,假设其模板文件为list.tpl.php
,在后台控制器类文件的相应方法中写入这行代码:
include $this->admin_tpl("list");//该方法默认调用本模块下的模板目录里的文件
若想调用其他模块中的模板,则需要使用第二个参数:
include $this->admin_tpl("link_list","link");//第二个参数为模块名,此为调用友情链接模块中的templates下的link_list.tpl.php模板。
(1)后台模板结构分析(以友情链接中的link_list.tpl.php为例)
1)头三行请不要动:
<?php
defined('IN_ADMIN') or exit('No permission resources.');//认证用
$show_dialog = 1;
include $this->admin_tpl('header', 'admin');//保持后台默认同意风格
?>
2)下面即一个列表
<div class="pad-lr-10">
<table width="100%" cellspacing="0" class="search-form">
<tbody>
<tr>
<td><div class="explain-col">
<?php echo L('all_linktype')?>: <a href="?m=link&c=link"><?php echo L('all')?></a>
<a href="?m=link&c=link&typeid=0">默认分类</a>
<?php
if(is_array($type_arr)){
foreach($type_arr as $typeid => $type){
?><a href="?m=link&c=link&typeid=<?php echo $typeid;?>"><?php echo $type;?></a>
<?php }}?>
</div>
</td>
</tr>
</tbody>
</table>
<form name="myform" id="myform" action="?m=link&c=link&a=listorder" method="post" >
<div class="table-list">
<table width="100%" cellspacing="0">
<thead>
<tr>
<th width="35" align="center"><input type="checkbox" value="" id="check_box" onclick="selectall('linkid[]');"></th>
<th width="35" align="center"><?php echo L('listorder')?></th>
<th><?php echo L('link_name')?></th>
<th width="12%" align="center"><?php echo L('logo')?></th>
<th width="10%" align="center"><?php echo L('typeid')?></th>
<th width='10%' align="center"><?php echo L('link_type')?></th>
<th width="8%" align="center"><?php echo L('status')?></th>
<th width="12%" align="center"><?php echo L('operations_manage')?></th>
</tr>
</thead>
<tbody>
<!-- 下面的代码请先忽略
<?php
if(is_array($infos)){
foreach($infos as $info){
?>
<tr>
<td align="center" width="35"><input type="checkbox" name="linkid[]" value="<?php echo $info['linkid']?>"></td>
<td align="center" width="35"><input name='listorders[<?php echo $info['linkid']?>]' type='text' size='3' value='<?php echo $info['listorder']?>' class="input-text-c"></td>
<td><a href="<?php echo $info['url'];?>" title="<?php echo L('go_website')?>" target="_blank"><?php echo new_html_special_chars($info['name'])?></a> </td>
<td align="center" width="12%"><?php if($info['linktype']==1){?><?php if($info['passed']=='1'){?><img src="<?php echo $info['logo'];?>" width=83 height=31><?php } else echo $info['logo'];}?></td>
<td align="center" width="10%"><?php echo $type_arr[$info['typeid']];?></td>
<td align="center" width="10%"><?php if($info['linktype']==0){echo L('word_link');}else{echo L('logo_link');}?></td>
<td width="8%" align="center"><?php if($info['passed']=='0'){?><a
href='?m=link&c=link&a=check&linkid=<?php echo $info['linkid']?>'
onClick="return confirm('<?php echo L('pass_or_not')?>')"><font color=red><?php echo L('audit')?></font></a><?php }else{echo L('passed');}?></td>
<td align="center" width="12%"><a href="###"
onclick="edit(<?php echo $info['linkid']?>, '<?php echo new_addslashes(new_html_special_chars($info['name']))?>')"
title="<?php echo L('edit')?>"><?php echo L('edit')?></a> | <a
href='?m=link&c=link&a=delete&linkid=<?php echo $info['linkid']?>'
onClick="return confirm('<?php echo L('confirm', array('message' => new_addslashes(new_html_special_chars($info['name']))))?>')"><?php echo L('delete')?></a>
</td>
</tr>
<?php
}
}
?>
-->
</tbody>
</table>
</div>
①小插曲:上面代码列表中的<?php echo L('logo')?>
L("英文")
为一个语言函数,使用<?php echo L('英文')?>
这个代码是为了软件国际化使用。此处和语言包相关。后台操作语言的选择在第三章后台功能——我的面板——修改个人信息——Language中修改。此处的language文件,在www\dynews\phpcms\languages目录中(此处以东亚新闻网为例),如下图:
每个英文包中都含有各个模块的翻译文件,如下图:
每个翻译文件里装的都是一个php数组(以友情链接模块为例),如下图:
自己创建了一个模块之后,若想做国际化,也可以在相应的语言包目录(languages)下,新建相应模块的语言翻译文件,以相同的方式创建数组,在模板中也使用代码
<?php echo L('英文')?>
,即可调用自己的语言包进行自动翻译,代码中的‘英文’就是语言翻译文件中数组的键。L()
函数详解:该函数有三个参数,第一个参数就是翻译文件中数组的键;
第二个参数,忘了QAQ;
第三个函数就是模块名,若想调用其他模块的语言翻译文件,输入模块名即可,该参数有两个特性:第一,默认为本模块,第二,如果之前调用这个函数选择了其他模块,那么这次调用传入此参数则默认与之前调用的模块相同。
注意:若不想做国际化,则可以忽略此代码,直接在
<?php echo L('英文')?>
处,写中文即可!
3)后台控制器类数据传送到前端
<?php
if(is_array($infos)){
foreach($infos as $info){
?>
<tr>
<td align="center" width="35"><input type="checkbox" name="linkid[]" value="<?php echo $info['linkid']?>"></td>
<td align="center" width="35"><input name='listorders[<?php echo $info['linkid']?>]' type='text' size='3' value='<?php echo $info['listorder']?>' class="input-text-c"></td>
<td><a href="<?php echo $info['url'];?>" title="<?php echo L('go_website')?>" target="_blank"><?php echo new_html_special_chars($info['name'])?></a> </td>
<td align="center" width="12%"><?php if($info['linktype']==1){?><?php if($info['passed']=='1'){?><img src="<?php echo $info['logo'];?>" width=83 height=31><?php } else echo $info['logo'];}?></td>
<td align="center" width="10%"><?php echo $type_arr[$info['typeid']];?></td>
<td align="center" width="10%"><?php if($info['linktype']==0){echo L('word_link');}else{echo L('logo_link');}?></td>
<td width="8%" align="center"><?php if($info['passed']=='0'){?><a
href='?m=link&c=link&a=check&linkid=<?php echo $info['linkid']?>'
onClick="return confirm('<?php echo L('pass_or_not')?>')"><font color=red><?php echo L('audit')?></font></a><?php }else{echo L('passed');}?></td>
<td align="center" width="12%"><a href="###"
onclick="edit(<?php echo $info['linkid']?>, '<?php echo new_addslashes(new_html_special_chars($info['name']))?>')"
title="<?php echo L('edit')?>"><?php echo L('edit')?></a> | <a
href='?m=link&c=link&a=delete&linkid=<?php echo $info['linkid']?>'
onClick="return confirm('<?php echo L('confirm', array('message' => new_addslashes(new_html_special_chars($info['name']))))?>')"><?php echo L('delete')?></a>
</td>
</tr>
<?php
}
}
?>
此处即为对数组$infos
的遍历,$infos
是控制器类的方法中的变量(如下图),当方法调用该模板的时候,会自动将方法中的变量带入到该模板中。
假设后台控制器类中的$infos
变量如下代码所示:
<?php
defined('IN_PHPCMS') or exit('No permission resources.');//限制访问
pc_base::load_app_class('admin','admin',0);//加载admin模块中的admin类,因为下面要继承此类
class test extends admin {
function init(){
$title = "aaaaa";
$info = array(
array("id"=>1, "name"=>"11111", "age"=>10, "sex"=>"男", "email"=>"aaaa@bbb.com"),
array("id"=>1, "name"=>"11111", "age"=>10, "sex"=>"男", "email"=>"aaaa@bbb.com"),
array("id"=>1, "name"=>"11111", "age"=>10, "sex"=>"男", "email"=>"aaaa@bbb.com"),
array("id"=>1, "name"=>"11111", "age"=>10, "sex"=>"男", "email"=>"aaaa@bbb.com"),
array("id"=>1, "name"=>"11111", "age"=>10, "sex"=>"男", "email"=>"aaaa@bbb.com"),
array("id"=>1, "name"=>"11111", "age"=>10, "sex"=>"男", "email"=>"aaaa@bbb.com"),
);
include $this->admin_tpl('init');
}
}
则在后台模板中如下遍历:
<?php
if(is_array($infos)){
foreach($infos as $info){
?>
<tr>
<td align="center" width="35"><input type="checkbox" name="linkid[]" value="<?php echo $info['linkid']?>"></td>
<td align="center" width="35"><?php echo $info['id']?></td>
<td align="center" width="35"><?php echo $info['name']?></td>
<td align="center" width="35"><?php echo $info['age']?></td>
<td align="center" width="35"><?php echo $info['sex']?></td>
<td align="center" width="35"><?php echo $info['email']?></td>
</tr>
<?php
}
}
?>
其后台显示效果如下图所示:
4)增加功能子菜单
在后台操作界面中点击扩展→菜单管理,找到相应的菜单,点击其右边的“添加子菜单”操作,在界面中设置要添加菜单的内容并提交后即可添加模块中的子菜单。详情如下图所示:
界面中的方法名,就是后台控制器类中的方法名,此处填写的方法名为‘add’,若在后台控制器类中编写方法
add()
(如下代码所示)并输出一行字符的话,则可看到下图的显示:
<?php
defined('IN_PHPCMS') or exit('No permission resources.');//限制访问
pc_base::load_app_class('admin','admin',0);//加载admin模块中的admin类,因为下面要继承此类
class test extends admin {
function init(){
$title = "aaaaa";
$infos = array(
array("id"=>1, "name"=>"11111", "age"=>10, "sex"=>"男", "email"=>"aaaa@bbb.com"),
array("id"=>1, "name"=>"11111", "age"=>10, "sex"=>"男", "email"=>"aaaa@bbb.com"),
array("id"=>1, "name"=>"11111", "age"=>10, "sex"=>"男", "email"=>"aaaa@bbb.com"),
array("id"=>1, "name"=>"11111", "age"=>10, "sex"=>"男", "email"=>"aaaa@bbb.com"),
array("id"=>1, "name"=>"11111", "age"=>10, "sex"=>"男", "email"=>"aaaa@bbb.com"),
array("id"=>1, "name"=>"11111", "age"=>10, "sex"=>"男", "email"=>"aaaa@bbb.com"),
);
include $this->admin_tpl('init');
}
//子菜单所指向的方法
function add(){
echo "aaaaaa";
}
}
若想使用如下图所示的大按钮(建议使用此方式),则需要加入下列代码:
<?php
defined('IN_PHPCMS') or exit('No permission resources.');//限制访问
pc_base::load_app_class('admin','admin',0);//加载admin模块中的admin类,因为下面要继承此类
class test extends admin {
function init(){
$title = "aaaaa";
$infos = array(
array("id"=>1, "name"=>"11111", "age"=>10, "sex"=>"男", "email"=>"aaaa@bbb.com"),
array("id"=>1, "name"=>"11111", "age"=>10, "sex"=>"男", "email"=>"aaaa@bbb.com"),
array("id"=>1, "name"=>"11111", "age"=>10, "sex"=>"男", "email"=>"aaaa@bbb.com"),
array("id"=>1, "name"=>"11111", "age"=>10, "sex"=>"男", "email"=>"aaaa@bbb.com"),
array("id"=>1, "name"=>"11111", "age"=>10, "sex"=>"男", "email"=>"aaaa@bbb.com"),
array("id"=>1, "name"=>"11111", "age"=>10, "sex"=>"男", "email"=>"aaaa@bbb.com"),
);
//操作界面中添加大按钮的代码
$show_validator = $show_scroll = true;
$big_menu = array('javascript:window.top.art.dialog({id:\'add\',iframe:\'?m=link&c=link&a=add\', title:\'添加XXX\', width:\'700\', height:\'450\'}, function(){var d = window.top.art.dialog({id:\'add\'}).data.iframe;var form = d.document.getElementById(\'dosubmit\');form.click();return false;}, function(){window.top.art.dialog({id:\'add\'}).close()});void(0);', "添加XXX");
include $this->admin_tpl('init');
}
function add(){
echo "aaaaaa";
}
}
将代码中原本用L()
函数的地方替换成自己需要的东西即可。
(2)创建如下图所示的数据表(学习测试用,并不严谨)
添加100条数据
然后进入
www\dynews\phpcms\model
目录(以东亚新闻网为例),即可见到如下图所示的数据库连接模型,其与数据库表一一对应(多出的一个表是新建的dy_news)。(3)创建model
根据此目录中其他文件的命名规则,创建test_model.class.php
文件,写入以下代码:
<?php
defined('IN_PHPCMS') or exit('No permission resources.');//防止用户通过前台访问
pc_base::load_sys_class('model', '', 0);//加载model.class.php这个文件的类
class test_model extends model {
function __construct() {
$this->db_config = pc_base::load_config('database');//加载caches\config目录里的database.php配置文件
$this->db_setting = 'default';//选择数据库服务器,服务器信息就在上面的database.php中设置,添加数据库服务器只要增加数组内容即可
$this->table_name = 'test';//此处表名不用写表前缀
parent::__construct();//继承model里的父类方法
}
}
(4)控制器类中加载model,连接数据库
在控制器类中增加构造方法,加载对应的表的model,代码如下:
<?php
defined('IN_PHPCMS') or exit('No permission resources.');//限制访问
pc_base::load_app_class('admin','admin',0);//加载admin模块中的admin类,因为下面要继承此类
class test extends admin {
function __construct(){
$this->db = pc_base::load_model("test_model");//将model创建成了对象赋值给$this->db,通过此对象即可实现数据库操作。
}
function init(){
include $this->admin_tpl('init');
}
}
$this->db
对象可以使用www\dynews\phpcms\libs\classes
目录下model.class.php
这个类所有的方法!比如使用下面的listinfo()
方法:
<?php
defined('IN_PHPCMS') or exit('No permission resources.');//限制访问
pc_base::load_app_class('admin','admin',0);//加载admin模块中的admin类,因为下面要继承此类
class test extends admin {
function __construct(){
$this->db = pc_base::load_model("test_model");
}
function init(){
$page = isset($_GET['page']) ? intval($_GET['page']):1;//获取从前台传过来的分页信息
$infos = $this->db->listinfo('', 'id desc', $page, 10);////使用db对象中的listinfo分页方法,按id倒序,每次显示10条
$pages = $this->db->pages;//获取分页按钮信息
include $this->admin_tpl('init');
}
}
前台代码如下:
<?php
defined('IN_ADMIN') or exit('No permission resources.');
$show_dialog = 1;
include $this->admin_tpl('header', 'admin');
?>
<div class="pad-lr-10">
<form name="myform" id="myform" action="?m=link&c=link&a=listorder" method="post" >
<div class="table-list">
<table width="100%" cellspacing="0">
<thead>
<tr>
<th width="35" align="center"><input type="checkbox" value="" id="check_box" onclick="selectall('testid[]');"></th>
<th width="35" align="center">编号</th>
<th>姓名</th>
<th width="12%" align="center">年龄</th>
<th width="10%" align="center">性别</th>
<th width='10%' align="center">邮箱</th>
<th width="8%" align="center">添加时间</th>
<th width="12%" align="center"><?php echo L('operations_manage')?></th>
</tr>
</thead>
<tbody>
<?php
/*
在这里遍历用listinfo查询出来的数据
*/
if(is_array($infos)){
foreach($infos as $info){
?>
<tr>
<td align="center" width="35"><input type="checkbox" name="linkid[]" value="<?php echo $info['linkid']?>"></td>
<td align="center" width="35"><?php echo $info['id']?></td>
<td align="center" width="35"><?php echo $info['name']?></td>
<td align="center" width="35"><?php echo $info['age']?></td>
<td align="center" width="35"><?php echo $info['sex']?></td>
<td align="center" width="35"><?php echo $info['email']?></td>
<td align="center" width="35"><?php echo date("Y-m-d H:i:s",$info['ptime'])?></td>
</tr>
<?php
}
}
?>
</tbody>
</table>
</div>
<div class="btn">
<input name="dosubmit" type="submit" class="button"
value="<?php echo L('listorder')?>"> <input type="submit" class="button" name="dosubmit" onClick="document.myform.action='?m=link&c=link&a=delete'" value="<?php echo L('delete')?>"/></div>
<div id="pages"><?php echo $pages?></div><!-- 此处就是分页信息 -->
</form>
</div>
最后后台界面上显示如下:
(5)“添加信息”子菜单
在后台控制器类的init
方法中加入以下代码:
$big_menu = array('javascript:window.top.art.dialog({id:\'add\',iframe:\'?m=test&c=test&a=add\', title:\''."添加内容".'\', width:\'700\', height:\'450\'}, function(){var d = window.top.art.dialog({id:\'add\'}).data.iframe;var form = d.document.getElementById(\'dosubmit\');form.click();return false;}, function(){window.top.art.dialog({id:\'add\'}).close()});void(0);', "添加内容");
/*?后面的参数意思如下
*m是模块名
*c是类名
*a是方法名
*title是层的标题
*width是层的宽
*height是层的高
*js函数的最后一个参数是按钮显示内容
*/
即可添加大按钮式的子菜单,这种菜单是弹出一个层,来进行信息的填写额。具体设置参考上面的增加功能子菜单部分。
此插件的名称为“artDialog”,感性趣的话可以学习一下。
之后要在类中编写和a方法名相同的函数。
(6)编写后台功能函数/方法和模板
1)增
我们在前面已经介绍了如何增加功能子菜单,在增加子菜单的时候需要填写一个方法名,当时我们填写的是add
方法,现在我们来完善这个方法。完善之前我们先介绍一下系统中的form类,我们将使用该类进行图片上传的讲解。
form类简介
phpcms/lib/classes/
下的form.class.php这个类是一个很好用的类,加入你想要加入新闻编辑器,只要调用该类中的editor方法即可,想要加入上传图片,只要调用image方法,日历组件等等,各种组件都有。
该类是一个系统类,使用之前必须使用pc_base::load_sys_class("form",'', 0);
代码加载进来。如下代码所示:
<?php
defined('IN_PHPCMS') or exit('No permission resources.');//限制访问
pc_base::load_app_class('admin','admin',0);//加载admin模块中的admin类,因为下面要继承此类
class test extends admin {
function __construct(){
$this->db = pc_base::load_model("test_model");
}
function init(){
$page = isset($_GET['page']) ? intval($_GET['page']):1;
$infos = $this->db->listinfo('', 'id desc', $page, 10);
$pages = $this->db->pages;
$big_menu = array('javascript:window.top.art.dialog({id:\'add\',iframe:\'?m=test&c=test&a=add\', title:\''."添加内容".'\', width:\'700\', height:\'450\'}, function(){var d = window.top.art.dialog({id:\'add\'}).data.iframe;var form = d.document.getElementById(\'dosubmit\');form.click();return false;}, function(){window.top.art.dialog({id:\'add\'}).close()});void(0);', "添加内容");
include $this->admin_tpl('init');
}
function add(){
pc_base::load_sys_class("form",'', 0);
include $this->admin_tpl('add');
}
}
除此之外,我们还要准备好add的模板,如下代码所示:
<?php
defined('IN_ADMIN') or exit('No permission resources.');
include $this->admin_tpl('header','admin');
?>
<script type="text/javascript">
<!--
$(function(){
$.formValidator.initConfig({formid:"myform",autotip:true,onerror:function(msg,obj){window.top.art.dialog({content:msg,lock:true,width:'200',height:'50'}, function(){this.close();$(obj).focus();})}});
$("#link_name").formValidator({onshow:"<?php echo L("input").L('link_name')?>",onfocus:"<?php echo L("input").L('link_name')?>"}).inputValidator({min:1,onerror:"<?php echo L("input").L('link_name')?>"});
$("#link_url").formValidator({onshow:"<?php echo L("input").L('url')?>",onfocus:"<?php echo L("input").L('url')?>"}).inputValidator({min:1,onerror:"<?php echo L("input").L('url')?>"}).regexValidator({regexp:"^http:\/\/[A-Za-z0-9]+\.[A-Za-z0-9]+[\/=\?%\-&]*([^<>])*$",onerror:"<?php echo L('link_onerror')?>"})
})
//-->
</script>
<div class="pad_10">
<form action="?m=test&c=test&a=add" method="post" name="myform" id="myform">
<table cellpadding="2" cellspacing="1" class="table_form" width="100%">
<tr>
<td width="500">用户名称:</td>
<td><input type="text" name="test[name]" id="test_name"
size="15" class="input-text"></td>
</tr>
<tr>
<td>用户年龄:</td>
<td><input type="text" name="test[age]" id="test_age"
size="15" class="input-text"></td>
</tr>
<tr>
<td>用户性别:</td>
<td><input type="text" name="test[sex]" id="test_sex"
size="15" class="input-text"></td>
</tr>
<tr>
<td>用户e-mail:</td>
<td><input type="text" name="test[email]" id="test_email"
size="15" class="input-text"></td>
</tr>
<tr id="logolink">
<td>上传头像:</td>
<td><?php echo form::images('test[logo]', 'logo', '', 'test')?></td>
</tr>
<tr>
<th></th>
<td><input type="hidden" name="forward" value="?m=test&c=test&a=add"> <input
type="submit" name="dosubmit" id="dosubmit" class="dialog"
value=" 添加 "></td>
</tr>
</table>
</form>
</div>
</body>
</html>
上面的JS代码是JQuery的formValidator验证插件,可以百度了解一下。其就是做表单组件内容验证的,你想验证哪个表单组件,就将其id名写成哪个组件的id,例如,我们要验证姓名,就填写test_name即可:
<script type="text/javascript">
<!--
$(function(){
$.formValidator.initConfig({formid:"myform",autotip:true,onerror:function(msg,obj){window.top.art.dialog({content:msg,lock:true,width:'200',height:'50'}, function(){this.close();$(obj).focus();})}});
$("#test_name").formValidator({onshow:"请输入用户名",onfocus:"请正确输入用户名"}).inputValidator({min:1,onerror:"用户名输入有误"});
/*
$("#link_url").formValidator({onshow:"<?php echo L("input").L('url')?>",onfocus:"<?php echo L("input").L('url')?>"}).inputValidator({min:1,onerror:"<?php echo L("input").L('url')?>"}).regexValidator({regexp:"^http:\/\/[A-Za-z0-9]+\.[A-Za-z0-9]+[\/=\?%\-&]*([^<>])*$",onerror:"<?php echo L('link_onerror')?>"})
*/
})
//-->
</script>
代码中的.formValidator
中的onshow
是一开始显示的验证提示,onfocus
是获取焦点之后的验证提示,.inputValidator
中的min
是允许输入的最小字符数,onerror
是低于最小字符数之后的错误提示。除此之外还可以在后面进行.
连贯操作进行进一步验证,可以参考注视的部分,或者百度自行学习。
若要显示这个插件的验证信息,需要在控制器的方法中加入$show_validator = $show_scroll = $show_header = true;
代码,如下所示:
function add(){
if(isset($_POST['dosubmit'])){
print_r($_POST['dosubmit']));
}else{
$show_validator = $show_scroll = $show_header = true;
pc_base::load_sys_class("form",'', 0);
include $this->admin_tpl('add');
}
}
做完以上工作之后,我们再点击我们设置好的添加菜单按钮,就可以弹出下面的界面了:
当我们点击“上传图片”之后,则显示form组建设置好的功能界面,如下图所示:
我们根据是否有表单提交传过来的内容,来确定添加按钮显示的界面,若有表单提交的内容,则进行后台的数据操作,若无提交内容,则展示表单界面,代码如下:
function add(){
if(isset($_POST['dosubmit'])){
$_POST['test']['ptime'] = SYS_TIME;//SYS_TIME是系统常量,获取当前时间
$lastid=$this->db->insert($_POST['test']);
if($lastid){
showmessage('添加成功',HTTP_REFERER);//该函数
}else{
showmessage('添加失败','?m=test&c=test&a=init');
}
}else{
$show_validator = $show_scroll = $show_header = true;//加了这行代码,上面的验证插件才能显示
pc_base::load_sys_class("form",'', 0);
include $this->admin_tpl('add');
}
}
一下是insert方法和showmessage函数的详解:
/**
* 执行添加记录操作
* @param $data 要增加的数据,参数为数组。数组key为字段值,数组值为数据取值
* @param $return_insert_id 是否返回新建ID号
* @param $replace 是否采用 replace into的方式添加数据
* @return boolean
*/
final public function insert($data, $return_insert_id = false, $replace = false) {
return $this->db->insert($data, $this->table_name, $return_insert_id, $replace);
}
/**
* 提示信息页面跳转,跳转地址如果传入数组,页面会提示多个地址供用户选择,默认跳转地址为数组的第一个值,时间为5秒。
* showmessage('登录成功', array('默认跳转地址'=>'http://www.phpcms.cn'));
* @param string $msg 提示信息
* @param mixed(string/array) $url_forward 跳转地址
* @param int $ms 跳转等待时间
*/
function showmessage($msg, $url_forward = 'goback', $ms = 1250, $dialog = '', $returnjs = '') {
if(defined('IN_ADMIN')) {
include(admin::admin_tpl('showmessage', 'admin'));
} else {
include(template('content', 'message'));
}
exit;
}
如此一来,即可进行添加操作,添加成功后如下图所示:
2)改
我们在初始化的模板init.tpl.php文件中,增加“修改”操作。增加代码如下所示:
<?php
defined('IN_ADMIN') or exit('No permission resources.');
$show_dialog = 1;
include $this->admin_tpl('header', 'admin');
?>
<div class="pad-lr-10">
<form name="myform" id="myform" action="?m=link&c=link&a=listorder" method="post" >
<div class="table-list">
<table width="100%" cellspacing="0">
<thead>
<tr>
<th width="35" align="center"><input type="checkbox" value="" id="check_box" onclick="selectall('testid[]');"></th>
<th width="35" align="center">编号</th>
<th>姓名</th>
<th width="12%" align="center">年龄</th>
<th width="10%" align="center">性别</th>
<th width='10%' align="center">邮箱</th>
<th width="8%" align="center">添加时间</th>
<th width="12%" align="center">操作</th>
</tr>
</thead>
<tbody>
<?php
if(is_array($infos)){
foreach($infos as $info){
?>
<tr>
<td align="center" width="35"><input type="checkbox" name="linkid[]" value="<?php echo $info['linkid']?>"></td>
<td align="center" width="35"><?php echo $info['id']?></td>
<td align="center" width="35"><?php echo $info['name']?></td>
<td align="center" width="35"><?php echo $info['age']?></td>
<td align="center" width="35"><?php echo $info['sex']?></td>
<td align="center" width="35"><?php echo $info['email']?></td>
<td align="center" width="35"><?php echo date("Y-m-d H:i:s",$info['ptime'])?></td>
<!-- 此处为新增代码 -->
<td align="center" width="12%"><a href="###"
onclick="edit(<?php echo $info['linkid']?>, '<?php echo new_addslashes(new_html_special_chars($info['name']))?>')"
title="<?php echo L('edit')?>"><?php echo L('edit')?></a> | <a
href='?m=link&c=link&a=delete&linkid=<?php echo $info['linkid']?>'
onClick="return confirm('<?php echo L('confirm', array('message' => new_addslashes(new_html_special_chars($info['name']))))?>')"><?php echo L('delete')?></a>
</td>
<!-- 此处为新增代码over -->
</tr>
<?php
}
}
?>
</tbody>
</table>
</div>
<div class="btn">
<input name="dosubmit" type="submit" class="button"
value="<?php echo L('listorder')?>"> <input type="submit" class="button" name="dosubmit" onClick="document.myform.action='?m=link&c=link&a=delete'" value="<?php echo L('delete')?>"/></div>
<div id="pages"><?php echo $pages?></div>
</form>
</div>
<script type="text/javascript">
function edit(id, name) {
window.top.art.dialog({id:'edit'}).close();
window.top.art.dialog({title:'<?php echo L('edit')?> '+name+' ',id:'edit',iframe:'?m=link&c=link&a=edit&linkid='+id,width:'700',height:'450'}, function(){var d = window.top.art.dialog({id:'edit'}).data.iframe;var form = d.document.getElementById('dosubmit');form.click();return false;}, function(){window.top.art.dialog({id:'edit'}).close()});
}
function checkuid() {
var ids='';
$("input[name='linkid[]']:checked").each(function(i, n){
ids += $(n).val() + ',';
});
if(ids=='') {
window.top.art.dialog({content:"<?php echo L('before_select_operations')?>",lock:true,width:'200',height:'50',time:1.5},function(){});
return false;
} else {
myform.submit();
}
}
//向下移动
function listorder_up(id) {
$.get('?m=link&c=link&a=listorder_up&linkid='+id,null,function (msg) {
if (msg==1) {
//$("div [id=\'option"+id+"\']").remove();
alert('<?php echo L('move_success')?>');
} else {
alert(msg);
}
});
}
</script>
</body>
</html>
新增部分的操作功能的代码,调用了其下方的js代码中的edit函数,这个函数还是调用了artDialog这个组件。
我们将代码做一些微调,调整一下组件中的title、域名中的m、c、a、id和width、height的值,这些都是可以调整的,调整后如下:
function edit(id, name) {
window.top.art.dialog({id:'edit'}).close();
window.top.art.dialog({title:'修改内容 '+name+' ',id:'edit',iframe:'?m=test&c=test&a=mod&id='+id,width:'700',height:'300'}, function(){var d = window.top.art.dialog({id:'edit'}).data.iframe;var form = d.document.getElementById('dosubmit');form.click();return false;}, function(){window.top.art.dialog({id:'edit'}).close()});
}
模板中的html代码也要根据上面的调整做出修改,修改后如下:
<td align="center" width="12%"><a href="###"
onclick="edit(<?php echo $info['id']?>, '<?php echo new_addslashes(new_html_special_chars($info['name']))?>')"
title="修改内容">修改</a> | <a
href='?m=link&c=link&a=delete&linkid=<?php echo $info['linkid']?>'
onClick="return confirm('<?php echo L('confirm', array('message' => new_addslashes(new_html_special_chars($info['name']))))?>')"><?php echo L('delete')?></a>
</td>
修改完成后,点击修改即可弹出弹框。然后我们再编辑mod的模板和控制器方法。
接下来我们先设置mod的模板,mod的模板基本上和add的模板一样,不同的地方有以下几点:
1.表单提交到的控制器需要改,包括form中的action要改成?m=test&c=test&a=mod&id=
,以及隐藏的input中value的值?m=test&c=test&a=mod
.
2.给每个input中都假如默认值value=XXX"
,此默认值是修改之前的值,具体怎么获取后面会讲到。
模板的整体页面代码如下:
<?php
include $this->admin_tpl('header','admin');
?>
<div class="pad_10">
<form action="?m=test&c=test&a=mod&id=<?php echo $id; ?>" method="post" name="myform" id="myform">
<table cellpadding="2" cellspacing="1" class="table_form" width="100%">
<tr>
<td width="500">用户名称:</td>
<td><input type="text" name="test[name]" id="test_name"
size="15" class="input-text" value="<?php echo $name; ?>"></td>
</tr>
<tr>
<td>用户年龄:</td>
<td><input type="text" name="test[age]" id="test_age"
size="15" class="input-text" value="<?php echo $age; ?>"></td>
</tr>
<tr>
<td>用户性别:</td>
<td><input type="text" name="test[sex]" id="test_sex"
size="15" class="input-text" value="<?php echo $sex; ?>"></td>
</tr>
<tr>
<td>用户e-mail:</td>
<td><input type="text" name="test[email]" id="test_email"
size="15" class="input-text" value="<?php echo $email; ?>"></td>
</tr>
<tr id="logolink">
<td>上传头像:</td>
<td><?php echo form::images('test[logo]', 'logo', $info['logo'], 'test')?></td>
</tr>
<tr>
<th></th>
<td><input type="hidden" name="forward" value="?m=test&c=test&a=mod"> <input
type="submit" name="dosubmit" id="dosubmit" class="dialog"
value=" 添加 "></td>
</tr>
</table>
</form>
</div>
</body>
</html>
然后我们来编写mod控制器方法,此方法主要逻辑同add一样,我们根据是否有表单提交传过来的内容,来确定添加按钮显示的界面,若有表单提交的内容,则进行后台的数据操作,若无提交内容,则展示表单界面,代码如下:
function mod(){
if(isset($_POST['dosubmit'])){
if($this->db->update($_POST['test'],array('id'=>$_GET['id']))){
showmessage("修改成功");
}else{
showmessage("修改失败");
}
}else{
//$show_validator = $show_scroll = $show_header = true;//此处暂时不做前端表单验证
pc_base::load_sys_class('form', '', 0);
//解出链接内容
$info = $this->db->get_one(array('id'=>$_GET['id']));//这是db类中获取一条数据的方法
extract($info); //此方法可以将数组转成变量,变量名是数组中的键,变量值是数组中的值
include $this->admin_tpl('mod');
}
}
上述代码中用到了db对象中的get_one、update方法和extract函数,extract是php函数,请自行百度,以下是钱两种方法的详细解释:
/**
* 获取单条记录查询
* @param $where 查询条件
* @param $data 需要查询的字段值[例`name`,`gender`,`birthday`]
* @param $order 排序方式 [默认按数据库默认方式排序]
* @param $group 分组方式 [默认为空]
* @return array/null 数据查询结果集,如果不存在,则返回空
*/
final public function get_one($where = '', $data = '*', $order = '', $group = '') {
if (is_array($where)) $where = $this->sqls($where);
return $this->db->get_one($data, $this->table_name, $where, $order, $group);
}
/**
* 执行更新记录操作
* @param $data 要更新的数据内容,参数可以为数组也可以为字符串,建议数组。
* 为数组时数组key为字段值,数组值为数据取值
* 为字符串时[例:`name`='phpcms',`hits`=`hits`+1]。
* 为数组时[例: array('name'=>'phpcms','password'=>'123456')]
* 数组的另一种使用array('name'=>'+=1', 'base'=>'-=1');程序会自动解析为`name` = `name` + 1, `base` = `base` - 1
* @param $where 更新数据时的条件,可为数组或字符串
* @return boolean
*/
final public function update($data, $where = '') {
if (is_array($where)) $where = $this->sqls($where);
return $this->db->update($data, $this->table_name, $where);
}
我们用get_one方法,根据传过来的id获取单条记录,将记录中的每一项变成变量同步到模板中,在模板中的input中的value中用echo输出显示,就可以显示默认值。我们用update方法,根据id来更新数据库中的记录,根据他返回的布尔值进行进一步操作。
3)删
删除操作则和修改很类似,先修改一下新增的“删除”操作的a标签的href,将其指向到我们自己的删除控制器中,代码如下:
<a href='?m=test&c=test&a=del&id=<?php echo $info['id']?>' onClick="return confirm('你确定要删除吗?')">删除</a>
然后编写我们的del方法,代码如下:
function del(){
$id=intval($_GET['id']);
if($id<1 && $id!=0){
return false;
}
$result = $this->db->delete(array('id'=>$id));
if($result){
showmessage('删除成功','?m=test&c=test&a=init');
}else {
showmessage('删除失败','?m=test&c=test&a-init');
}
}
在这里,我们用到了db的delete方法,具体用法如下:
/**
* 执行删除记录操作
* @param $where 删除数据条件,不充许为空。
* @return boolean
*/
final public function delete($where) {
if (is_array($where)) $where = $this->sqls($where);
return $this->db->delete($this->table_name, $where);
}
根据删除的结果做操作,这里我们让他返回初始页面。
7、在线升级下的操作
若我们想在已有功能上添加新的功能,我们需要在控制器目录下新建个文件,文件名一定要用my_
开头,后面跟着原控制器的名字,这样系统可以自动识别该文件并自动集成原控制器。但是该文件中的类必须继承原控制器的类,文件中的类代码如下(以友情链接为例):
class MY_link extends Link{
function __construct() {
parent::__construct();
}
//……your code
}
注意:
(1)在继承了原控制器的类之后,如果要重写构造方法,在第一行一定要写上parent::__construct();
代码,否则原控制器的构造方法会被完全覆盖。这个在任何继承中都要注意。
(2)如果你写的一个类中的方法,不希望它被继承,就在方法前面加上final
关键字。
七、PMPCMS框架
1.新建
将项目中的phpsso_server
目录中的所有目录和文件复制一份,在网站根目录中新建一个新的项目,并粘贴进去,即可使用PHPCMS的框架再建立一个项目,如下图所示:
2.配置
需要修改的配置文件全都在www\v9\caches\configs
目录中。
(1)system.php
将此文件修改成如下所示:
<?php
return array(
//网站路径
'web_path' => '/v9/',
//Session配置
'session_storage' => 'mysql',//如果要使用文件方式进行存储,此处改为'file'
'session_ttl' => 1800,
'session_savepath' => CACHE_PATH.'sessions/',
'session_n' => 0,
//Cookie配置
'cookie_domain' => '', //Cookie 作用域
'cookie_path' => '/', //Cookie 作用路径
'cookie_pre' => 'xBgtT_', //Cookie 前缀,同一域名下安装多套系统时,请修改Cookie前缀
'cookie_ttl' => 0, //Cookie 生命周期,0 表示随浏览器进程
'js_path' => 'http://localhost/v9/statics/js/', //CDN JS
'css_path' => 'http://localhost/v9/statics/css/', //CDN CSS
'img_path' => 'http://localhost/v9/statics/images/', //CDN img
'upload_path' => PHPCMS_PATH.'uploadfile/', //上传文件路径
'app_path' => 'http://localhost/v9/',//动态域名配置地址
'charset' => 'utf-8', //网站字符集
'timezone' => 'Etc/GMT-8', //网站时区(只对php 5.1以上版本有效),Etc/GMT-8 实际表示的是 GMT+8
'debug' => 1, //是否显示调试信息
'admin_log' => 0, //是否记录后台操作日志
'errorlog' => 0, //是否保存错误日志
'gzip' => 1, //是否Gzip压缩后输出
'auth_key' => 'cGre2NgmfYLbVhbWLPeG', // //Cookie密钥
'lang' => 'zh-cn', //网站语言包
'admin_founders' => '1', //网站创始人ID,多个ID逗号分隔
'execution_sql' => 0, //EXECUTION_SQL
//UCenter配置开始
'ucuse'=>'0',//是否开启UC
'uc_api'=>'http://localhost/comsenz/uc',//Ucenter api 地址
'uc_ip'=>'',//Ucenter api IP
'uc_dbhost'=>'localhost',//Ucenter 数据库主机名
'uc_dbuser'=>'root',//Ucenter 数据库用户名
'uc_dbpw'=>'root',//Ucenter 数据库密码
'uc_dbname'=>'ucenter',//Ucenter 数据库名
'uc_dbtablepre'=>'uc_',//Ucenter 数据库表前缀
'uc_dbcharset'=>'gbk',//Ucenter 数据库字符集
'uc_appid'=>'',//应用id(APP ID)
'uc_key'=>'',//Ucenter 通信密钥
);
?>
phpcms所用的框架,将用户会话信息(session)存到了数据库中,这是目前中大型网站通用的方法,因为使用文件存储的话,太多的话不便于管理。因此现在通常使用缓存数据库进行存储。
(2)创建项目数据库
利用phpmyadmin创建一个新的数据库:
在此库里创建两个必须的表,分别是记录用户信息的admin表和记录登录信息的session表,具体表结构如下图所示:
(3)database.php
在此文件中配置这些项:
<?php
return array (
'default' => array (
'hostname' => 'localhost',
'port' => 3306,
'database' => 'myv9',
'username' => 'root',
'password' => '',
'tablepre' => 'v9_',
'charset' => 'utf8',
'type' => 'mysqli',
'debug' => true,
'pconnect' => 0,
'autoconnect' => 0
)
);
?>
配置完之后退出系统重新登录,在“管理员设置->添加管理员”中增加管理员,则可在admin中显示新建的信息。
(4)创建model
在www\v9\phpcms\model
中,根据创建的数据库 ,创建(/保留)admin_model.class.php和session_model.class.php。
(5)创建(修改)控制器
在www\v9\phpcms\modules
中创建(/保留)admin目录,创建(/保留)index.php文件,里面有个right方法,此方法只保留include $this->admin_tpl('right');
这个代码。
(6)创建(修改)前台模板
登录首页的模板分为两块,一块是左边菜单栏,其模板文件为www\v9\phpcms\modules\admin\templates\index.tpl.php
,另一块是右边的内容区域,其模板文件为www\v9\phpcms\modules\admin\templates\right.tpl.php
,可以对这两个文件进行编辑修改,调整显示的内容。例如我们在\index.tpl.php模板中添加hello模块,具体代码如下(html中添加注释的部分):
<?php defined('IN_ADMIN') or exit('No permission resources.');?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=<?php echo CHARSET?>" />
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<title><?php echo L('phpsso')?></title>
<link href="<?php echo CSS_PATH?>reset.css" rel="stylesheet" type="text/css" />
<link href="<?php echo CSS_PATH?>system.css" rel="stylesheet" type="text/css" />
<style>
#loading{position:absolute;left:600px;display:none}
</style>
<script language="javascript" type="text/javascript" src="<?php echo JS_PATH?>jquery.min.js"></script>
</head>
<body scroll="no">
<div id="loading"><div class="msg lf"><p class="attention"><?php echo L('loading');?><span id="loadsecond"></span>...</p></div></div>
<div class="header">
<div class="logo lf"><span class="invisible"><?php echo L('phpsso')?></span></div>
<div class="lf">
<div class="log white cut_line"><?php echo L('hellow')?> <?php echo $userinfo['username']?> <?php if($userinfo['issuper']) echo '['.L('subminiature_tube').']'?><span>|</span><a href="?m=admin&c=password&a=init" target="right_iframe">[<?php echo L('account_setting')?>]</a><span>|</span><a href="?m=admin&c=login&a=logout">[<?php echo L('logout')?>]</a></div>
</div>
</div>
<div id="content" class="content-on">
<div class="col-left left_menu">
<div>
<a href="/"><h3 class="f14"><?php echo L('manage_center')?></h3></a>
<ul>
<li class="menuli" onclick="menu_show(this);"><a hidefocus="true" style="outline:none" href="?m=admin&c=password&a=init" target="right_iframe"><?php echo L('account_setting')?></a></li>
<li class="menuli" onclick="menu_show(this);"><a hidefocus="true" style="outline:none" href="?m=admin&c=administrator&a=init" target="right_iframe"><?php echo L('admin_manage')?></a></li>
<!-- 此处为欢迎模块(开始) -->
<li class="menuli" onclick="menu_show(this);"><a hidefocus="true" style="outline:none" href="?m=hello&c=hello&a=init" target="right_iframe">欢迎模块</a></li>
<!-- 此处为欢迎模块(结束) -->
</ul>
</div>
<a hidefocus="true" style="outline:none" href="javascript:;" id="openClose" class="open" title="<?php echo L('spread_or_closed')?>"><span class="hidden"><?php echo L('expand')?></span></a>
</div>
<div class="col-auto mr8">
<div class="crumbs"><?php echo L('local')?><span id="local"></span></div>
<div class="col-1">
<div class="content">
<iframe name="right_iframe" id="right_iframe" src="?m=admin&c=index&a=right" frameborder="false" scrolling="auto" style="overflow-x:hidden;border:none" width="100%" height="auto" allowtransparency="true" onload="showloading()"></iframe>
</div>
</div>
</div>
</div>
<script type="text/javascript">
//clientHeight-0; 空白值 iframe自适应高度
function windowW(){
if($(window).width()<940){
$('.header').css('width',940+'px');
$('#content').css('width',940+'px');
$('body').attr('scroll','');
$('body').css('overflow','');
}
}
windowW();
$(window).resize(function(){
if($(window).width()<940){
windowW();
}else{
$('.header').css('width','auto');
$('#content').css('width','auto');
$('body').attr('scroll','no');
$('body').css('overflow','hidden');
}
});
window.onresize = function(){
var heights = document.documentElement.clientHeight-120;document.getElementById('right_iframe').height = heights;
var openClose = $("#right_iframe").height()+39;
$("#openClose").height(openClose);$("#content").height(openClose);
}
window.onresize();
//左侧开关
$("#openClose").toggle(
function () {
$(".left_menu").addClass("left_menu_on");
$(this).addClass("close");
$("#content").addClass("content-off")
},
function () {
$(".left_menu").removeClass("left_menu_on");
$(this).removeClass("close");
$("#content").removeClass("content-off")
}
);
function menu_show(obj) {
$('.menuli').removeClass('on fb blue');
$(obj).addClass('on fb blue');
}
function span_local(name) {
$('#local').html(name);
}
if(top.location != self.location) {
top.location=self.location;
}
var read;
function showloading(type) {
if(type) {
$('#loadsecond').html('');
$('#loading').show();
//second = 1;
//read = setInterval(readsecond, 1000);
} else {
$('#loading').fadeOut("slow");
//if(read) clearInterval(read);
}
}
function readsecond() {
$('#loadsecond').html('('+second+')');
second++;
}
</script>
</body>
</html>
然后再建立相应的控制器。
(7)创建控制器
控制器的创建和编写请参考第六章第四节。
(8)配置默认首页
进入系统后默认的界面,此配置请参考第六章第三节。
3、调用系统库的类和函数
参考第六章第四节第1、2小节,此处以sso模块中的form.class.php
这个文件的类进行讲解。
3.1、调用form中的文本编辑器,代码如下:
<?php
defined('IN_PHPCMS') or exit('No permission resources.');
pc_base::load_app_class('admin','admin',0);
pc_base::load_sys_class('form','',0);
class hello {
function init(){
echo '<textarea id="content"></textarea>';
echo form::editor('content','full','hello');
}
}
3.2、调用form中的图片上传插件,代码如下:
<?php
defined('IN_PHPCMS') or exit('No permission resources.');
pc_base::load_app_class('admin','admin',0);
pc_base::load_sys_class('form','',0);
class hello {
function init(){
echo form::images('logo');
}
}
3.3、调用form中的日历插件,代码如下:
<?php
defined('IN_PHPCMS') or exit('No permission resources.');
pc_base::load_app_class('admin','admin',0);
pc_base::load_sys_class('form','',0);
class hello {
function init(){
echo form::date('starttime');
}
}
3.4、调用form中的验证码插件,代码如下:
<?php
defined('IN_PHPCMS') or exit('No permission resources.');
pc_base::load_app_class('admin','admin',0);
pc_base::load_sys_class('form','',0);
class hello {
function init(){
echo form::checkcode();
}
}
具体实现请见第六章第6节第6小节form类详解。
4、模块移植
4.1、拷贝模块目包
将原项目名\phpcms\modules\
目录中的模块,拷贝到现项目名\phpcms\modules\
中。
4.2、拷贝数据库
将数据库中原模块对应的的数据库表,挪到现模块对应的数据库中。注:若使用数据库文件拷贝的方式,要拷贝对应的frm
、MYD
、MYI
三个文件,且在拷贝之前要停止数据库服务。
4.3、拷贝数据库连接模型
将原项目名\\phpcms\model
目录中的模块对应的数据库连接模型,拷贝到现项目名\phpcms\model
中。
4、如何使用前台模板
phpcms中的sso的小型框架,目前没有整合前台模板,你可以自己把smarty模板加入进去。
八、站点移植
如何将此站点从现服务器移植到一个新的服务器上。
1、拷贝原应用
先将现项目目录下的所有文件和目录全部拷贝到新服务器的项目目录下。例如原项目目录为dynews\
,新项目目录为dynews2\
,则将dynews\
下的文件和目录(如下图所示)全部拷贝到dynews2\
中。
2、拷贝数据库
将原有的数据库所有的表都拷贝到新的数据库服务器中。
小插曲:做个本机域名
在windows系统中,C:\WINDOWS\system32\drivers\etc
下的hosts文件里最后加上一行代码:
127.0.0.1 你的域名
注意,上面的“你的域名”一定是要没有注册过的域名。
这样设置过之后就可以通过域名访问本机了。
3、修改配置文件的域名
修改新项目/caches/configs/system.php
里面所有和域名有关的,把以前的老域名修改为新域名就可以了。
例如本项目总将所有的/dynews/
改为/dynews2/
,所有的/localhost/
都改为/www.dazuiwoniu.com/
4、修改后台设置的站点
进行后台设置->站点管理 对相应的站点的域名进行修改。此项目中,将“站点域名”这一项由原来的http://localhost/dynews/
改为http://www.dazuiwoniu.com/dynews2
。修改完成后,删掉项目目录中的index.html文件,然后点击内容->管理栏目,点击其中的更新栏目缓存,最后点击更新缓存。
5、修改附件地址
进入内容->附件管理->附件地址替换。把附件地址批量的替换为新的地址。然后更新缓存。
6、更新文章URL地址
内容->批量更新URL 。把所有的文章的地址都更新一下。
7、生成全站
把全站都生成一次。
九、和Discuz!整合
1、PHPSSO的作用
(1)统一多个phpcms站点的用户,例如一个网站,在北京、上海、西安、武汉等地机房都搭建了站点,但他们几个站点的用户却只有一个统一的用户,这个时候就只要有一个站点安装了PHPSSO就可以让这几个站点使用一套用户就行了。下面进行演示:
1)重新安装一个站点,但不要用全新安装模式,这样就不会安装PHPSSO了。如下图所示:
注意:安装时要选用新的数据库,否则会安装失败。
安装完后,在后台管理的PHPSSO->应用设置中就出现了两个站点之间的通信状态,如下图所示:
2)设置
如果phpsso中的应用列表中有记录显示通讯失败的话,就要对此条目进行编辑,点击操作一栏中的“编辑”,详细内容中的“通信密钥”中的值一定要和你要同步的站点中的“设置”->“PHPSSO配置”里的“加密密钥的值相同”。
**注意:出现通信不成功有可能是以下几种状况:
①phpsso中应用设置里的应用ID与设置中的phpsso配置中的应用ID不对应。
②c:windows\systyem32\drivers\etc\hosts
文件中没有绑定127.0.0.1 localhost(将# 127.0.0.1 localhost 前面的#号去掉)。
③把phpcms\modules\member\classes\client.class.php 361行
$fp = @fsockopen(($ip ? $ip : $host), $port, $errno, $errstr, $timeout);
改成:
$fp = stream_socket_client("tcp://".($ip ? $ip : $host).":".$port, $errno, $errstr, $timeout);
这样就可以解决fsockopen pfsockopen两个函数禁用的问题。
④修改php.ini,加上一行:allow_url_include = On;
。
⑤找到\phpcms\modules\member\classes\client.class.php文件;找到$return_arr = explode("\n", $return);
,上面还有官方的注释“//部分虚拟主机返回数值有误,暂不确定原因,过滤返回数据格式”。看来已经发现问题,就是没有正确解决,修改为$return_arr = explode("\r\n\r\n", $return);
然后更新全站缓存。
⑥如果以上方法都不管用,那就重新安装一下分站点。**
2、Discuz!的安装
(1)去官网下载Discuz!的安装包。
(2)新建discuz!的数据库。
(3)将discuz!安装包中upload目录中的所有文件拷贝到网站根目录的新域名目录下。
(4)访问http://localhost/域名/install
开始安装,安装界面如下:
(5)安装完之后访问后台要先在前台登录管理员账号,然后点击管理中心再登录,然后进入后台,后台如下图所示。
3、Discuz!和phpcms的呼配调通
(1)discuz!的设置:
①点击UCenter->应用管理->添加应用;
②填写如下图所示的值:
(2)phpcms的设置:
①点击phpsso->系统设置->UCenter配置
②填写如下图所示的值:
(3)第(2)步之后第(1)步中的应用自动通信成功!
这时在phpcms和discuz!中注册,在另一个系统中也能直接登录了。
4、Discuz!和phpcms的同步登录退出
详情请见手册中的“整合文档->整合Discuz!”,或者“常见问题->应用间同步登录问题”这一项。
5、phpcms调用Discuz!的帖子
(1)添加数据源
①点击phpcms后台->模块->数据源->外部数据源->添加外部数据源,弹出如下图所示界面:
②在模板中要展示帖子的地方贴上如下代码,即可调用论坛中的帖子:
{pc:get sql="SELECT * FROM pre_forum_thread" cache="3600" page="$page" dbsource="discuz" return="data"}
<ul>
{loop $data $key $val}
<li><a href="http://localhost/discuz/forum.php?mod=viewthread&tid={$val[tid]}">{$val[subject]}</a></li>
{/loop}
</ul>
{if $pages}<div class=page>{$pages}</div>{/if}
{/pc}
其中dbsource
就是前面设置的数据源名,链接中的$val[tid]
是discuz帖子中的唯一id。
如此一来,在页面上即可调用论坛的数据。
十、其他细节
1.页面静态化
①点击内容->管理栏目,选择一个栏目,点击修改,点击生成HTML设置tab,将栏目生成html和内容页生成html都选择‘是’。
或者点击内容->管理栏目,选择批量编辑,将全部的目生成html和内容页生成html都选择‘是’。
然后别忘了点击批量更新URL、批量更新栏目页、批量更新内容页和更新缓存。
②如果设置完之后地址是静态的了但是访问不了,那我们就要更改阿帕奇的配置文件了。打开阿帕奇的httpd.conf文件,找到
#LoadModule rewrite_module modules/mod_rewrite.so
,将其开启(把前面的#去掉),再把一开始下载的phpcms压缩包里的readme目录下的.htaccess
文件拷贝到项目目录中,之后重启web服务器。
2.主程序与web目录程序分离
如果有黑客攻击了网站根目录(www目录),那么他只能攻击www目录下的目录和文件,所以我们把网站的主程序部分(项目目录中的phpcms目录)拷贝到服务器别的目录中,就不会被攻击到了,会使网站更安全。详情请见手册中的高级应用于部署->主程序与web目录分离一项。
3.Sphinx做全文索引
详情请见手册中的高级应用于部署->Sphinx全文索引教程。建议先学习Sphinx。
4.高洛峰自创的Ajax类
搜索一下高洛峰自己写的Ajax类,可以搜索高洛峰老师以前的视频来寻找。