[PHP+ci4] codeignitor4 Cache 及 Session 使用 memcached

URL Link //n.sfs.tw/16398

2024-04-08 13:04:32 By 張○○

Codeignitor4(以下全稱為ci4) 自帶提供memcache,設置上非常方便,其實ci3上就有memcache,但是因為 selinux的關係,我一直試不成功,所以放棄。

memcache是使用記憶體當空間給session或cache使用,7版以前的php使用的是Memcache類別,8版使用 Memcached類別,除了名稱多了一個 d以外,裡面的方法都不一樣。

ci4上設置有兩個部分,一是修改cache另一個是修改session的設置,兩者可擇一設置,session的部分如果要使用memcache的話,需安裝 php-memcached 這個模組並開啟。

以下文章中 memcache 指的是這個服務,memcached 是這個服務的程式,名稱上常常會混用,要注意看,雖然我也很困擾。

程式碼來源於[1],有小部分修改。

此次異動的檔案有二個,在app/目錄下

├── Config
│   ├── Cache.php  <== Cacha的設定
│   └── Session.php <== Session的設定
├── Controller
│   └── TestSession.php <== 測試用,非必要
└── .env <==設定顯示錯誤

Config/Cache.php

修改兩個地方即可[1] :

...
//    public string $handler = 'file';  <== 註解原本的,加上下面這行
    public string $handler ='memcached';
...

    public array $memcached = [
        'host'   => 'memcache', //'127.0.0.1',  <== 改成ip或是container的service name
        'port'   => 11211,
        'weight' => 1,
        'raw'    => false,
    ];

其餘不必動
 

Config/Session.php

修改或新增以下兩行

//    public string $driver = FileHandler::class;  <== 註解這行
    public string $driver = 'CodeIgniter\Session\Handlers\MemcachedHandler';
...
//    public string $savePath = WRITEPATH . 'session';  <== 註解這行
    public string $savePath = 'memcache:11211';

其中 $savepath 的 memcahce 改成ip即可。

 

讓你的php支援 php-memcached 

在session中使用memcached得安裝 php-memcached 並啟用。

安裝 php memcached 模組

# yum install php-pecl-memcache

重啟後請檢查

# php -m

...
mbstring
memcached   <== 需要有這個模組
mysqli
...

Docker中安裝 php-memcached

預設docker php:8.2-fpm 中並無安裝此模組,要自行建立,請在 Dockerfile 中加入[4]

RUN
  ...
  apt-get install -y libmemcached-dev zlib1g-dev libssl-dev && \
  yes '' | pecl install -f memcached-3.2.0 && docker-php-ext-enable memcached  && \
  ...

 

測試及除錯

使用的memcache如果無法連線,大概率會得到這樣的錯誤:

codeignitor4 Fatal error: Uncaught ErrorException: session_write_close(): Failed to write session data using user defined save handler. memcached

這樣的錯誤無法清楚的知道是怎樣的問題,所以可以使用下面兩種方式先確定你的memcache伺服器是正常的。

 

使用php原生的方式測試 [5]

$m= new MemCached();

$m->addServer('memcached', 11211);

$m->set('int', 99);
$m->set('string', 'a simple string');
$m->set('array', array(11, 12));
/* expire 'object' key in 5 minutes */
$m->set('object', new stdClass, time() + 300);
print $m->get('int');

var_dump($m->get('int'));
var_dump($m->get('string'));
var_dump($m->get('array'));
var_dump($m->get('object'));

結果:

99int(99)
string(15) "a simple string"
array(2) {
  [0]=>
  int(11)
  [1]=>
  int(12)
}
object(stdClass)#2 (0) {
}

CI4中叫用測試

session原則上和原本使用的方式一樣,不必特別改變習慣

Controller 中session叫用測試:

$session = session();

$session->set('cachename', 'My Memcache');
print $session->get('cachename');
//or
print $session->cachename;

結果:

My MemcacheMy Memcache

備註,CI4出現 whoops! 怎麼辦

如果出現 whoops!,到 ci4的根目錄下[3]

$ cp env .env

修改.env 把

CI_ENVIRONMENT = production

換成這個

CI_ENVIRONMENT = development

 

預設使用session library

如果要預設載入 session的library,修改 BaseController.php [2]

    public $session;
    public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
    {
        // Do Not Edit This Line
        parent::initController($request, $response, $logger);

        // Preload any models, libraries, etc, here.
        $this->session = \Config\Services::session();
    }

其它controller 直接使用 $this->session 即可

 

參考資料

[1] https://codeigniter.com/user_guide/libraries/caching.html#memcached-caching

[2] https://forum.codeigniter.com/showthread.php?tid=72170

[3] https://stackoverflow.com/questions/60558157/why-whoops-error-showing-in-codeigniter-4

[4] https://stackoverflow.com/questions/76490445/problem-adding-memcached-support-in-docker-for-php8-1-using-bookworm

[5] https://www.php.net/manual/en/memcached.set.php