吴孟达


项目地址:https://github.com/ayuayue/php-frame

制作一个PHP简易框架(一)–准备工作

制作一个PHP简易框架(二)– 引入容器

制作一个PHP简易框架(三)– 信息调试

制作一个PHP简易框架(四)– 路由系统

制作一个PHP简易框架(五)– 响应

制作一个PHP简易框架(六)– 视图模板

制作一个PHP简易框架(七)– 路由及路径优化

制作一个PHP简易框架(八)– 配置中心

制作一个PHP简易框架(九)– ORM

制作一个PHP简易框架(十)– Session and Cookie


状态管理

对于一个 web 系统来说,一个用户的状态管理基本是必须的,但由于 http 连接是无法保存状态的,所以 session , cookie 便被设计了出来。

php 默认的 session 存储方式是 文件存储。但对于现代的大型应用,一般都是将 session 存入到 db ,redis 中进行持久化。

项目开启 Session

1
2
3
# bootstrap/app.php
session_save_path(__DIR__ . '../storage/sessions');
session_start();

测试是否开启成功。

1
2
3
4
5
6
# app\Controller\HomeController.php
public function index($request)
    {
        $_SESSION['name'] = config('name');
        dump($_SESSION['name']);
    }

如果获取到 session 说明开启成功。

定义 session 接口

sessin 的存储方式因项目需求可能会改变,所以要定义一个统一的接口,用来规范每个存储类需要完成的操作。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# app\Service\Session\SessionInterface.php
<?php

namespace App\Service;

interface SessionInterface
{
    public function has($key);

    public function set($key,$value);

    public function get($key,$value);

    public function del(...$key);
}

定义文件存储方式,实现接口

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# app\Serice\Session\FileSession.php
<?php


namespace App\Service\Session;

class FileSession implements SessionInterface
{

    public function has($key)
    {
        return isset($_SESSION[$key]) && !empty($key);
    }

    public function set($key, $value = null)
    {
        if(is_array($key)){
            foreach ($key as $k=>$v){
                $_SESSION[$k] = $v;
            }
        }else{
            $_SESSION[$key] = $value;
        }
    }

    public function get($key, $default = null)
    {
        if ($this->has($key)){
            return $_SESSION[$key];
        }
        if ($default != null){
            $_SESSION[$key] = $default;
            return $default;
        }else{
            return $default;
        }
    }

    public function del(...$key)
    {
        foreach($key as $v){
             unset($_SESSION[$v])
        }
    }
}

创建 Session 服务提供者

注册到容器中,使用容器统一管理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# app\Providers\SessionServiceProvider.php
<?php


namespace App\Providers;


use App\Service\Session\FileSession;
use League\Container\ServiceProvider\AbstractServiceProvider;

class SessionServiceProvider extends AbstractServiceProvider
{
    protected $provides = [
        'session'
    ];
    public function register()
    {
        $container = $this->getContainer();
        $container->add('session',function(){
            return new FileSession();
        });
    }
}

注册到容器中

1
2
3
4
5
6
7
# config/app.php
'providers' => [
        App\Providers\AppServiceProvider::class,
        App\Providers\ViewServiceProvider::class,
        App\Providers\DatabaseServiceProvider::class,
        App\Providers\SessionServiceProvider::class,
    ]

调用测试

1
2
3
4
5
6
7
8
9
# app\Controller\HomeController.php
class HomeController
{
    public function index($request)
    {
        dump(app('session')->get('name'));
        return view('index.twig', compact('user'));
    }
}

定义助手函数

1
2
3
4
5
6
7
# helpers.php
if (!function_exists('session')) {
    function session()
    {
        return app('session');
    }

测试

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# app\Controllers\HomeController.php
class HomeController
{
    public function index($request)
    {
        dump(session()->get('name'));
        session()->del('name');
        return view('index.twig', compact('user'));
    }
}

有了 session ,就少不了 cookie ,下面来封装 cookie 的方法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# app\Service\Cookie\Cookie.php
<?php


namespace App\Service\Cookie;


class Cookie
{
    protected $path = '/';
    protected $domain;
    protected $secure = false;
    protected $httponly = true;
    public function set($key,$value = null,$minutes = 120)
    {
        $expires = time() + $minutes *60;
        if (is_array($key)){
            foreach ($key as $k => $v){
                setcookie($k,$v,$expires,$this->path,$this->domain,$this->secure,$this->httponly);
            }
        }else{
            setcookie($key,$value,$expires,$this->path,$this->domain,$this->secure,$this->httponly);
        }
    }
    public function has($key)
    {
        return isset($_COOKIE[$key]) && !empty($key);
    }

    public function get($key,$default = null)
    {
        if ($this->has($key)){
            return $_COOKIE[$key];
        }
        if ($default){
            $this->set($key,$default);
            return $default;
        }else{
            return $default;
        }
    }


    public function forever($key,$value)
    {
        $this->set($key,$value,-3600000000);
    }

    public function del(...$key)
    {
        foreach($key as $v){
            $this->set($v);
        }
    }
}

创建服务提供者并注册到容器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# app\Providers\CookieServiceProvider.php
<?php


namespace App\Providers;


use App\Service\Cookie\Cookie;
use League\Container\ServiceProvider\AbstractServiceProvider;

class CookieServiceProvider extends AbstractServiceProvider
{
    protected $provides = [
        'cookie'
    ];
    public function register()
    {
        $container = $this->getContainer();
        $container->add('cookie',function(){
           return new Cookie();
        });
    }
}
1
2
3
4
5
6
7
8
# config/app.php
'providers' => [
        App\Providers\AppServiceProvider::class,
        App\Providers\ViewServiceProvider::class,
        App\Providers\DatabaseServiceProvider::class,
        App\Providers\SessionServiceProvider::class,
        App\Providers\CookieServiceProvider::class,
    ]

创建助手函数

1
2
3
4
5
6
7
8
# helpers.php
if (!function_exists('cookie')) {
    function cookie()
    {
        return app('cookie');
    }
}

测试

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# app\Controllers\HomeController.php
class HomeController
{
    public function index($request)
    {
        cookie()->set([
            'name'=>'1',
            'a'=>1
        ]);
        cookie()->del('a','name','age');
        $user = 123;
        return view('index.twig', compact('user'));
    }
}

系列完结。

后面有时间可能还会增加第二阶段的文章。主要包括

  1. 用户
  2. 数据验证
  3. 异常处理
  4. 中间件
  5. 网络安全
  6. 重定向
  7. CSRF