CodeIgniter3 笔记

特点

优点

  • 框架配置简单、执行效率高
  • 有基本的路由功能,可以进行一定程度的路由配置
  • 框架简单,且文档详细,上手成本低

缺点:

  • 内部过于混乱,不易于扩展
  • Model层只有简单的数据库操作封装
  • CodeIgniter3不支持命名空间
  • 没有模板引擎,(如果用来写API的话确实用不上)

开始

要求

  • PHP 5.3.7+
  • MySQL5.1+ 开启 mysqli 和 pdo

安装

  • 没有composer安装方式(从4开始有),只能下载压缩包
  • index.php文件位于根目录(默认),直接解析到public就行
  • 为了安全性systemapplication都可以放置在根目录之外,不会被浏览器直接访问。但需要设置在index.php文件中对应的配置变量:$system_path$application_folder$view_folder
  • 设置Apache的URL重写文件:.htaccess
    1. RewriteEngine On
    2. RewriteCond %{REQUEST_FILENAME} !-f
    3. RewriteCond %{REQUEST_FILENAME} !-d
    4. RewriteRule ^(.*)$ index.php?/$1 [L]

基础

框架目录

项目根目录
index.php                          入口文件
.htaccess                          Apache 重写文件
├─application                      项目目录
│  ├─cache                         存放数据或模板的缓存文件
│  ├─config                         配置文件目录
│  │      autoload.php              设置自动加载类库的配置文件
│  │      config.php              项目相关的配置文件
│  │      constants.php              常量配置文件
│  │      database.php              数据库配置文件
│  │      doctypes.php              DOCTYPE标签预设
│  │      foreign_chars.php          外国字符转换配置文件
│  │      hooks.php                  钩子配置文件
│  │      index.html              403文件 每个目录都有
│  │      memcached.php              Memcached配置文件
│  │      migration.php              迁移类配置文件
│  │      mimes.php                  MIME类型配置文件
│  │      profiler.php
│  │      routes.php              路由配置文件
│  │      smileys.php              笑脸表情配置文件
│  │      user_agents.php          用户UA配置文件
│  │      
│  ├─controllers                 控制器
│  ├─core                         项目核心程序
│  ├─helpers                     项目辅助函数
│  ├─hooks                         钩子,在不修改系统核心文件的基础上扩展系统功能
│  ├─language                     语言包目录
│  ├─libraries                     通用类库,可以自己写类库覆盖系统的类库
│  ├─logs                         日志目录
│  ├─models                         模型目录
│  ├─third_party                 第三方库
│  └─views                         视图目录
└─system                          框架程序目录
    ├─core                          框架核心程序
    │  │  Benchmark.php              基准测试类
    │  │  CodeIgniter.php          缓存驱动器
    │  │  Common.php              加载基础类的公共函数
    │  │  Config.php              配置类:CI_Config
    │  │  Controller.php          控制器类:CI_Controller
    │  │  Exceptions.php          排版类,格式化文本:CI_Exceptions
    │  │  Hooks.php                  钩子,核心文件扩展:CI_Hooks
    │  │  index.html              403文件 防止暴露目录
    │  │  Input.php                  输入类:CI_Input
    │  │  Lang.php                  语言类:CI_Lang
    │  │  Loader.php              加载器类:CI_Loader
    │  │  Log.php                  日志类:CI_Log
    │  │  Model.php                  模型类:CI_Model
    │  │  Output.php              输出类:CI_Output
    │  │  Router.php              路由类:CI_Router
    │  │  Security.php              安全类,XSS过滤CSRF过滤:CI_Security
    │  │  URI.php                  URL类:CI_URI
    │  │  Utf8.php
    ├─database                      数据库相关操作程序
    ├─fonts                          字库
    ├─helpers                      辅助函数
    ├─language                       语言包目录
    └─libraries                      通用类库

URL和路由

  • 遵循http://域名/控制器/方法
  • 例如:http://localhost/user/add 则表示用户模块下的添加用户方法
  • 如果域名中包含index.php ,可以通过URL重写去掉
  • 支持使用路由对URL进行美化,可以使用正则表达式或回调函数

保留路由

application\config\routes.php文件中可以配置:

  • $route['default_controller'] 默认加载那个控制器,默认是 Welcome
  • $route['404_override'] 当访问控制器不存在时加载该控制器,若不设置 则加载application/views/errors/error_404.php 文件
  • $route['translate_uri_dashes'] 是否将url中的 -自动转换为_

编码规范

  • PHP结束标签
    • 所有的结束标签不使用?>,用一个空行代替
  • 文件命名

    • 类文件命名是用大写字母开头
    • 配置文件、视图文件、脚本文件使用全小写
    • 可以使用下划线分割单词 ``` 错误的: somelibrary.php someLibrary.php SOMELIBRARY.php Some_Library.php

    Application_config.php Application_Config.php applicationConfig.php

    正确的: Somelibrary.php Some_library.php

    applicationconfig.php application_config.php ```

  • 类和方法命名

    • 类名必须使用大写开头,多个单词之间使用下划线分割,不要使用驼峰命名法 ``` 错误的: class superclass class SuperClass

正确的: class Super_class


   - 类名全部使用小写,并且应该明确指出该方法的功能,最好包含一个动词。冗长的名称使用下划线分割多个单词

错误的: function fileProperties() // not descriptive and uses CamelCase function getfileproperties() // Better! But still missing underscore separator function getFileProperties() // uses CamelCase function get_the_file_properties_from_the_file() // wordy

正确的: function get_file_properties() // descriptive, underscore separator, and all lowercase letters


   - 私有方法和变量应该使用下划线开头
- 变量命名
   - 使用全小写,下划线分割,并且需要明确指出该变量的使用用途
   - 非常短无意义的变量只能在for循环或迭代器中使用
- 常量命名
   - 常量命名规则与变量一致,但需要全部大写
   - 尽量使用CodeIgniter定义好的常量:`SLASH`、`LD`、`RD`、`PATH_CACHE`等
- TRUE、FALSE和NULL
   - TRUE,FALSE和NULL关键字全部使用大写
- 代码缩进
   - 缩进使用TAB而不是空格
   - 除了类的定义外,所有的大括号需要独占一行
   - 中括号和小括号不要有多余的空格
- 注释
   - 单行注释与代码是在一起的
   - 多行注释需要与代码中间有一个空格
   - 使用DocBlock风格的注释,可以被IDE识别

/**

  • Super Class *
  • @package Package Name
  • @subpackage Subpackage
  • @category Category
  • @author Author Name
  • @link http://example.com */ class Super_class {

    /**

  • Encodes string for use in XML *
  • @param string $str Input string
  • @return string */ function xml_encode($str)

/**

  • Data for class manipulation *
  • @var array */ public $data = array(); ```
  • SQL查询
    • SQL的关键字永远大写:SELECT、INSERT、UPDATE、WHERE、AS、JOIN、ON、IN等
    • 如果查询过长,建议分成多行,最好是一行只有一个从句

自动加载

CodeIgniter 的自动加载特性允许每次运行时自动初始化类库、辅助函数和模型等

支持自动加载到有下面这些:

  • libraries/ 目录下的核心类
  • helpers/ 目录下的辅助函数
  • config/ 目录下的用户自定义配置文件
  • system/language/ 目录下的语言文件
  • models/ 目录下的模型类

若需要CodeIgniter 支持Compooser的自动加载,只需要在配置文件application/config/config.php文件中的 $config['composer_autoload'] 设置为 TRUE 或者设置为你自定义的路径。

控制器 Controller

控制器就是application/controllers/目录下的类文件。

比如访问:[http://example.com/blog/index](http://example.com/blog/index),就会加载控制器目录下的Blog.php文件中的index方法

<?php
// 需要继承父控制器类,才可以使用父类方法
class Blog extends CI_Controller {

    public function index()
    {
        echo 'Hello World!';
    }
}

 URL传参

访问域名:http://codeigniter/demo/msg/23/zhangsan

接收参数代码:

<?php
class Demo extends CI_Controller {
    public function msg($id,$name){
        echo '用户id:'.$id.PHP_EOL;
        echo '用户名称:'.$name;
    }
}

输出内容:用户id:23 用户名称:zhangsan

接收数据

CodeIgniter提供了几个辅助方法来分别获取POST、GET、COOKIE、SERVER数组中的数据。CI框架做了一些安全性的过滤,比直接使用$_POST$_get更安全,同时会检查数据是否存在,如果不存在则返回NULL。

主要有以下几个方法:

  • $thins->input->post()
  • $this->input->get()
  • $thins->input->cookie()
  • $thins->input->server()

接收php://input流

如果需要使用PUT、DELETE、PATCH或其他的请求方法,只能使用特殊的流来读取,CodeIgniter对这个流进行了封装,使用$this->input->raw_input_stream;属性就能读取,如果输入流也是数组形式,则可以通过input_stream()方法来进行读取,与get和post一样,如果请求的数据不存在,则会返回NULL。

同样支持XSS过滤:

this->input->input_stream('key', TRUE); // XSS Clean
$this->input->input_stream('key', FALSE); // No XSS filter

重映射方法

如果在控制器中写一个_remap()方法,不管访问的具体是哪个方法,都会进入到_remap()方法,然后由_remap()重写路由,可以接受一个参数,决定加载那个方法。

<?php
public function _remap($method)
{
    if ($method === 'some_method')
    {
        $this->$method();
    }
    else
    {
        $this->default_method();
    }
}

构造函数

如果需要在控制器中使用构造函数,则必须在构造函数中调用父类的构造函数,因为子类的构造函数会覆盖掉父类的构造函数。

<?php
class Blog extends CI_Controller {

    public function __construct()
    {
        parent::__construct();
    }
}

数据库 Database

连接数据库

默认数据库类是不进行自动加载的,如果需要自动加载,可在 application/config/autoload.php 中的 library 数组里添加 database:

$autoload['libraries'] = array('database');

也可以使用手动方式加载数据库配置并初始化数据库类,如果想在整个类中使用,需要把初始化代码写在构造函数中:

$this->load->database();

database()方法支持在初始化的时候传递一些参数:

  • 数据库连接值,使用数组或者DSN字符串传递
  • 布尔值,是否返回连接对象(连接多个数据库时会用到)
  • 布尔值,是否启用查询构造器类,默认为TRUE

从配置文件中选择一个特定分组:

$this->load->database('分组名');

连接一个完全手动指定的数据库,可以传递一个数组参数:

$config['hostname'] = 'localhost';
$config['username'] = 'myusername';
$config['password'] = 'mypassword';
$config['database'] = 'mydatabase';
$config['dbdriver'] = 'mysqli';
$config['dbprefix'] = '';
$config['pconnect'] = FALSE;
$config['db_debug'] = TRUE;
$config['cache_on'] = FALSE;
$config['cachedir'] = '';
$config['char_set'] = 'utf8';
$config['dbcollat'] = 'utf8_general_ci';
$this->load->database($config);

使用DSN作为参数连接数据库:

$dsn = 'dbdriver://username:password@hostname/database';
$this->load->database($dsn);

如果需要连接多个数据库,可以使用这种方式:

$DB1 = $this->load->database('group_one', TRUE);
$DB2 = $this->load->database('group_two', TRUE);

重新连接

当要处理耗时较长的PHP操作时,如果超过了数据库最长连接时间,可以使用reconnect() 向数据库发起一次ping命令,重新建立连接

$this->db->reconnect();

关闭数据库链接

CodeIgniter 可以智能的管理或关闭数据库链接,但除此之外,还可以使用下面的方式手动关闭:

$this->db->close()

数据库配置

CodeIgniter 有一个专门的配置文件用来保存数据库配置:application/config/database.php,配置文件中存放一个多维数组:$db

$db['default'] = array(
    'dsn'   => '',
    'hostname' => 'localhost',
    'username' => 'root',
    'password' => '',
    'database' => 'database_name',
    'dbdriver' => 'mysqli',
    'dbprefix' => '',
    'pconnect' => TRUE,
    'db_debug' => TRUE,
    'cache_on' => FALSE,
    'cachedir' => '',
    'char_set' => 'utf8',
    'dbcollat' => 'utf8_general_ci',
    'swap_pre' => '',
    'encrypt' => FALSE,
    'compress' => FALSE,
    'stricton' => FALSE,
    'failover' => array()
);

或者直接使用DSN:

// PDO
$db['default']['dsn'] = 'pgsql:host=localhost;port=5432;dbname=database_name';

可以设置多个组,来满足开发、测试、生产环境的需要,例如设置一个 “test” 组,可以这样:

$db['test'] = array(
    'dsn'   => '',
    'hostname' => 'localhost',
    'username' => 'root',
    'password' => '',
    'database' => 'database_name',
    'dbdriver' => 'mysqli',
    'dbprefix' => '',
    'pconnect' => TRUE,
    'db_debug' => TRUE,
    'cache_on' => FALSE,
    'cachedir' => '',
    'char_set' => 'utf8',
    'dbcollat' => 'utf8_general_ci',
    'swap_pre' => '',
    'compress' => FALSE,
    'encrypt' => FALSE,
    'stricton' => FALSE,
    'failover' => array()
);

然后设置配置文件中的 $active_group变量,告诉系统默认使用哪个组链接

构造查询器

可以通过配置文件中的 $query_builder变量对 “查询构造器类”继续全局设定 ,如果不使用可以通过设置为false来减少资源消耗。

参数解释

这里只是常用的参数解释,完整的请看官方文档:

配置名 描述
dsn DSN连接字符串
hostname 数据库的主机名
username 数据库用户名
password 数据库密码
database 链接的数据库名
dbdriver 数据库类型:mysq、postgres、odbc等,必须为小写
dbprefix 表前缀
pconnect 布尔值,是否持续链接
db_debug 布尔值,是否显示数据库错误信息
cache_on 布尔值,是否开启数据库查询缓存
cachedir 数据库查询缓存存储目录,服务器绝对路径
char_set 与数据库通信的字符集
dbcollat 与数据库通信时所使用的字符规则,仅限mysql和mysqli驱动
compress 布尔值,是否使用客户端压缩协议,仅限MySQL
port 数据库端口号,要使用这个值,应该添加一行代码到数据库配置组

SQLite

使用SQLite时,无需指定用户名和密码,数据库名直接设置数据库文件的路径即可。

查询数据库

常规查询

要提交一个查询,使用query函数:

$this->db->query('SELECT * FROM user');
  • 当执行读类型的查询时,将会返回一个对象形式的结果集。
  • 当执行写类型的查询时,将会简单的返回布尔值来表示操作是否成功

转义查询

在提交数据时可以通过CodeIgniter 的三个方法来进行转义:

  • $this->db->escape() 会检测数据类型,仅转义字符串类型的数据
  • $this->db->secape_str() 忽略数据类型,对传入的数据进行转义,这个方法用的不多
  • $this->db->escape_like_str() 用于处理LIKE语句中的字符串

查询绑定

查询绑定可以简化查询语法:

$sql = "SELECT * FROM some_table WHERE id = ? AND status = ? AND author = ?";
$this->db->query($sql, array(3, 'live', 'Rick'));

也可以使用二维数组,会被转换为IN语句的集合:

$sql = "SELECT * FROM some_table WHERE id IN ? AND status = ? AND author = ?";
$this->db->query($sql, array(array(3, 6), 'live', 'Rick'));

查询绑定所有的值都会被转义,生成安全的查询语句,不写用手工进行转义

错误处理

获取最近一次发生的错误,使用error()方法可以得到一个包含错误代码和错误消息的数组:

if ( ! $this->db->simple_query('SELECT `example_field` FROM `example_table`'))
{
    $error = $this->db->error(); // Has keys 'code' and 'message'
}

生成查询结果

结果数组

result() 别名:result_object()

这个方法会以对象数组的形式返回查询结果,如果查询失败返回空数组,可以在foreach循环中使用它

$query = $this->db->query("SELECT * FROM user");
foreach ($query->result() as $row)
{
    echo $row->age;
    echo $row->name;
    echo $row->sex;
}

result_array()方法

这个方法会返回一个数组形式的查询结果,如果无结果,则返回一个空数组。

$query = $this->db->query("SELECT * FROM user");
foreach ($query->result_array() as $row)
{
    echo $row['age'];
    echo $row['name'];
    echo $row['sex'];
}

结果行

row()

这个方法返回单独的一行结果,如果查询结果不止一行,则返回的第一行,返回的是对象形式:

$query = $this->db->query("YOUR QUERY");
$row = $query->row();
if (isset($row))
{
    echo $row->title;
    echo $row->name;
    echo $row->body;
}

如果需要发返回特定行号,可以把行号作为第一个参数传递:

$row = $query->row(5);

row_arrray() 这个方法和上面的方法完全一样,只是返回的数组而不是对象

另外可以使用下面的方法从结果集中获取数据,默认返回对象,若传递参数”array”字符串,则返回数组:

方法 含义
$query->first_row() 获取第一行
$query->last_row() 获取最后一行
$query->next_row() 获取下一行
$query->previous_row() 获取上一行

unbuffered_row()

row()方法一样,但不会把所有结果预加载到内存中,如果查询结果集不止一行,则会返回当前一行,并将指针指向下一行:

$query = $this->db->query("YOUR QUERY");
while ($row = $query->unbuffered_row())
{
    echo $row->title;
    echo $row->name;
    echo $row->body;
}

可以制定不同的返回类型:

$query->unbuffered_row();       // object 对象
$query->unbuffered_row('object');   // object 对象
$query->unbuffered_row('array');    // array 数组

num_rows()

用于返回查询结果的行数

<?php
$query = $this->db->query('SELECT * FROM my_table');
echo $query->num_rows();

num_fields()

返回查询结果集的字段数

<?php
    $query = $this->db->query('SELECT * FROM my_table');
    echo $query->num_fields();

fiee_result()

释放掉查询结果集所占用的内存,并删除结果集的资源标识。

辅助函数

执行查询的信息

获取 INSTER 后 通过此方法获取新插入的ID

$this->db->insert_id();

获取 INSERT 、UPDATE 等写类型语句,影响行数

$this->db->affected_rows();

获取上一次执行的查询语句

$this->db->last_query();

获取查询构造器组装 SELECT 语句,返回 SQL 和查询结果集。

 $this->db->get();

获取查询构造器组装 SELECT 语句,此语句只返回SQL,不执行查询。

$this->db->get_compiled_select();

数据库信息

获取表的总行数 第一个参数为表名:

$this->db->count_all('table_name');

钩子 Hooks

个人理解就类似于生命周期函数,在配置文件 config/hooks.php 设置什么时候调用那个文件的哪个方法,和ThinkPHP中的行为是一样的。

定义Hooks

首先需要在文件 application/config/config.php 文件中全局开启钩子:

<?php
$config['enable_hooks'] = TRUE;

然后再钩子的配置文件application/config/hooks.php中定义钩子的数组:

<?php
$hook['挂载点名称']=[
    // 需要调用的类,如果直接写方法不写类可以为空
    'class'    => 'Demo',
    // 需要调用的方法或函数名
    'function' => 'test',
    // 调用钩子的文件名
    'filename' => 'Demo.php',
    // 调用钩子所处的目录
    'filepath' => 'hooks',
    // 传递的参数,可选
    'params'   => 'pre_system'
];

如果需要挂载多个钩子到同一个挂载点,直接写成二维数组即可:

<?php
$hook['挂载点名称'][]=[...];
$hook['挂载点名称'][]=[...];

挂载点

  • pre_system 系统执行的早期调用,只加载了基准测试类和钩子类
  • pre_controller 在控制器调用之前触发,所有的基础类已加载
  • post_controller_constructor 在控制器实例化之后执行,还没有调用任何方法
  • post_controller 在控制器完全运行结束时执行
  • display_override 在最终输出内容时调用,会覆盖_display() 方法,需要手动输出
  • cache_override 用自己的方法替换输出类中的_display_cache()方法,可以自己控制缓存显示机制
  • post_system 在最终页面发送给浏览器之后,框架的最后期会调用

    Hooks 代码示例

    以上面的配置文件为例,在application/hooks目录创建Demo.php文件:
    <?php
    class Demo{
      function test($name){
          echo 'Hooks被调用了:'.$name;
      }
    }
    

自定义Hook

可以在配置文件中自定义挂载点名称:

$hook['test']=[
    'class'    => 'Demo',
    'function' => 'test',
    'filename' => 'Demo.php',
    'filepath' => 'hooks',
    'params'   => '我是测试的hook'
];

然后再想要触发的地方使用:

$this->hooks->call_hook('test');

返回值:调用成功返回true,调用失败返回false,钩子不能使用return返回数据