php学习(四):CodeIgniter框架,仅次于Laravel的框架(CI 4)

鲜于峰
2023-12-01

注意:CI 4 框架支持 print_r() + exit; 但不支持dd 输出, 这与TP, Laravel不同

1.coddeIgniter安装

1.创建CI项目

(1.CodeIgniter4

1.配置php.ini文件 ,开启一下内容
  ;extension=intl
  
2.创建项目
 (1.安装框架 
composer create-project codeigniter4/appstarter=4.0.x CoProject -s rc

 (2.下载依赖包 
 composer install

3.运行项目
 php spark  serve                 默认启动8080端口
  

(2.项目结构

├─app 应用目录
│  ├─Controllers         控制器目录
│  ├─Models              模型目录
│  ├─Views               视图目录
│  └─Config              应用配置目录
│
├─public                WEB目录(对外访问目录)
│  ├─index.php          入口文件  
│ 
├─route                 路由定义目录 
2.运行Git项目

3.开启生产模式

公共函数和全局常量 — CodeIgniter 4.0.0 中文手册|用户手册|用户指南|中文文档

在项目下的 .env文件,修改CI_ENVIRONMENT ( 没有什么作用)

# CI_ENVIRONMENT = production
替换为
CI_ENVIRONMENT = development

APPPATH, 这是个全局变量,它指向 app文件夹目录

ROOTPATH  项目根目录,APPPATH 目录的上层目录。

SECOND,MINUTE,HOUR,DAY,WEEK,MONTH,YEAR,DECADE
4.日志信息

日志保存在 writable/logs/xxx.log 文件中

在控制器中可以使用log_message方法,向日志输出信息

log_message('error', 'Some variable did not contain a value.');

2.codeIgniter全栈学习

1.Routes路由

路由文件默认在app/Config/Routes.php, 里面定义了一个默认路由规则

$routes->get('/', 'Home::index');

1.重新设置路由文件

1.在app文件 夹下创建 Routes/web.php 文件, 添加以下内容

<?php
 
function _routes($routes){ 
    $routes->get('/', 'Home::index');
}

2.修改app/Config/Routes.php 文件,先删除默认路由规则,再添加以下内容

// 自定义路由目录
require(APPPATH ."Routes/web.php");
_routes($routes);

2.定义路由规则

<?php


function _routes($routes){
(1.普通方法
    $routes->get('/', 'Home::index');
    $routes->get('user', 'Admin\User::index');
    $routes->post('user', 'Admin\User::index');
    $routes->put('user', 'Admin\User::index');
    $routes->delete('user', 'Admin\User::index');

(2.多个请求方法
    $routes->match(['get','put'],'user', 'Admin\User::index');

(2.1 映射多个路由
    $homes = [
        '/:num'=>'Home::index/$num',
        '/hello'=>'Home::index',
    ];
    $routes->map($homes);

(3.路径参数
//   设置一个num为路径参数, "$1" 是表示第一个实参 ,这是必选项
//  并且 num 不能替换为非通配符的路径参数,形参倒是可以自由定义
    $routes->get('/hello/(:num)/(:num)', 'Home::index/$1/$2');
//    通配符
//    (:any) 将会从当前位置开始到URI结束,匹配任何字符。这一通配符可能会包括多个URI分段。
//    (:segment) 将会匹配除了斜杠(/)以外的任何字符,从而将匹配结果限制在一个单独的分段中。
//    (:num) 将会匹配任何整数。
//    (:alpha) 将会匹配任何英文字母字符。
//    (:alphanum) 将会匹配任何英文字母或整数,或者是这两者的组合。
//    (:hash) 与 :segment 相同,但可用于方便地查看那个路由正在使用哈希id(参照 Model )。


(4.正则路由
    $routes->get('/([a-z]+)/(\d+)', 'Home::index/$alpha/$digit');


(5.重定向路由, as重命名
    $routes->get('/hello', 'Home::index',['as'=>'home']);
// (5.1.重定向至命名路由
    $routes->addRedirect('home/a', 'home');
// (5.2.重定向至URI
    $routes->addRedirect('home/b', '/hello');


(6.分组路由, filter 过滤器(前后置守卫) ['filter'=>'pi-auth']
    $routes->group('home', function($routes){
        $routes->get('hello', 'Home::index',['filter'=>'isLogin']);
        $routes->get('hi', 'Home::index',['filter'=>'isLogin']);
    });



(7.空路由
    (6.1、空路由(自定义)
    $routes->addPlaceholder('empty', '.*?');
    $routes->get('/:empty', 'Home::index');

    (6.2、404路由(官方)
    //  将执行App\Errors类的show404方法
    $routes->set404Override('App\Errors::show404');
    // 将会输出一个自定义的视图
    $routes->set404Override(function(){
        echo view('my_errors/not_found.html');
    });


(8.反向路由
     $routes->get('users/(:id)/gallery(:any)', 'Galleries::showUserGallery/$1/$2',['as' => 'user_gallery']);
//    在视图中通过route_to 传递参数
/*    <a href="<?= route_to('user_gallery', 15, 12) ?>">查看相册</a>*/


(9.命令行路由
    $routes->cli('migrate', 'App\Database::migrate');

(10.测试路由
//    options参数
//    as重命名 , filter 过滤器, namespace 命名空间, hostname 域名限制, subdomain 限制子域名
//    限制所有子域名访问
    $routes->get('from', 'to', ['subdomain' => '*']);
}

2.Controllers控制器

基本的控制器,需要继承BaseController,也需要使用公有方法声明。才可以通过URL访问。

<?php

namespace App\Controllers;

class Home extends BaseController
{
//    形参定义路径 参数
    public function index($num1)
    {
        return 'hello  world'.$num1;
    }
}

(1.__construct构造函数

<?php
class Blog extends \CodeIgniter\Controller
{
        public function __construct(...$params)
        {
                parent::__construct(...$params);

                // Your own constructor code
        }
}

(2.forceHTTPS 强制HTTPS

默认情况下,在支持 HTTP 严格传输安全报头的现代浏览器中,此调用应强制浏览器将非 HTTPS 调用转换为一年的 HTTPS 调用。你可以通过将持续时间(以秒为单位)作为第一个参数来修改。

if (! $this->request->isSecure())
{
        $this->forceHTTPS(31536000);    // one year
}

*(3.before,after前后置过滤器 **

<?php namespace App\Filters;

use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\Filters\FilterInterface;

class MyFilter implements FilterInterface
{
    public function before(RequestInterface $request)
    {
        // Do something here
        // 这里可以做认证功能
    }

    //--------------------------------------------------------------------

    public function after(RequestInterface $request, ResponseInterface $response)
    {
        // Do something here
    }
}

*(4.media内容协商 **

主要是根据客户端的接受数据格式,返回指定数据

内容协商是一种用来根据客户端和服务端可处理的资源类型,来决定返回给客户端哪种类型的内容的机制。 该机制可用来决定客户端是想要 HTML 还是想要 JSON ,一个图片是应该以 JPG 还是以 PNG 格式返回,或者支持哪种类型的压缩方法等。 这些决策是通过分析四个不同的请求头,而这些请求头里支持多个带有优先级的值选项。手动对这些值选项进行优先级匹配通常是较有挑战性的,因此 CodeIgniter提供了 Negotiator 来处理以上过程。


$supported = [
        'application/json',
        'text/html',
        'application/xml'
];

// 非强制返回,没有匹配到 ,就以第一个格式返回
$format = $request->negotiate('media', $supported);
$format = $negotiate->media($supported);
 
// 强制返回,没有匹配,则返回空字符串 
$format = $request->negotiate('media',$supported,true);
$format = $negotiate->media($supported,true);

(5.HTTP类型伪装

当处理HTML表单时,你只可以使用GET或POST这两个HTTP动词。在大多数情况下,这种情况是没有问题的。然而为了支持REST-ful格式的路由, 你需要支持其他更为正确的路由动词。例如DELETE或PUT。由于浏览器不支持这种方式,CodeIgniter提供了一种正在使用的伪装请求类型的方法。 这种方法允许你发起一个POST请求,但是告诉程序这个请求应该被作为另一个请求类型而处理。

// 为了伪装请求类型,一个名为 _method 的隐藏输入字段需要被添加到表单中。这个字段的值应当是你希望发送的请求类型:
<form action="" method="post">
    <input type="hidden" name="_method" value="PUT" />

</form>
3.Views视图

1.view函数

return view('templates/list',['data'=>'eee'])

2.redirect函数

注意:redirect 跳转的路由是: xxxx/index.php/login, 这个与tp, laravel不同

return redirect('login')

3.缓存视图

你可以通过 view 方法的第三个参数 cache 选项来实现视图缓存功能,缓存的实际单位是秒:

// 视图会缓存 60 秒
echo view('file_name', $data, ['cache' => 60]);

4.动态视图

CodeIgniter 可以智能的处理在控制器中多次调用 view() 方法。如果出现了多次调用,它们将被合并到一起。例如,你可能希望有一个 页头视图、 一个菜单视图,一个内容视图 以及 一个页脚视图。代码看起来应该这样:

 public function index()
{
     $data = [
          'page_title' => 'Your title'
     ];

      echo view('header');
      echo view('menu');
      echo view('content', $data);
      echo view('footer');
}

5.子视图

子视图允许你插入在控制器以外生成的 HTML 片段,但它只能调用指定类的方法,且该方法只能返回有效的 HTML 字符串内容。这个可调用方法可以是在 项目中自动加载器可以定位到的任何可访问类的任何方法,唯一的限制是该类的构造方法不可有必须传入的参数。使用这个功能后,对模块化代码有很好的帮助。

<?= view_cell('\App\Libraries\Blog::recentPosts',['category' => 'codeigniter', 'limit' => 5], 300, 'newcacheid') ?>

public function recentPosts(int $limit, string $category)
{
    $posts = $this->blogModel->where('category', $category)
                             ->orderBy('published_on', 'desc')
                             ->limit($limit)
                             ->get();

    return view('recentPosts', ['posts' => $posts]);
}

6.表格类视图

Table Class 提供的方法使您能够从数组或数据库结果集自动生成 HTML 表。

HTML Table Class — CodeIgniter 4.0.0 中文手册|用户手册|用户指南|中文文档

$table = new \CodeIgniter\View\Table();

$table->setHeading('Name', 'Color', 'Size');
$table->addRow('Fred', '<strong>Blue</strong>', 'Small');

$table->function = 'htmlspecialchars';
echo $table->generate();

在上面的例子中,所有的单元格数据都将通过 PHP 的htmlspecialchars()函数运行,结果是:
<td>Fred</td><td>&lt;strong&gt;Blue&lt;/strong&gt;</td><td>Small</td>
4.MySQL数据库连接

(1.配置php.ini

在php.ini中打开 mysqli模块。 TP和Laravel都是 使用pdo_mysql模块。

打开 模块后,注意重启项目:php artisan serve

;extension=mysqli 

(1.数据库配置

在app/config/database.php是总文件配置


public $default = [
    'DSN'      => '',
    'hostname' => 'localhost',
    'username' => '',
    'password' => '',
    'database' => '',
    'DBDriver' => 'MySQLi',
    'DBPrefix' => '',
    'pConnect' => false,
    'DBDebug'  => (ENVIRONMENT !== 'production'),
    'charset'  => 'utf8',
    'DBCollat' => 'utf8_general_ci',
    'swapPre'  => '',
    'encrypt'  => false,
    'compress' => false,
    'strictOn' => false,
    'failover' => [],
    'port'     => 3306,
];

(2.env环境配置文件

把“#” 给删除

database.default.hostname = localhost
database.default.database = codeigniter-test
database.default.username = root
database.default.password = 123456
database.default.DBDriver = MySQLi
database.default.DBPrefix =
database.default.port = 3306

(3.多个数据库连接


$db1 = \Config\Database::connect('group_one');
$db2 = \Config\Database::connect('group_two');

// 若你使用 MySQLi 数据库驱动,reconnect() 方法并不能 ping 通服务器但它可以关闭连接然后再次连接。
$db->reconnect();

// 手动关闭数据库
// 虽然 CodeIgniter 可以智能的管理并自动关闭数据库连接,你仍可以显式关闭连接。
$db->close();

5.Models模型层

模型提供了一种与数据库中特定表进行交互的方法。它们是开箱即用的辅助方法,可用于您与数据库表交互所需的许多标准方法,包括查找记录、更新记录、删除记录等。

**(1.创建模型 **

<?php namespace App\Models;

use CodeIgniter\Model;

class UserModel extends Model
{
    protected $table      = 'user-msg';   // 数据库表
    protected $primaryKey = 'id';      // 主键

    protected $returnType     = 'array';
    protected $useSoftDeletes = true;

    protected $allowedFields = [         //  表的字段
        'username',
        'password',
        'sex',
        'address',
        'token',
        'registerTime',
        'isDelete',
    ];

    protected $useTimestamps = false;

    // 注意:必须要定义这下面的3个字段,不可以为空或者空字符串, 可以是为同一个字段
    protected $createdField  = 'registerTime';
    protected $updatedField  = 'registerTime';
    protected $deletedField  = 'registerTime';

    protected $validationRules    = [];
    protected $validationMessages = [];
    protected $skipValidation     = false;
}

(2.使用模型

提供了几个函数来对表进行基本的 CRUD 工作,包括 find()、insert()、update()、delete()

use App\Models\UserModel;

public function index(){
//        方法一:创建模型的实例 (建议使用)
        $userModel = new UserModel();
        $users = $userModel->where("id",1)->find();

//        方法二:model 辅助函数
        $userModel = model('UserModel',false); 
        $users = $userModel->where("id",1)->find(); 
}
5.data数据获取
1.Form表单获取
<?php

namespace App\Controllers;
use CodeIgniter\HTTP\RequestInterface; // 真正的请求类 

class Home extends BaseController
{

//  路由是    $routes->get('/hello/(:num)/(:num)', 'Home::index/$1/$2');
//  形参定义路径 形参定义第一个路径参数num
    public function index($name,$num)
    {
//        获取当前上下文的request, 就是RequestInterface 的实例对象
         $request = $this->request;

//        (1.get 请求
//        $input = $this->request->getGet();
//        (2.post请求
//        $input = $this->request->getPost();
//        (3.获取上传的文件(一般是post请求)
//        $input = $this->request->getFiles();
//        (5.获取请求头数据
//        $input = $this->request->getHeaders();

//        (4.获取所有参数
//        $input = $this->request->getServer();
//        $path_info = $input['PATH_INFO'];           //  /1122
//        $request_uri = $input['REQUEST_URI'];       //  /1122?name=1111
//        $request_method = $input['REQUEST_METHOD']; // GET
//        $query_string = $input['QUERY_STRING'];     // name=1111
//        $http_host = $input['HTTP_HOST'];           //  localhost:8080
//        (5.获取当前用户ip
//        $ip = $this->request->getIPAddress()
//        $res = $this->validIP($ip)

//        return '222';
    }
}
2.Mysql数据获取

(1.ORM数据查询(建议使用)

注意:使用 ORM返回的数据,是数组,而不是对象,这与TP, Laravel不同。

$userModel = new UserModel(); // 建议使用

1.查询数据 
$user = $userModel->where('id',1)->find()   // 查询第一个,first() 也是相同的结果,返回的是数组 
$user = $userModel->where('id',1)->findAll()   // 查询所有 

2.插入数据
$data = [ 'username' => 'darth', 'email'=> 'd.vader@theempire.com'];
$user =  $userModel->insert($data)   
 
3.更新数据
$data = [ 'username' => 'darth', 'email'=> 'd.vader@theempire.com'];
$user = $userModel->update($id,$data)   

4.删除数据
$user =  $userModel->delete($id);

(2.DB数据查询(原生)

注意:sql 语句受到 数据库表的限制,表名不能包含短线

$db = \Config\Database::connect();

// 1.查询数据
// (1.多结果查询
$query = $db->query('SELECT name, title, email FROM my_table');
// (1.1.getResult() 函数返回一个 对象数组 。例如:$row->title
$results = $query->getResult();
// (1.2.getResultArray() 函数返回一个 二维数组 。例如:$row[‘title’]
$results = $query->getResultArray();
// (1.3.getFieldCount() 返回查询结果的字段个数(列数),
$query = $db->query('SELECT * FROM my_table'); 
$count = $query->getFieldCount();
// (1.4.执行”写入”类型的语句(insert,update等)时返回有多少行受影响
$db->affectedRows()

// (2.单结果查询
$query = $db->query('SELECT name FROM my_table LIMIT 1');
// getRow() 函数返回一个 对象 。例如:$row->name
$row = $query->getRow();
// getRowArray() 函数返回一个 一维数组 。例如:$row[‘name’]
$row = $query->getRowArray();


// 2.插入数据
// $db->escape() 这个方法会判断数据类型,对字符串数据做转义, 它也会自动给数据加单引号,你无需额外处理:
$sql = "INSERT INTO mytable (title, name) VALUES ({$db->escape($title)},{$db->escape($name)})";
$db->query($sql);
// getAffectedRows 影响的行数
$db->getAffectedRows();


// 3.查询绑定(sql模板语句)
$sql = "SELECT * FROM some_table WHERE id = ? AND status = ? AND author = ?";
$db->query($sql, [3, 'live', 'Rick']);


// 4.预编译查询
使用 prepare() 方法可轻松完成编译,它有一个参数,是函数闭包,返回一个查询对象。 查询对象由任一 “最终” 类型的查询自动生成,包括 insert , update , delete , replace 和 get 。使用查询构造器执行查询可以最轻松地处理此问题。 查询实际没有执行,传入的值不重要也不会被处理,仅做占位使用。 这样会返回一个预编译查询对象:
// 创建预编译查询对象
$pQuery = $db->prepare(function($db) {
    return $db->table('user')->insert([  'name'    => 'x', 'email'   => 'y']);
}); 
// 执行查询
$results = $pQuery->execute($name, $email, $country);
// 虽然 PHP 在(自动)关闭所有打开的查询资源时做的非常好,但手动关闭执行完的预编译查询同样也是好的主意:
$pQuery->close();


// 5.错误处理
如果你需要获取最近一次发生的数据库报错,error() 方法会返回一个数组, 包含错误号和错误信息,来看下用例: 
if(! $db->simpleQuery('SELECT `example_field` FROM `example_table`')) {
        $error = $db->error(); // Has keys 'code' and 'message'
}


// 6.测试功能
返回各种编译构造之后的最终查询语句,也就是发送到数据库执行的语句
$sql = $query->getQuery();
返回执行查询的时长(秒),浮点数,精确到毫秒:
$microtime = $query->getDuration();

(3.查询构造器(table)


// 一、基本CRUD
// 1.查询数据
// (1.1.get获取所有数据,get(10, 20); 指定获取的数量
$query = $db->table('table_name')->get();
$res = $query->getResult()
foreach ($res as $row) {
    echo $row->title;
}
// (1.2.getCompiledSelect没有获取sql语句,并不执行
// (1.3.select返回指定字段 
$sql = $db->table('my_table')->select('title, content, date')->getCompiledSelect();
$sql = $db->table('my_table')->select(['title','content','date'])->get();
// (1.4.selectMax 查询最大字符串,第二个参数是别名,selectMin 查询最小字符串,第二个参数是别名
		 selectAvg 获取平均数,selectSum  获取总和,selectCount 查询行数
$res = $db->table('my_table')->selectMax('age',('new_age'))->get();
$res = $db->table('my_table')->selectMin('age',('new_age'))->get();
$res = $db->table('my_table')->selectAvg('age')->get();
$res = $db->table('my_table')->selectSum('age')->get();
$res = $db->table('my_table')->selectCount('age')->get();
//(1.5.distinct 去重 
$query = $db->table('blog')->select("name")->distinct('title')->get();  
// (1.6.countAllResults 行数
// (    countAll一张数据表的总共行数,第一个参数是表名
$query = $db->table('blog')->select("name")->distinct('title')->countAllResults();  
$count = $db->table('my_table')->countAll();
 
// 2.插入数据
// (2.1.insert插入数据
// (2.2.ignore 如果存在相同的主键,则不插入
$data = [  'title' => $title, 'name' => $name, 'date' => $date ]; 
$db->table('mytable')->insert($data); 
$db->table('mytable')->ignore(true)->insert($data); 
 
// 3.update  更新数据
// (3.1.update 更新
$data = [  'title' => $title, 'name' => $name, 'date' => $date ]; 
$db->table('mytable')->where('id',1)->update($data); 
// (3.2.replace , 如果title是主键,并且查找到数据,则更新
$data = [  'title' => $title, 'name' => $name, 'date' => $date ]; 
$db->table('mytable')->insert($data); 
 
// 4.delete  删除数据
// (4.1.delete 删除 
$db->table('mytable')->where('id',1)->delete(); 
// (4.2.truncate 清空表 
 $db->table('mytable')->where('id',1)->truncate();
 
 
 
// 二、其他方法
// 1.join连表查询 
// 你可以传入第三个参数指定连接的类型,可选: left,right, outer, inner, left outer 和 right outer 。
$query = $db->table('blog')->select('*')->join('comments', 'comments.id = blogs.id')->get();
 
// 2.where过滤查询
$query = $db->table('blog')->where('name', $name)->get(); 
$query = $db->table('blog')->where('age >', $number)->get(); 
$query = $db->table('blog')->where(['name'=>$name])->get();  
$query = $db->table('blog')->where($whereSqlStr)->get(); 

// (3.子查询
$res = $db->table("user")->where('advance_amount <', function(BaseBuilder $query) {
    return $query->select('MAX(advance_amount)', false)->from('orders')->where('id >', 2);
}); 

// (4.orWhere 或查询
$query = $db->table('blog')->orWhere('name', $name)->get(); 

// (5.whereIn   In查询, 
//    orWhereIn  or in 查询 
//    whereNotIn  not In 查询
//    orWhereNotIn or not In 查询
$query = $db->table('blog')->whereIn('name', ['a','b'])->get(); 
$query = $db->table('blog')->orWhereIn('name', ['a','b'])->get(); 
$query = $db->table('blog')->whereNotIn('name', ['a','b'])->get(); 
$query = $db->table('blog')->orWhereNotIn('name', ['a','b'])->get(); 
$query = $db->table('blog')->whereIn('name', function(BaseBuilder $query) {
    return $query->select('job_id')->from('users_jobs')->where('user_id', 3);
})->get(); 

// (6.like   模糊查询, 
//     orLike   or like查询
//     notLike   not like查询
//     orNotLike   or not like查询
// 第三个参数, 可以是'before','after','both', 分别表示 %match, match%, %match%
$query = $db->table('blog')->like('title', 'match')->get(); 
$query = $db->table('blog')->orLike('title', 'match')->get(); 
$query = $db->table('blog')->notLike('title', 'match')->get(); 
$query = $db->table('blog')->orNotLike('title', 'match')->get(); 
$query = $db->table('blog')->like(['title'=>'match'])->get();

// (7.orderBy 排序
$query = $db->table('blog')->select("*")->orderBy("title",'DESC')->get();  

// (10.limit 限制数量
$query = $db->table('blog')->select("*")->limit(10)->get();  
$query = $db->table('blog')->select("*")->limit(10, 20)->get();  

// (8.其他方法
(10.2.groupBy 组排序
$query = $db->table('blog')->select("*")->groupBy("title");  
$query = $db->table('blog')->select("*")->groupBy(["title", "date"]);  

3.Response响应

注意:当前CI 4的版本并没有模块去支持返回json数据,而TP, Laravel 有相应的模块。

<?php

namespace App\Controllers;

class Home extends BaseController
{
 
    public function index()
    { 

//        (1.返回字符串
//        return '222';
        
//        (2.返回json数据(返回的依旧是字符串类型 ,前端需要使用 res = JSON.parse(res) )
//        return array('data'=>'hello');
        
//        返回视图文件
//        (2.return view('templates/list',['data'=>"222"]);
    }
}

6.模板语法
1.route_to反向路由
$routes->get('users/(:id)/gallery(:any)', 'Galleries::showUserGallery/$1/$2',['as' => 'user_gallery']);

//    在视图中通过route_to 传递参数
/*    <a href="<?= route_to('user_gallery', 15, 12) ?>">查看相册</a>*/

2.esc($url,'url')转义

默认情况下,esc() 方法认为要转义的数据会在 HTML 中使用。如果数据打算用于 Javascript、CSS 或 href 属性时,需要不同的转义规则才 能生效。你可以传入转义类型名称作为第二个参数,选择合适的规则。规则支持 ‘html’, ‘js’, ‘css’, ‘url’ 和 ‘attr’:

<a href="<?= esc($url, 'url') ?>" data-foo="<?= esc($bar, 'attr') ?>">Some Link</a>
<script>
        var siteName = '<?= esc($siteName, 'js') ?>';
</script> 
<style>
        body {
                background-color: <?= esc('bgColor', 'css') ?>
        }
</style>
3.extends 继承页面

注意点:对比codeigniter, thinkphp, laravel, 只有 thinkphp 必须通过控制器去访问页面视图

1.被继承的模板 layout.php
   充当内容的占位符。
   <?= $this->renderSection('content') ?>

2.继承的模板 hello.php
  在文件开头使用 
      <?= $this->extend('layout') ?>
  给占位内容填写数据 
   <?= $this->section('content') ?>
   	   <h1>Hello World!</h1>
   <?= $this->endSection() ?>
4.include引入页面
<?= script_tag("public/js/script.js")?>
<?= link_tag("public/js/style.css")?>

// 在文件中引入header
<?=$this->include('header') ?>

5.<?= xxx ?>插值
 <title><?= $title ?></title>
6.foreach 循环遍历
<?php foreach ($data as $key=>$item): ?>

    <li><?= $item ?></li>

<?php endforeach; ?>
7.if 条件分支
<?php if($num==2): ?>
    2222
<?php elseif($num==1): ?>
    1111
<?php endif; ?>
7.Filters过滤器

注意:CI本身没有中间件,但过滤器有相同的功能。

控制器过滤器可以是在控制器运行前或者运行后执行相应的操作,与 事件 不同,你可以非常简单、方便的选择在应用程序的哪个 URI 上应用过滤器。 过滤器可以修改传入的请求,也可以对响应做出修改,从而具有很大的灵活性和功能性。我们可以使用过滤器执行一些共同的常见的任务,例如:

(1.配置过滤器

在app/Config/Filters.php中有它的配置

// $aliases,数组可以将一个简单的名称与一个或多个完整类的路径进行绑定关联,这些完整的类就是需要运行的过滤器:
// 一般只设置这个就行
public $aliases = [
	'isLogin'       => \App\Filters\LoginFilter::class,
        
    'csrf' => \CodeIgniter\Filters\CSRF::class
];

// $globals,这部分允许你定义应用程序中每个请求需要经过的过滤器。 请一定要注意过滤器的数量,因为所有的请求都将经过这些过滤器,过多会导致影响性能。可以在 before 和 after 中添加别名来指定 过滤器:
public $globals = [
        'before' => [
                'csrf',                         // 全部匹配                  
                'csrf' => ['except' => 'api/*'] // 排除匹配
        ],
        'after'  => []
];

// $methods,你可以将过滤器应用于请求的某些方法,例如 POST、GET、PUT等,在数组中使用全部小写的形式指定过滤器名称,与 $globals 或 $filters 属性设置目的不同,这些过滤器全部都是前置过滤器,也就是说都在控制器运行前执行:
public $methods = [
    'post' => ['foo', 'bar'],
    'get'  => ['baz']
]

// filters,这个属性是过滤器别名数组,每个别名可以定义指定 URI 的前置或后置过滤器,
public filters = [
    'foo' => ['before' => ['admin/*'], 'after' => ['users/*']],
    'bar' => ['before' => ['api/*', 'admin/*']]
];

(2.创建过滤器

在app/Filters 文件夹下创建 LoginFilter.php文件

<?php
namespace App\Filters;

use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\Filters\FilterInterface;

use Config\Services;

class LoginFilter implements FilterInterface
{
    // 前置过滤器
    public function before(RequestInterface $request, $arguments = null)
    {
    	// 获取请求的参数 (里面是首字母大写), 下面原来是access-token 
    	$access_token_obj =  (string)$request->headers()['Access-Token'];
        $access_token = preg_replace("/Access-Token\:\s/",'',$access_token_obj,-1);
 
        
        // 监测是否登录
        if (!session()->get('user'))
        {
            return redirect('login');
        }
        
        // 直接返回结果(返回response就被拦截,否则执行后面的程序)
       return Services::response()->setBody(json_encode( ['msg'=>'token错误!无法访问','code'=>403]));
    }

    //--------------------------------------------------------------------
    // 后置过滤器(不能省略)
    public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
    {
        // Do something here
    }
}

(3.路由过滤


$routes->get('/index', 'Home::index',['filter'=>'isLogin']);
   
1.session 认证

(1.配置session

在app/Config/App.php里面

// 存活时间
public $sessionExpiration = 7200;

(2.使用session

方法一:辅助函数(建议)
设置会话
session()->set('some_name', 'some_value');

获取会话(对于 get() 方法,如果你要访问的项目不存在,返回 NULL。) 
session()->get('item');

检查会话
session()->has('some_name');

移除当前会话
session()->remove('some_name');

清除会话
session()->destroy();


方法二:Services下的session (不建议)
$session = \Config\Services::session();

2.csrf 跨站防御
方法一:
<input type="hidden" name="<?php echo csrf_token();?>" value="<?php echo csrf_hash();?>">

方法二:
<?= csrf_field() ?>

csrf_test_name: xxxxxxxxxxxxxxxx
3.encrypter加密

(1.配置文件

app/Config/Encryption.php 中的配置加密密钥。


// 方法 一:手动设置密钥(建议)
echo md5(uniqid());     
// 例如  82043c0635878d36610283d4e57f32da
// 在配置文件里面设置
public $key = '';
// 创建加密对象实例
$encrypter = \Config\Services::encrypter();


// 方法二 :也可以启动config配置  
use CodeIgniter\Encryption\Encryption;
$config = new \Config\Encryption();
// 创建密钥,将被分配一个32字节(256位)随机密钥 
$config->key    =  Encryption::createKey(32);
$config->driver = 'OpenSSL';
// 创建加密对象实例
$encrypter = \Config\Services::encrypter($config);

(2.使用方法

// 注意:直接加密的结果是二进制数据,容易在复制的时候出错,所以需要把结果转换 成base64格式的数据

// 加密
$originTxt = '123456';
$encrypText = base64_encode($encrypter->encrypt($originTxt));

// 解密
$newText = $encrypter->decrypt(base64_decode($encrypText)); 
4.pager分页器(???)
//$pager = \Config\Services::pager();

public function index()
{
    $model = new \App\Models\UserModel();

    $data = [
        'users' => $model->paginate(10),
        'pager' => $model->pager
    ];

    echo view('users/index', $data);
}

创建新视图时,只需要创建生成分页链接本身所需的代码。你不应该创建不必要的包装 div,因为它可能会在多个地方使用,并且这会限制它们的用途。这里通过向你展示现有的 default_full 模板,来演示创建新视图:

<?php $pager->setSurroundCount(2) ?>

<nav aria-label="Page navigation">
    <ul class="pagination">
    <?php if ($pager->hasPrevious()) : ?>
        <li>
            <a href="<?= $pager->getFirst() ?>" aria-label="First">
                <span aria-hidden="true">First</span>
            </a>
        </li>
        <li>
            <a href="<?= $pager->getPrevious() ?>" aria-label="Previous">
                <span aria-hidden="true">&laquo;</span>
            </a>
        </li>
    <?php endif ?>

    <?php foreach ($pager->links() as $link) : ?>
        <li <?= $link['active'] ? 'class="active"' : '' ?>>
            <a href="<?= $link['uri'] ?>">
                <?= $link['title'] ?>
            </a>
        </li>
    <?php endforeach ?>

    <?php if ($pager->hasNext()) : ?>
        <li>
            <a href="<?= $pager->getNext() ?>" aria-label="Previous">
                <span aria-hidden="true">&raquo;</span>
            </a>
        </li>
        <li>
            <a href="<?= $pager->getLast() ?>" aria-label="Last">
                <span aria-hidden="true">Last</span>
            </a>
        </li>
    <?php endif ?>
    </ul>
</nav>
5.Validation验证类
$validation =  \Config\Services::validation();


public $signup = [
    'username'     => 'required',
    'password'     => 'required',
    'pass_confirm' => 'required|matches[password]',
    'email'        => 'required|valid_email'
];

public $signup_errors = [
    'username' => [
        'required'    => '请输入用户名',
    ],
    'email'    => [
        'valid_email' => '邮箱格式不正确.'
    ]
];

// 设置规则
$validation->setRules($signup,$signup_errors);
// 检查错误
$errors = $validation->getErrors();
if($errors && count($errors)){
    echo $errors;
}
8.分离项目过滤
1.cors 跨域

安全类包含了一些方法,用于帮助保护你的网站,以免受到跨站请求伪造(CSRF)的攻击。

(1.创建过滤器

app/Filters/CorsFilter.php文件

<?php

namespace App\Filters;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\Filters\FilterInterface;

class CorsFilter implements FilterInterface
{
    // 前置过滤器
    public function before(RequestInterface $request, $arguments = null)
    {
        $response = service('response');
        $response->setHeader('Access-Control-Allow-Origin', '*');

    }

    //--------------------------------------------------------------------
    // 后置过滤器
    public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
    {
        // Do something here

    }
}

(2.配置全局过滤

在 app/Config/Filters.php文件下,打开以下内容


public $aliases = [ 
	'cors'  => \App\Filters\CorsFilter::class,
];

public $globals = [
    'before' => [
    	'cors'  // cors 跨域
    ]
];
2.php-jwt 认证

(1.安装模块

composer require firebase/php-jwt (--ignore-platform-reqs)

(2.创建JWT过滤器

在 app/Filters下创建JWTFilter中间件,填写以下内容

app/Filters/JWTFilter.php文件

注意: static 静态方法,可以使用 类名访问 JWTFilter::signToken

<?php

namespace App\Filters;

use Firebase\JWT\JWT;
use Firebase\JWT\Key; 

class JWTFilter
{
    /**
     * 生成验签
     * @param $uid 用户id
     * @return mixed
     */
    // 静态方法,可以使用 类名访问 JWTMiddleware::signToken

    public static function signToken($uid){
        $key='abcdefg';         //自定义的一个随机字串用户于加密中常用的 盐  salt
        $token=array(
            "iss"=>$key,        //签发者 可以为空
            "aud"=>'',          //面象的用户,可以为空
            "iat"=>time(),      //签发时间
            "nbf"=>time(),      //在什么时候jwt开始生效
            "exp"=> time()+15*24*60*60,  //token 过期时间
            "data"=>[           //记录的uid的信息
                'uid'=>$uid,
            ]
        );
        $jwt = JWT::encode($token, $key, "HS256");  //生成了 token
        return $jwt;
    }

    /**
     * 验证token
     * @param $token
     * @return array|int[]
     */
    public static function parseToken($token){
        $key='abcdefg';     //自定义的一个随机字串用户于加密中常用的 盐  salt
        $res['status'] = false;
        try {
            JWT::$leeway    = 60;//当前时间减去60,把时间留点余地
            $decoded        = JWT::decode($token, new Key($key, 'HS256')); //HS256方式,这里要和签发的时候对应
            $arr            = (array)$decoded;
            $res['status']  = true;
            $res['data'] = $arr['data'];
            return $res;

        } catch(\Firebase\JWT\SignatureInvalidException $e) { //签名不正确
            $res['info']    = "签名不正确";
        }catch(\Firebase\JWT\BeforeValidException $e) { // 签名在某个时间点之后才能用
            $res['info']    = "token失效";
        }catch(\Firebase\JWT\ExpiredException $e) { // token过期
            $res['info']    = "token过期";
        } 
        return $res;
    }
}

(3.在控制器中使用

注意:这jwt需要配合 第10条创建的AuthFilter过滤器, 进行路由的拦截。


use App\Filters\JWTFilter;

1.生成token 
$token = JWTFilter::signToken($res['id']);
   

2.解析token
$token = JWTFilter::parseToken($token);
// 返回数组  Array ( [uid] => 123,[status]=>true ) 

(4.配置路由过滤器

1.在app/Config/Filters.php
    public $aliases = [
         ...
        'auth'       => \App\Filters\AuthFilter::class,
		 ...
    ];

2.在路由上配置过滤器
  $routes->get('logout', 'LoginController::logout',['filter'=>'auth']);

(5.请求拦截Auth过滤器

<?php
namespace App\Filters;

use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\Filters\FilterInterface;


use App\Models\UserMsgModel;
use App\Filters\JWTFilter;

use Config\Services;

class AuthFilter implements FilterInterface
{
    // 解析token
    // 获取用户id $user_id = AuthLogin::getAccessToken($request);
    public static function getAccessToken($request){
        // 在前后端分离的情况下,不要使用session,因为session无效。
//        $access_token =  $request->headers()['Access-Token'];
        $access_token_obj =  (string)$request->headers()['Access-Token'];
        $access_token = preg_replace("/Access-Token\:\s/",'',$access_token_obj,-1);

        // 去除bearer-
        $access_token = str_replace('bearer-','',$access_token);
         // 解析token
        $pre_user = JWTFilter::parseToken($access_token);

        if($pre_user['status'] && $access_token ) {
            // 返回解析的用户uid;
            // $pre_user['data']['uid']无效
            return $pre_user['data']->uid;
        }else {
            return false;
        }
    }

    // 前置过滤器
    public function before(RequestInterface $request, $arguments = null)
    {
        $userMsgModel = new UserMsgModel();

        $pre_user_id =  AuthFilter::getAccessToken($request);

        if($pre_user_id){
            // 判断帐号是否存在,(并且没有注销)
            $res = $userMsgModel->where('id',$pre_user_id )->find();
            if($res && $res[0]['isDelete'] != '1'){
                $res = $res[0];
                // 判断帐号是否登录token
                if($res['token']){
                    // 不进行拦截
                }else{
                    return Services::response()->setBody( json_encode(['msg'=>'当前未登录!请进行登录','code'=>403]));
                }
            }else{
                return Services::response()->setBody( json_encode(['msg'=>'帐号不存在','code'=>403]));
            }
        }else{
            return Services::response()->setBody(json_encode( ['msg'=>'token错误!无法访问','code'=>403]));
        }
    }

    //--------------------------------------------------------------------
    // 后置过滤器(不能省略)
    public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
    {
        // Do something here
    }
}
9.功能模块
1.file上传文件(原生)
public  upload(){

 		$files = $request->getFiles()
 		
	    $res = $files->hasFile("image")   // 检查是否有文件
 
        $file = $files ->getFile('image');  // 获取文件
 
        $name = $file->getRandomName();
 
        $file->move('/path/to/dir', $name);   // 保存文件

        echo $file->getSize('mb');      // 1.23
        echo $file->getExtension();     // jpg
        echo $file->getType();          // image/jpg
}
2.download文件下载(x)
$response = $this->response;

1.下载文本
$data = 'Here is some text!';
$name = 'mytext.txt';
$response->download($name, $data);

2.下载图片
// photo.jpg 的内容将被自动读取
$response->download('/path/to/photo.jpg', NULL);

3.HTTP缓存(???)

默认情况下,所有通过 CodeIgniter 发送的响应都是关闭了 HTTP 缓存的。 但在实际应用中,情况千变万化,无法简单的设置一个合适的默认值,除非关闭它, 不过,可以通过 setCache() 方法设置你需要的缓存的值。这非常简单

$options = [
        'max-age'  => 300,
        's-maxage' => 900,
        'etag'     => 'abcde',
];
$this->response->setCache($options);
4.内容安全策略(CSP)

对XSS攻击的最佳保护方式之一是在站点上实施内容安全策略。

这迫使你将从你网站的 HTML 中载入的每一个内容来源列入白名单中,包括图片,样式表,JavaScript文件等。浏览器将拒绝白名单外的的内容。这个白名单在响应的 Content-Security-Policy 标头中创建,并且有多种配置方式。

(1.启动CSP

默认情况下,CSP策略是禁用的。想要在应用程序中启用CSP,修改 application/Config/App.php 中的 CSPEnabled 的值

public $CSPEnabled = true;

(2.配置白名单

在 application/Config/ContentSecurityPolicy.php 中设置的值应用于这个实例,如果在运行时没有修改,那么将会发送正确的格式化后的标题,并且完成所有操作。

$reportOnly = true;

$response->CSP->reportOnly($reportOnly);
$response->CSP->setBaseURI('example.com', true);
$response->CSP->setDefaultSrc('cdn.example.com', $reportOnly);
$response->CSP->setReportURI('http://example.com/csp/reports');
$response->CSP->setSandbox(true, ['allow-forms', 'allow-scripts']);
$response->CSP->upgradeInsecureRequests(true);
$response->CSP->addChildSrc('https://youtube.com', $reportOnly);
$response->CSP->addConnectSrc('https://*.facebook.com', $reportOnly);
$response->CSP->addFontSrc('fonts.example.com', $reportOnly);
$response->CSP->addFormAction('self', $reportOnly);
$response->CSP->addFrameAncestor('none', $reportOnly);
$response->CSP->addImageSrc('cdn.example.com', $reportOnly);
$response->CSP->addMediaSrc('cdn.example.com', $reportOnly);
$response->CSP->addObjectSrc('cdn.example.com', $reportOnly);
$response->CSP->addPluginType('application/pdf', $reportOnly);
$response->CSP->addScriptSrc('scripts.example.com', $reportOnly);
$response->CSP->addStyleSrc('css.example.com', $reportOnly);

(3.安全脚本

可以设置一个网站不保护自己的页面上的内联脚本和样式,因为这可能是用户生成的内容的结果。 为了防止这种情况,CSP 允许你再

你可以在代码中包含 {csp-style-nonce} 或 {csp-script-nonce} 占位符,程序将会自动为你处理

// Original
<script {csp-script-nonce}>
    console.log("Script won't run as it doesn't contain a nonce attribute");
</script>

// OR
<style {csp-style-nonce}>
        . . .
</style>
10.框架比较
1.TP,CI,Laravel
  1. Laravel功能齐全,安全性高,MVC最典型的架构。CI也是如此,TP较为不安全
  2. CI在安全和缓存上,不管是在http请求,还是数据库查询,都有大量的配置。
  3. TP最轻量,可以灵活根据业务,对框架进行二次开发。
  4. CI4, TP6才采用Composer进行框架的安装,起步更晚。对于这 两个框架,也许多应用模式才是这两个框架最大的亮点。
  5. Laravel 框架占据最大的比重,在国外CI也是非常流行的框架,TP只有在国内,才受到比较大的欢迎。CI的社区并没有TP这么广泛,CI的居中位置并没有让它在国内市场发展的非常好。其中CI的硬伤是框架的许多部分做的并没有laravel那么好,比如:没有通过命令行创建模型,控制器,还有 路由的封装也不是很好。

3.codeIgniter3原生网站

1.创建项目(CI.3)

(1.CodeIgniter3

1.创建CIproject项目
(1.创建项目
	composer create-project codeigniter/framework=3.1.x FirstProject     
(2.配置文件config
   在application/config/config.php 修改为一下内容
   (2.1 安装模块路径
   $config['composer_autoload'] = 'vendor/autoload.php'; 

2.运行项目
 通过wampserver,或nginx 启动

(1.方法一:配置Nginx (失败,因为本地Nginx没有php解析器)
    在conf/nginx.conf文件配置 
    location / {
        try_files $uri $uri/ /index.php/$args;
    } 
(2.方法二:配置wampserver  
    (2.1 在根目录配置
    先对www目录的权限设置所有人可以访问 ,
    再把FirstProject项目文件放在 C:\wamp64\www\ 根目录文件夹
    浏览器访问:http://localhost:8080/FirstProject/index.php/welcome/index
    浏览器访问:http://ci.php.com:8080/
    
    (2.2 在非根目录配置
    先对www目录的权限设置所有人可以访问,
    因为脱离了根目录,所以使用路径访问无效。(下方访问,项目会出现404)
    例如:http://localhost:8080/php_demo/giteeWarehouse/study-php/2.codeIgniter%E5%AD%A6%E4%B9%A0/FirstProject/index.php
    只有通过本地的DNS域名,才可以正常访问项目
    浏览器访问:http://ci.php.com:8080/
    
(3.方法三:配置phpStudy (未知,略)
    弊端是mysql,并不是使用本地的mysql,而是phpStudy内置的mysql.


3.使用DNS域名 
   (2.方法二: 配置wampserver(apache)
     在本机的hosts添加:   127.0.0.1 ci.php.com
     在wampserver的Apache/httpd-vhosts.conf添加:
       (1.根目录的项目
       <VirtualHost *:8080>
           ServerName ci.php.com
           ServerAlias ci.php.com 
           DocumentRoot "${INSTALL_DIR}/www/FirstProject"
           <Directory "${INSTALL_DIR}/www/FirstProject/">
           		Options +Indexes +Includes +FollowSymLinks +MultiViews
           		AllowOverride All
           		Require local
           </Directory>
		</VirtualHost> 
		
		(2.非根目录的项目
        <VirtualHost *:8080>
          ServerName ci.php.com
          ServerAlias ci.php.com    
          DocumentRoot "${INSTALL_DIR}/www/php_demo/giteeWarehouse/study-php/2.codeIgniter学习/FirstProject"
          <Directory "${INSTALL_DIR}/www/php_demo/giteeWarehouse/study-php/2.codeIgniter学习/FirstProject/">
            Options +Indexes +Includes +FollowSymLinks +MultiViews
            AllowOverride All
            Require local
          </Directory>
        </VirtualHost> 

    浏览器访问: http://ci.php.com:8080/


4.去除index.php入口文件(Apache)
     在项目根目录下,创建.htaccess
        <IfModule mod_rewrite.c>
             RewriteEngine on
             RewriteCond %{REQUEST_FILENAME} !-d
             RewriteCond %{REQUEST_FILENAME} !-f
             RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
        </IfModule>

     在wampserver(Apache) 的httpd.conf, 取消下面这行的“#”注释
         LoadModule rewrite module modules/mod_rewrite.so

     浏览器访问:http://ci.php.com:8080/mytest
     浏览器访问:http://ci.php.com:8080/index.php/mytest


注意:

  1. 官方建议将 vendor 目录放在 application 目录中,项目迁移时复制整个 application 目录即可,比较方便。这时可以直接将上面的选项设置为 TRUE,CodeIgniter 框架会使用 application/vendor/autoload.php 这个默认路径。

  2. 但我们刚才通过 Composer 命令将依赖包安装在了项目根目录下,所以要自行填入路径 vendor/autoload.php

(2.CodeIgniter3项目结构

|-----index.php 入口文件 

|-----system 框架程序目录

|-----application 项目目录

|----------routes.php 路由配置文件

|----------controllers 控制器目录 

|----------models 模型目录

|----------views 视图目录 


2.routes路由
1.php网站

(1.nginx配置

指向index.php文件就可以

(2.index.php主文件

<?php
   // 这个入口文件
   header("Content-Type:text/html;charset=utf-8");

   // 控制器
   $c = $_GET['c'];

   // 包含控制器
   include './controllers/'.$c.'Controller.php';

   // 实例化控制器对象
   $className = $c.'Controller';
   $controller = new $className;

   // 方法名
   $a = $_GET['a'];

   // 调用方法
   $controller->$a();
 

(3.控制器

在 /controllers/UserController.php文件内容

<?php
 class UserController{
 	public function index(){
 		echo '这是User控制器';
 		
 		include './views/User/index.php'
	}
 }

(4.视图文件

在 /views/User/index.php文件内容

<!doctype html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport"
		  content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title>Document</title>
</head>
<body>
   这是视图文件
</body>
</html>

(5.浏览器访问

 
http://localhost:8080/php_demo/giteeWarehouse/study-php/2.codeIgniter%E5%AD%A6%E4%B9%A0/CodeIgniter-3.1.5/index.php?c=User&a=index

2.codeIgniter3网站

(1.基本规则

注意:

  1. 控制器文件名称大写,在路由中小写

  2. 有时候你可能希望某些方法不能被公开访问,要实现这点,只要简单的将方法声明为 private 或 protected , 这样这个方法就不能被 URL 访问到了

  3. 一般情况下,一个 URL 字符串和它对应的控制器中类和方法是一一对应的关系。 URL 中的每一段通常遵循下面的规则:

语法:
http://example.com/class/function/

例如:
http://localhost:8080/FirstProject/index.php/welcome/index

(2.定义路由

(1.在application/config/routes.php文件中定义路由规则

$route['mytest'] = 'welcome/test';

(2.在application/controllers/Welcome.php控制器中添加函数

 	public function test()
	{
		echo 'test';
	}

(3.浏览器中可以两种方式访问

http://ci.php.com:8080/index.php/mytest

http://ci.php.com:8080/index.php/welcome/test

(3.封装路由

(1.在application/config/routes.php文件中引入文件
    // 自定义路由目录
    //(codeigniter3的路由是一维数组,codeigniter的路由是对象)
    // 对象存在引用,而二维数组必须要返回数组
    require(APPPATH."routes/web.php");
    $route = _routes($route);

(2.在application/routes/web.php 文件添加(新建立文件,文件夹)
    <?php 
    function _routes($route){
        $route['mytest'] = 'welcome/test'; 
        return $route;
    }

(3.浏览器访问 

http://ci.php.com:8080/index.php/mytest
3.url 基本语法
在视图中使用注意:表单提交的目标 /index.php/user/insert
注意: 在返回视图view前,需要   $this->load->helper('url');

1.site_url("控制器/别名") 路由别名;
<form action="/index.php/user/insert">
<form action=" <?php echo site_url('user/insenrt'); ?> ">
     

2.base_url() 根路由地址
在application同级目录下,可以建立uploads文件夹,可以被浏览器访问
<img src="/uploads/a.jpg"/>
<img src=" <?php echo base_url(); ?>/uploads/a.jpg"/>


3.$route 路由规则
$route['show/[\d]{6}/([\d+])\.html'] = 'welcome/index'

4.输出语法
1.项目中有很多$this->load->xxxx, 这种的$this 指向的还是比较复杂


2.项目中不能使用 dd(xxxx) 输出结果; 取代的可以是  print_r('xxx'); exit;


3.多应用模式

管理你的应用程序 — CodeIgniter 3.1.5 中文手册|用户手册|用户指南|中文文档

默认情况下,CodeIgniter 假设你只有一个应用程序,被放置在 application/ 目录下。但是,你完全可以拥有多个程序并让 它们共享一份 CodeIgniter 。你甚至也可以对你的应用程序目录 改名,或将其移到其他的位置。

(1.创建多个应用

如果你希望在一个 CodeIgniter 下管理多个不同的应用程序,只需简单的 将 application 目录下的所有文件放置到每个应用程序独立的子目录下即可。

例如,你要创建两个应用程序:“foo” 和 “bar”,你可以像下面这样组织你的目录结构:

applications/foo/
applications/foo/config/
applications/foo/controllers/
applications/foo/libraries/
applications/foo/models/
applications/foo/views/
applications/bar/
applications/bar/config/
applications/bar/controllers/
applications/bar/libraries/
applications/bar/models/
applications/bar/views/

(2.更改入口文件

要选择使用某个应用程序时,你需要打开 index.php 文件然后设置 $application_folder 变量。例如,选择使用 “foo” 这个应用,你可以这样:


$application_folder = 'applications/foo';

(3.新建立入口文件

因为一个应用只能使用一个入口文件,但可以设置多个入口文件index2.php,并配置服务器的文件。

多应用模式下,如果是非www根目录下运行,并且还要使用DNS + 省略入口文件,还会有点比较麻烦。


http://localhost:8080/FirstWeb/index1.php/welcome/index

http://localhost:8080/FirstWeb/index2.php/welcome/index
4.controllers控制器

application/controllers/Welcome.php文件

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Welcome extends CI_Controller {
 
	public function index()
	{
		$this->load->view('welcome_message');
	}
 	public function test()
	{
		echo 'test';
	}
}

(1.不能被浏览器访问的

1.非public 修饰的函数

2.方法名以下划线“_”开头


(2.基类控制器

  1. 继承CI_Controller,所有需要新的控制器,就继承它。

  2. 这是对CI控制器的扩展,system的模块扩展,就在application对应的文件建立新文件就可以。

  3. MY_前缀是 application/config/config.php里面配置的前缀, $config[‘subclass_prefix’]=‘MY_’;

在application/core/MY_Controller.php文件(新建)

<?
   class MY_Controller extends CI_Controller{
       public function __construct(){
           parent::__construct();
           
           //  权限认证部分
       }
   }


// 当其他控制器继承MY_Controller, 则对应的控制器就会经过基类控制器的监控 

(3.子类控制器

如果你正在构建一个比较大的应用,那么将控制器放到子目录下进行组织可能会方便一点。CodeIgniter 也可以实现这一点。

你只需要简单的在 application/controllers/ 目录下创建新的目录,并将控制器文件放到子目录下。

当使用该功能时,URI 的第一段必须指定目录,例如,假设你在如下位置有一个控制器:

application/controllers/products/Shoes.php

为了调用该控制器,你的 URI 应该像下面这样:

example.com/index.php/products/shoes/show/123
5.views视图

(1.加载视图

laravel视图是引入了blade模板引擎,需要使用. 来查找视图


$this->load->view('user/index');


$this->load->view('user/index',['data'=>'555']);

(2.分配变量


$this->assign('key','value');

$this->load->vars('title','这是标题')

(3.缓存视图


将下面的代码放到任何一个控制器的方法内,你就可以开启缓存了:

$this->output->cache($n);

其中 $n 是缓存更新的时间(单位分钟),上面的代码可以放在方法的任何位置,它出现的顺序对缓存没有影响, 所以你可以把它放到任何你认为合理的地方。一旦该代码被放在方法内, 你的页面就开始被缓存了。
6.database数据库

(1.配置数据库

在application/config/database.php文件里


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

(2.db自动加载

在application/config/autoload.php文件中


$autoload['libraries'] = array('database')
则可以省略装载的部分: $this->load->database()

(3.访问数据库

// 装载数据库操作类
$this->load->database()

$res = $this->db->query("select * from user");
$list = $res->result_array();

7.models模型(x)

application/models/User.php

(1.定义模型

<?
    class User_model extends CI_Model{
        public function getAll(){
            // 加载模型
            return  $this->db->select("id,name")->from("test")->where("id>",3)
                ->limit(2,3)->order_by('id','DESC')->get()->result();
        }
    }
 

(2.控制器使用(x)

<?
   class Welcome extends MY_Model{
      public function index(){
           // 加载模型
           $this->load->model('User_model');
           $list = $this->User_model->getAll();
           // 取别名
           $this->load->model('User_model','user');
           $list = $this->user->getAll();
      }
   }


8.data数据采集
1.form表单数据

注意:表单提交的目标 /index.php/xxxx/xxxx

1.路径参数
// 获取uri 参数位的具体段的路径参数
$this->uri->segment(index)
入口文件:php/controller/function/args1/args2

也可以在方法定义形参
public function test($id,$name){
     ....
}

2.get参数
$input = $this->input->get('name');

3.post参数
$input = $this->input->post("username")

4.其他参数
$input = $this->input->server("DOCUMENT_ROOT")
 


2.mysql数据库

(1.原始方法

// 装载数据库操作类
$this->load->database()

// 执行sql语句
$res = $this->db->query("select * from user");
$res = $this->db->query("select * from user where=?",$id);

// 返回的是对象
$list = $res->result();
// 返回的是数组
$list = $res->result_array();
// 返回影响的行
$res = $this->db->affected_rows();
$res = $this->db->insert_id();



(2.AR模型方法(建议)

在application/config/database.php文件里(ci 3 已经废弃)


$active_record = TRUE;

1.查询数据
$res = $this->db->select("name,password")->from("user")->where("id>",3)
		->limit(2,3)->order_by('id','DESC')->get();
$query = $res->result();

2.添加数据
$res = $this->db->insert('user',$data)

3.修改数据
$res = $this->db->update('user',$data,['id'=>3])

4.删除数据
$res = $this->db->delete('user',['id'=>3])
3.response 响应

public function index(){
   // 返回视图
   $this->load->view('welcome_message');
   
   // 返回字符串
   echo '2222';
}

9.功能模块
1.pagination分页

(1.定义分页逻辑

public function index(){
   // 装载类文件
   $this->load->library('pagination');
   $this->load->helper('url');
   // 每页显示10条数据
   $config['per_page']=10;
   $config['total_rows']=100;
   $config['base_url']=base_url();
   // 显示的格式
   $config['first_link']='首页';
   $config['next_link']='下一页';
   $config['uri_segment']=3; 
   
   $this->pagination->initialize($config);
   $data_list = $this->pagination->create_links();
}  

(2.分页结果


<?=$data_list?>
2.upload文件上传

(1.view视图页面


<form method="post" enctype="multipart/form-data">
    <input type="file" name="file"/>
    <input type="submit" value="上传"/>
</form>

(2.控制器

在 根目录下建立uploads文件夹

public  function upload(){
       $config['upload_path'] = './uploads/';
       $config['allowed_types'] = 'gif/png/jpg/jpeg';
       // 文件名称
       $config['file_name'] = uniqid();
       
       $this->load->library('upload',$config);
       $this->upload->do_upload('file');
      
      $new_filename = $this->upload->data()['file_name'];
}


3.Session 认证

(1.配置session

在 application/config/config.php文件 里面

// 注意不要定义123456为加密密钥
$config['encryption_key'] = 'asdasdfdfsfsdfsfd'

$config [ 'sess_cookie_name'] = 'ci_session' ;
$config [ 'sess_expiration' ] = 7200;
$config [ 'sess_expire_on_close' ] = FALSE;
$config [ 'sess_encrypt_cookie' ] = TRUE;
$config [ 'sess_use_database '] = FALSE;
$config [ 'sess_table_name'] = 'ci_sessions';
$config [ 'sess_match_ip' ] = FALSE;
$config [ 'sess_match_useragent'] = TRUE;
$config [ 'sess_time_to__update'] = 300;


// 在控制器中 可以使用,获取随机的md5加密值
echo md5(uniqid());

(2.使用session

public function login(){
    $this->load->library("session");
    $user = ['id'=>3,'name'='jack']
    
    // 设置session
    $this->session->set_userdata('user',$user);
}

public function check_login(){
    $this->load->library('session');
    // 获取session
    $user = $this->session->userdata('user');
}

4.captcha 验证码

(1.创建验证码

在application同级穿件captcha文件夹

public create_cap(){
    $this->load->helper('url');
    $this->load->helper('captcha');
    $data = [
    	'word'=>rand(1000,9999),
        'img_path'=>'./captcha/',
        'img_url'=>base_url(),
        'img_width'=>'150',
        'img_height'=>'80',
        'expiration'=>7200  // 过期时间,过期就自动删除图片
    ]
    $captcha_obj = create_captcha($data);
    // 生成验证码
    $captcha_img = $captcha_obj['image'];
    // 验证码数字
    $catcha_word = $captcha_obj['word'];
}


(2.显示验证码图片


// 下面是img标签
<?=$captcha_img?>

5.validate表单验证

**(1.配置 中文 **

在application/config/config.php文件


$config['language'] = 'zh_cn';

(2.表单验证


public function insert(){
    $this->load->library('form_validation');
    
    // 设置验证规则
    $this->form_validation->set_rules('name','用户名','required');
    $this->form_validation->set_rules('name','邮箱','valid_email');
    
    $res = $this->form_validation->run();
    
    if(!res){
       // $errors = validation_errors();
       // $errors = form_error('name');
       return $this->load->view('user/insert');
    }
}

(3.表单页面


<form>
	// 所有错误
    <?php echo validation_errors() ?>

    <input name='name' type='text' />
    <?php echo  form_error('name') ?>
    // 不换行显示错误
    <?php echo  form_error('name','<span>','</span>') ?>
   
   // 也可以手动重置表单
    <?php echo  set_value('name') ?>
</form>
 类似资料: