CI
一、Introduction
php常用框架,ThinkPHP,CI,YII,laravel,phalcon等。CI,CodeIgniter,小巧而功能大的php框架,没有模版引擎,没有严格的编码规则等。
二、ci的结构
官网下载ci的包,解压放到站点下。system目录下是ci框架的代码,application空的放自己开发的代码,index.php是入口文件。
1. 框架结构
将ci包放入编辑器,在application目录下,cache放缓存,config放配置文件,controllers放控制器类,models放模型类,third_party放第三方类库,比如支付宝的,微信的,views放视图文件。在config目录下,config.php是通用配置,database.php配数据库,memcached.php配memcache。
2. 控制器
ci中控制器命名没有严格的规范,所有的控制器继承自CI_Controller。ci的控制器可以分组,但不可以分模块。比如tp中可以分为Home和Admin,每个模块下有自己的mvc。在ci中,controllers下可以分home的controller和admin的controller。
3. 模型
ci中模型的命名也没有规范,都继承自CI_Model。但是控制器和模型的名字不要冲突,为了区分可以自己做一个规范。比如控制器中有一个Goods.php类,模型中不能再起名为Goods.php,可以规范模型的类以M.php结尾,比如GoodsM.php。
注意ci中有保留字,比如控制器不能起名为index.php,可以起名为IndexC.php,以避免使用保留字。
4. ci中url的访问
比如有IndexC.php的控制器
<?php
class IndexC extendsCI_Controller
{
public function index()
{
echo 'abc';
}
}
http://www.php2.com/blog/index.php/indexc/index
5. ci中GET变量的接收
传GET变量时不需要串变量名只传值,比如传name=tom,age=12,url为http://www.php2.com/blog/index.php/indexc/index/tom/12
接收的形式
<?php
class IndexC extendsCI_Controller
{
public function index($name, $age)
{
echo $name.'--'.$age;
}
}
为了适应get中可传可不传变量的情况,一般给方法中的参数默认值为’’。
<?php
class IndexC extendsCI_Controller
{
public function index($name='',$age='')
{
echo $name.'--'.$age;
}
}
6. 接收post并过滤xss
$this->input->post('content', TRUE); //第二个参数传true就是过滤xss
7. 生成模型
比如有模型GoodsM
<?php
class GoodsM extendsCI_Model
{
public function getAll()
{
echo 'goodModel-getAll';
}
}
在控制器中加载模型
<?php
class IndexC extendsCI_Controller
{
public function index($name='',$age='')
{
$this->load->model('GoodsM','g');//第二个参数起别名
//$this->GoodsM->getAll();
//$this->g->getAll();
}
}
8. 加载静态内容
所有的静态页都放在views目录下,所有的静态页的扩展名都是.php,静态页只要放到views目录下就可以,但是为了避免重名一类的放在一类的目录下。
比如在views下创建indexc目录,下创建add.php
在控制器中加载静态页
<?php
class IndexC extendsCI_Controller
{
public function index($name='',$age='')
{
$this->load->model('GoodsM');
$this->GoodsM->getAll();
$this->load->view('indexc/add');//目录从views开始,文件扩展名必须是.php,如果必须要html,可以在('indexc/add.html')写明
}
}
向页面传值
$this->load->view('indexc/add',array(
'name' => 'tom',
'age' => '12',
));
在页面中显示值,直接使用php变量
<body>
index.html
<br />
<?php echo $name; ?>
<?php echo $age; ?>
</body>
也可以使用短标签
<body>
index.html
<br />
<?php echo $name; ?>
<?php echo $age; ?>
<hr />
<?=$name?>
<?=$age?>
</body>
9. 类库的自动加载
ci提供了很多类库,这些类库必须手动加载后才能用,但是有些类使用频率高,比如,DB,SESSION。为了方便,可以在配置文件中配置自动加载的类。
在config目录的autoload.php文件中
$autoload['libraries'] =array('database','session');
$autoload['helper'] = array('url');//加载辅助函数site_url,相当于tp的U
10. 把后台模版导入项目
为项目分目录结构,分后台前台。controllers目录下建home和admin目录,views目录下建home和admin目录,在根目录下创建public目录,public下创建home和admin,放css、js、images等。
复制后台模版的样式文件等到public目录下。
后台创建首页控制器,访问路径,http://www.php2.com/blog/index.php/admin/indexc/index。
修改主页样式,在constant.php文件中定义常量,define('_PUBLIC', '/blog/public');//为公共目录定义常量
<link rel="stylesheet"type="text/css"href="<?=_PUBLIC?>/admin/css/common.css"/>
提取页面的公共部分为单独的文件,然后在所有的页面中加载公共部门
<?php$this->load->view('admin/top') ?>
<div class="containerclearfix">
<?php$this->load->view('admin/menu') ?>
…
三、ci操作数据库
1. 建表
create databaseblogphp;
use blog;
set name utf8;
create tableblogphp_blog
(
id mediumint unsigned not nullauto_increment comment 'Id',
title varchar(150) not null comment '日志名称',
content longtext comment '内容',
is_show enum('是','否') not null default '是' comment '是否显示',
addtime datetime not null comment '添加时间',
logo varchar(150) not null default ''comment 'logo图',
sm_logo varchar(150) not null default'' comment '小图',
mid_logo varchar(150) not null default'' comment '中图',
big_logo varchar(150) not null default'' comment '大图',
mbig_logo varchar(150) not null default'' comment '更大图',
primary key (id)
)engine=innodbdefault charset=utf8 comment '博客';
2. 创建控制器
<?php
/**
* 博客控制器
*/
class BlogC extendsCI_Controller
{
/**
* 添加博客
*/
public function add()
{
//导入表单验证类
$this->load->library('form_validation');
//定义验证规则
$this->form_validation->set_rules('title','标题', 'required|maxlength[150]');
$this->form_validation->set_rules('content','内容', 'required');
$this->form_validation->set_rules('is_show','是否显示', 'required|in_list[是,否]');
$z =$this->form_validation->run();
if($z === false)
{
//如果验证失败就显示表单
$this->load->view('admin/blogs/add');
}
else
{
//生成日志模型
$this->load->model('BlogM');
$this->BlogM->add();
//使用辅助函数跳转
redirect(site_url('admin/BlogC/lst'));
}
}
/**
* 博客列表
*/
public function lst()
{
echo 'list';
}
}
3. 创建模型
<?php
class BlogM extendsCI_Model
{
public function add()
{
//构造数据
$data = array(
'title' =>$this->input->post('title'),
'content' =>$this->input->post('content', true),//过滤xss
'is_show' =>$this->input->post('is_show'),
'addtime' =>$this->input->post('addtime'),
);
//插入数据库
$this->db->insert('blogphp_blog',$data);
}
}
4. 创建表单
<formaction="<?=site_url('admin/blogc/add'); ?>"method="post" id="myform" name="myform"enctype="multipart/form-data">
<tr>
<th><iclass="require-red">*</i>标题:</th>
<td>
<?php $error=form_error('title');?>
<input <?php if($error) echo'style="border-color:red;"'; ?> class="common-textrequired" id="title" name="title" size="50"value="<?=set_value('title'); ?>" type="text">
<spanstyle="color:red;"><?=$error; ?></span>
</td>
</tr>
…
5. 添加语言包
添加语言包,解决项目中提示的英文中文混编的问题。
将system目录下的language下的english目录到项目的application目录的language目录下,改名为ch-CN。修改配置文件,config.php文件,$config['language'] ='ch-CN';
修改英文包中的form_validation_lang.php内容为中文
$lang['form_validation_required'] = '{field}不能为空';
6. 修改数据库配置文件
在database.php中配置。
7. 测试
添加成功。ci在插入记录时并没有过滤,除非第二个参数设置为true显示的进行xss过滤。ci的思路是入库时不过滤,显示时才过滤。显示时,<?php echo htmlsepcialchars($title); ?>
四、制作列表、搜索、翻页
1. 模型中添加search方法
/**
* 搜索
*/
public function search($pageSize = 5)
{
/**************搜索***************/
//标题
$title =$this->input->get('title');
if($title)
{
$this->db->like('title',$title);
}
//是否显示
$isShow =$this->input->get('is_show');
if($isShow == '是' || $isShow == '否')
{
$this->db->where('is_show',$isShow);
}
/**************翻页***************/
//在设置的where的基础上总的记录数,取完总的记录数后默认就把前面设置的所有where都清空
//设置第二个参数为false,就会保留where条件
$count =$this->db->count_all_results('blogphp_blog', false);
//加载分页类
$this->load->library('pagination');
//构造配置的数据
$config['base_url'] =site_url('admin/blogc/lst');//基础地址
$config['total_rows'] =$count;//总的记录数
$config['per_page'] =$pageSize;
$config['first_link'] ="首页";
$config['last_link'] = "尾页";
//翻页时其他的变量继续传
$config['reuse_query_string']= true;
//配置翻页类
$this->pagination->initialize($config);
//生成翻页字符串
$pageString =$this->pagination->create_links();
//根据当前页计算偏移量
$offset = $pageSize *($this->pagination->cur_page-1);
/**************排序***************/
//默认根据id降序排列
$this->db->order_by('id','desc');
/**************取数据***************/
//取出所有的博客的数据
$data =$this->db->get('', $pageSize, $offset);
//返回数据
return array(
'data' => $data,
'page' =>$pageString,
);
}
2. 编写控制器的lst方法
/**
* 博客列表
*/
public function lst()
{
//生成模型
$this->load->model('BlogM','bm');
$data =$this->bm->search(2);
$this->load->view('admin/blogc/lst',$data);
}
3. 创建lst模版到视图
<?php foreach($data->result() as $k => $v): ?>
<tr>
<tdclass="tc"><?=$v->id?></td>
<tdclass="tc"><?=$v->title?></td>
<tdclass="tc"><?=$v->is_show?></td>
<tdclass="tc"><?=$v->addtime?></td>
<td>
<a class="link-update"href="#">修改</a>
<a class="link-del"href="#">删除</a>
</td>
</tr>
<?php endforeach;?>
五、修改和删除
1. 删除
在列表页为删除添加链接
<a class="link-del"onclick="returnhref="<?=site_url('admin/blogc/delete/'.$v->id)?>" confirm('确定要删除吗?');" >删除</a>
在控制器创建delete方法
/**
* 删除博客
*/
public function delete($id)
{
//生成模型
$this->load->model('BlogM','bm');
$data =$this->bm->delete($id);
redirect(site_url('admin/blogc/lst'));
}
在模型中添加delete方法
/**
* 删除方法
*/
public function delete($id)
{
$this->db->delete('blogphp_blog',array('id' => $id));
}
2. 修改
在控制器复制add方法为save方法
/**
* 修改博客
*/
public function save($id)
{
//生成日志模型
$this->load->model('BlogM');
//先取出要修改的记录的信息
$info =$this->BlogM->find($id);
// var_dump($info);
//导入表单验证类
$this->load->library('form_validation');
//定义验证规则
$this->form_validation->set_rules('title','标题', 'required|max_length[150]');
$this->form_validation->set_rules('content','内容', 'required');
$this->form_validation->set_rules('is_show','是否显示', 'required|in_list[是,否]');
$z =$this->form_validation->run();
if($z === false)
{
//如果验证失败就显示表单
$this->load->view('admin/blogc/save',$info);
}
else
{
$this->BlogM->save();
//使用辅助函数跳转
redirect(site_url('admin/BlogC/lst'));
}
}
复制add.php为save.php,修改save.php
<tr>
<th><iclass="require-red">*</i>标题:</th>
<td>
<?php $error=form_error('title');?>
<input <?php if($error) echo'style="border-color:red;"'; ?> class="common-textrequired" id="title" name="title" size="50"value="<?=set_value('title', $title); ?>"type="text">
<spanstyle="color:red;"><?=$error; ?></span>
</td>
</tr>
修改lst.php,添加修改按钮
<a class="link-update"href="<?=site_url('admin/blogc/save/'.$v->id)?>">修改</a>
在模型中添加find和save方法
/**
* 根据id取出博客信息
*/
public function find($id)
{
$this->db->from('blogphp_blog');
$this->db->where('id',$id);
$data =$this->db->get();
//将$data转化为二维数组
$data =$data->result('array');
return $data[0];
}
/**
* 修改的方法
*/
public function save()
{
//接收id
$id =$this->input->post('id');
$this->db->where('id',$id);
//构造数据
$data = array(
'title' =>$this->input->post('title'),
'content' =>$this->input->post('content', true),//过滤xss
'is_show' =>$this->input->post('is_show'),
'addtime' =>date('Y-m-d H:i:s'),
);
//更新数据库
$this->db->update('blogphp_blog',$data);
}
六、ci的扩展
模型中一些常用的方法都没有,比如find,delete等。
在ci的模型的父类中扩展封装一下,添加这些常用的公共的方法。
扩展的规则,如果要扩展ci中的类库,比如以MY_开头起名;扩展不同的东西,文件放在不同的位置。在ci的system文件目录中,core、helper和library分别来放不同的类。在application目录下也分别有这三个目录。
如果要扩展CI_Model,在system中,位于core目录下。在扩展时,也放在core目录下,以MY_开头。
在core目录下创建MY_Model.php
<?php
/**
* 扩展的模型的父类
*/
class My_Modelextends CI_Model
{
//定义表名属性用于由子类重写表名
protected $_tableName;
//添加的字段
protected $_insertFields;
//修改的字段
protected $_updateFields;
/*****************************************************/
/**
* 根据id查找信息
*/
public function find($id)
{
$this->db->from($this->_tableName);
$this->db->where('id',$id);
$data =$this->db->get();
//将$data转化为二维数组
$data =$data->result('array');
return $data[0];
}
/**
* 删除方法
*/
public function delete($id)
{
//判断子类是否定义了_before_delete方法
if(method_exists($this,'_before_delete'))
{
if($this->_before_delete($id)=== false)
{
returnfalse;
}
}
return$this->db->delete($this->_tableName, array('id' => $id));
}
/**
* 添加
*/
public function add()
{
//构造数据
$data = array();
foreach($this->_insertFields as $v)
{
$data[$v] =$this->input->post($v, true);
}
//调用添加前的钩子函数
if(method_exists($this,'_before_insert'))
{
if($this->_before_insert($data)=== false)
{
returnfalse;
}
}
//插入数据库
$this->db->insert($this->_tableName,$data);
//获取新插入的记录的id
$data['id'] =$this->db->insert_id();
//添加后的钩子函数
if(method_exists($this,'_after_insert'))
{
$this->_after_insert($data);
}
return $data['id'];
}
/**
* 修改
*/
public function save()
{
//设置where条件
$this->db->where('id',$this->input->post('id'));
//构造数据
$data = array();
foreach($this->_updateFields as $v)
{
$data[$v] =$this->input->post($v, true);
}
//调用修改前的钩子函数
if(method_exists($this,'_before_update'))
{
if($this->_before_update($data)=== false)
{
returnfalse;
}
}
//修改数据
$ret =$this->db->update($this->_tableName, $data);
//修改后的钩子函数
if(method_exists($this,'_after_update'))
{
$this->_after_update($data);
}
return $ret;
}
}
然后,子类继承这个父类,同时,重写需要提供数据的属性。
比如:
<?php
/**
* 博客模型
*/
class BlogM extendsMY_Model
{
//重写父类的tableName属性,其实就是tp框架的做法
protected $_tableName = 'blogphp_blog';
//表单中允许接收的字段
protected $_insertFields =array('title','content','is_show');
protected $_updateFields =array('title','content','is_show');
/*******************************************************/
…..
}
七、代码生成器
大的项目中有很多重复的功能代码,比如增删改查。使用代码生成器可以提高生产效率。
准备工作,有一套已经做好的控制器、模型、视图的增删改查模版,在controllers目录下创建gii_template目录专门放模版文件。添加一个管理员表。
1. 制作表单,让用户输入要生成的表的名字
<?php
/**
* 代码生成器控制器
*/
class GiiC extendsCI_Controller
{
public function gii()
{
//显示接收用户输入信息表单
$this->load->view('gii.php');
}
}
<formmethod="post" action="<?=site_url('giic/make')?>">
<table>
<tr>
<td>表名:</td><td><input type="text"name="table_name" /><td />
</tr>
<tr>
<td></td><td><inputtype="submit" value="生成代码" /></td>
</tr>
</table>
</form>
2. 生成控制器的流程
先把做好的博客控制器复制一份,把这个控制器的名字改成表名C,根据表中字段的信息生成验证规则,修改控制器中所有用到的模型为表名M,修改文件中所有跳转时的控制器为表名C。
3. 生成模型的流程
使用缓冲区中可以运行php的特性,直接在模版中写php代码,替换相应的内容。
<?php foreach($fieldsInfo as $k => $v)
{
if($v['Field'] == 'id')
{
continue;
}
$field[] = $v['Field'];
}
?>
class<?=$mName?> extends MY_Model
{
//设置添加和修改时允许接收的表单中的字段
protected $_tableName ='<?=$tName?>';
protected $_insertFields =array('<?php echo implode("','", $field); ?>');
protected $_updateFields =array('<?php echo implode("','", $field); ?>');
/*******************************************************/
public function search($pageSize = 5)
{
/**************搜索***************/
<?php foreach ($fieldsInfoas $k => $v):
if($v['Field'] =='id')
{
continue;
}
?>
//<?=$v['Comment']?>搜索
$<?=$v['Field']?> =$this->input->get('<?=$v['Field']?>');
if($<?=$v['Field']?>)
{
$this->db->where('<?=$v['Field']?>',$<?=$v['Field']?>);
}
<?php endforeach; ?>
//先设置要操作的表名
$this->db->from($this->$_tableName);
/**************翻页***************/
//在设置的where的基础上总的记录数,取完总的记录数后默认就把前面设置的所有where都清空
//设置第二个参数为false,就会保留where条件
$count =$this->db->count_all_results('$this->$_tableName', false);
//加载分页类
$this->load->library('pagination');
//构造配置的数据
$config['base_url'] =site_url('admin/<?=strtolower($cName)?>/lst');//基础地址
$config['total_rows'] =$count;//总的记录数
$config['first_link'] ="首页";
$config['last_link'] = "尾页";
$config['per_page'] =$pageSize;
//翻页时其他的变量继续传
$config['reuse_query_string']= true;
//配置翻页类
$this->pagination->initialize($config);
//生成翻页字符串
$pageString =$this->pagination->create_links();
//根据当前页计算偏移量
$offset = $pageSize *($this->pagination->cur_page-1);
/**************排序***************/
//默认根据id降序排列
$this->db->order_by('id','desc');
/**************取数据***************/
//取出所有的博客的数据
$data =$this->db->get('', $pageSize, $offset);
//返回数据
return array(
'data' => $data,
'page' =>$pageString,
);
}
/**
* 插入数据前的钩子函数
*/
public function_before_insert(&$data)
{
}
/**
* 插入数据后的钩子函数
*/
public function _after_insert($data)
{
}
/**
* 添加数据前的钩子函数
*/
public function_before_update(&$data)
{
}
/**
* 添加数据后的钩子函数
*/
public function _after_update($data)
{
}
/**
* 删除前的钩子函数
*/
public function _before_delete($id)
{
}
}
4. 生成视图文件的流程
先在views目录下生成与控制器名字一致的目录。然后,修改模板。
<?='<?php$this->load->view(\'admin/top\'); ?>';?>
<?='<divclass="container clearfix">';?>
<?='<?php$this->load->view(\'admin/menu\'); ?>';?>
<!--/sidebar-->
<div class="main-wrap">
<divclass="crumb-wrap">
<divclass="crumb-list"><i class="icon-font"></i><a href="/jscss/admin/design/">首页</a><spanclass="crumb-step">></span><aclass="crumb-name" href="/jscss/admin/design/">作品管理</a><spanclass="crumb-step">></span><span>新增作品</span></div>
</div>
<divclass="result-wrap">
<divclass="result-content">
<formaction="<?='<?=site_url(\'admin/'.strtolower($cName).'/add\');?>';?>" method="post" id="myform"name="myform" enctype="multipart/form-data">
<tableclass="insert-tab" width="100%">
<tbody>
<?php foreach($fieldsInfo as $k => $v):
if($v['Field'] =='id')
{
continue;
}
?>
<tr>
<th>
<?phpif($v['Null'] == 'NO' && $v['Default'] === NULL): ?>
<iclass="require-red">*</i>
<?phpendif; ?>
<?=$v['Comment']?>:
</th>
<td>
<?='<?php $error=form_error(\''.$v['Field'].'\'); ?>';?>
<input <?='<?php if($error)echo \'style="border-color:red;"\'; ?>';?>class="common-text required" id="title"name="<?=$v['Field'];?>" size="50"value="<?='<?=set_value(\''.$v['Field'].'\'); ?>';?>"type="text">
<span style="color:red;">
<?='<?=$error; ?>'?></span>
</td>
</tr>
<?phpendforeach; ?>
<tr>
<th></th>
<td>
<inputclass="btn btn-primary btn6 mr10" value="提交" type="submit">
<inputclass="btn btn6" onclick="history.go(-1)" value="返回" type="button">
</td>
</tr>
</tbody></table>
</form>
</div>
</div>
</div>
<!--/main-->
</div>
</body>
</html>
<!--导入在线编辑器-->
<linkhref="<?=_PUBLIC?>/umeditor1_2_2-utf8-php/themes/default/css/umeditor.css"type="text/css" rel="stylesheet">
<scripttype="text/javascript"src="<?=_PUBLIC?>/umeditor1_2_2-utf8-php/third-party/jquery.min.js"></script>
<scripttype="text/javascript" charset="utf-8"src="<?=_PUBLIC?>/umeditor1_2_2-utf8-php/umeditor.config.js"></script>
<scripttype="text/javascript" charset="utf-8"src="<?=_PUBLIC?>/umeditor1_2_2-utf8-php/umeditor.min.js"></script>
<scripttype="text/javascript" src="<?=_PUBLIC?>/umeditor1_2_2-utf8-php/lang/zh-cn/zh-cn.js"></script>
<script>
UM.getEditor('content',{
initialFrameWidth:800,
initialFrameHeight:200
});
</script>
5. 编写代码生成的方法
<?php
/**
* 代码生成器控制器
*/
class GiiC extendsCI_Controller
{
/**
* 显示输入表名的表单
*/
public function gii()
{
//显示接收用户输入信息表单
$this->load->view('gii.php');
}
/**
* 生成代码
*/
public function make()
{
//生成的控制器和模型的名字
$name = $tName =$this->input->post('table_name');
$name = ucfirst(explode('_',$name)['1']);
$cName = $name.'C';//控制器名
$mName = $name.'M';//模型名
/******************生成控制器********************/
//根据控制器模版复制一个新的控制器
$str =file_get_contents('./application/controllers/gii_template/controller.php');
//修改模版中的内容
$str = str_replace('BlogC',$cName, $str);
$str = str_replace('blogc',strtolower($cName), $str);
$str = str_replace('BlogM',$mName, $str);
//根据表结构构造验证规则
//取出表中所有的字段
$fieldsInfo =$this->db->query('show full fields from '.$tName);
$fieldsInfo =$fieldsInfo->result('array');
//根据表中的字段拼出验证规则
//定义存放rules的数组
$rules = array();
foreach ($fieldsInfo as $k=> $v)
{
if($v['Field'] =='id')
{
continue;
}
if($v['Null'] =='NO' && isset($v['Default']) == NULL)
{
$rules[] ='$this->form_validation->set_rules(\''.$v['Field'].'\',\''.$v['Comment'].'\', \'required\');';
}
}
//把生成的规则替换掉模版中的规则的标记
//如果有规则就替换
if($rules)
{
$str =str_replace('#form_rules#', implode("\r\n\t\t", $rules), $str);
}
//复制到控制器文件
file_put_contents('./application/controllers/admin/'.$cName.'.php',$str);
/******************生成模型********************/
//使用另一种方式
//开启ob缓冲区
ob_start();
//引入模版,并运行模版
include('./application/controllers/gii_template/model.php');
//取出运行后的结果
$str = ob_get_clean();
//生成模型文件
file_put_contents('./application/models/'.$mName.'.php',"<?php\r\n".$str);
/******************生成视图文件********************/
//先在view目录下创建和控制器名字一致的目录
$viewDir ='./application/views/admin/'.strtolower($cName).'/';
if(!is_dir($viewDir))
{
mkdir($viewDir,0777, true);//注意这个方法在安全模式下失效
}
//生成add.php
ob_start();
include('./application/controllers/gii_template/add.php');
$str = ob_get_clean();
file_put_contents($viewDir.'/add.php',$str);
//生成save.php
ob_start();
include('./application/controllers/gii_template/save.php');
$str = ob_get_clean();
file_put_contents($viewDir.'/save.php',$str);
//生成lst.php
ob_start();
include('./application/controllers/gii_template/lst.php');
$str = ob_get_clean();
file_put_contents($viewDir.'/lst.php',$str);
echo '成功';
}
}