2015-06-25 4 views
0

Хорошо, я следовал этому примеру обмена сеанса между PHP и nodejs с помощью Redis: https://gist.github.com/mscdex/9507b0d8df42e0aec825CakePHP 3.x с nodejs использованием Redis

я получил, что работает прекрасно, но сейчас я пытаюсь увидеть как бы я это сделал с CakePhp. У меня есть несколько вопросов о том, как я бы об этом:

  1. Должен ли я просто создать новый обработчик сеанса и внутри конструктора запуска конфигурации сеанса, что мне нужно сделать до начала сессии ??

  2. Должен ли я просто создать новый класс Session.php, расширенный от того, предоставленного CakePhp? Если я это сделаю, как я могу заставить приложение использовать его?

код связан выше:

var express = require('express'), 
    app = express(), 
    cookieParser = require('cookie-parser'), 
    session = require('express-session'), 
    RedisStore = require('connect-redis')(session); 

app.use(express.static(__dirname + '/public')); 
app.use(function(req, res, next) { 
    if (~req.url.indexOf('favicon')) 
    return res.send(404); 
    next(); 
}); 
app.use(cookieParser()); 
app.use(session({ 
    store: new RedisStore({ 
    // this is the default prefix used by redis-session-php 
    prefix: 'session:php:' 
    }), 
    // use the default PHP session cookie name 
    name: 'PHPSESSID', 
    secret: 'node.js rules', 
    resave: false, 
    saveUninitialized: false 
})); 
app.use(function(req, res, next) { 
    req.session.nodejs = 'Hello from node.js!'; 
    res.send('<pre>' + JSON.stringify(req.session, null, ' ') + '</pre>'); 
}); 

app.listen(8080); 
<?php 
// this must match the express-session `secret` in your Express app 
define('EXPRESS_SECRET', 'node.js rules'); 

// this id mutator function helps ensure we look up 
// the session using the right id 
define('REDIS_SESSION_ID_MUTATOR', 'express_mutator'); 
function express_mutator($id) { 
    if (substr($id, 0, 2) === "s:") 
    $id = substr($id, 2); 
    $dot_pos = strpos($id, "."); 
    if ($dot_pos !== false) { 
    $hmac_in = substr($id, $dot_pos + 1); 
    $id = substr($id, 0, $dot_pos); 
    } 
    return $id; 
} 

// check for existing express-session cookie ... 
$sess_name = session_name(); 
if (isset($_COOKIE[$sess_name])) { 
    // here we have to manipulate the cookie data in order for 
    // the lookup in redis to work correctly 

    // since express-session forces signed cookies now, we have 
    // to deal with that here ... 
    if (substr($_COOKIE[$sess_name], 0, 2) === "s:") 
    $_COOKIE[$sess_name] = substr($_COOKIE[$sess_name], 2); 
    $dot_pos = strpos($_COOKIE[$sess_name], "."); 
    if ($dot_pos !== false) { 
    $hmac_in = substr($_COOKIE[$sess_name], $dot_pos + 1); 
    $_COOKIE[$sess_name] = substr($_COOKIE[$sess_name], 0, $dot_pos); 

    // https://github.com/tj/node-cookie-signature/blob/0aa4ec2fffa29753efe7661ef9fe7f8e5f0f4843/index.js#L20-L23 
    $hmac_calc = str_replace("=", "", base64_encode(hash_hmac('sha256', $_COOKIE[$sess_name], EXPRESS_SECRET, true))); 
    if ($hmac_calc !== $hmac_in) { 
     // the cookie data has been tampered with, you can decide 
     // how you want to handle this. for this example we will 
     // just ignore the cookie and generate a new session ... 
     unset($_COOKIE[$sess_name]); 
    } 
    } 
} else { 
    // let PHP generate us a new id 
    session_regenerate_id(); 
    $sess_id = session_id(); 
    $hmac = str_replace("=", "", base64_encode(hash_hmac('sha256', $sess_id, EXPRESS_SECRET, true))); 
    // format it according to the express-session signed cookie format 
    session_id("s:$sess_id.$hmac"); 
} 
// https://github.com/TheDeveloper/redis-session-php 
require('redis-session-php/redis-session.php'); 
RedisSession::start(); 

$_SESSION["php"] = "Hello from PHP"; 
if (!isset($_SESSION["cookie"])) 
    $_SESSION["cookie"] = array(); 

echo "<pre>"; 
echo json_encode($_COOKIE, JSON_PRETTY_PRINT); 
echo json_encode($_SESSION, JSON_PRETTY_PRINT); 
echo "</pre>"; 

?> 

ответ

1

Я не очень хорошо знаком с Redis или узел, но смотреть на коде RedisSession класса (https://github.com/TheDeveloper/redis-session-php), я d сказать, что вам придется идти с помощью специального обработчика сеанса. Если обработчик сеанса должен шарить с печеньем очень спорно, я бы, вероятно, положить, что где-то еще в процессе самонастройки, может быть, как диспетчерский фильтр.

Однако, если вам нужен идентификатор сеанса в определенном формате, вам также необходимо будет использовать собственный класс сеанса, по крайней мере, если вы не хотите/не можете использовать недокументированный session id genereation handler stuff, который был введен с PHP 5.5.1.

Создание расширенного класса сеанса, который обрабатывает это довольно просто, просто перезапишите метод start() и renew() и сделайте все, что вам нужно сделать с идентификатором.

Внедрение нового класса сеанса в приложение довольно просто, так как во всей структуре сеанс извлекается из запроса (\Cake\Network\Request::session()). Однако получение пользовательского класса в запросе немного уродливое, так как нет чистого способа привязать его к процессу создания запроса от глобальных переменных. В любом случае вам придется изменить свой фронт-контроллер (webroot/index.php), чтобы соответствующий диспетчер передал соответствующий класс запроса.

Вы можете

  • создать пользовательский класс запроса с, например, в перезаписанного Request::createFromGlobals() метод, при котором вы будете создать экземпляр пользовательского класса сессии и передать его в конфиге

  • создать экземпляр нового запроса класса, где вы можете передать объект сеанса для использования с помощью конфигурационного ключа session (для этого вам нужно самим изобразить base и webroot)

  • или перезаписать уже назначенный/построенный класс сеанса с вашим пользовательским, используя метод Request::session().

Смотрите также

В этом примере я пойду с пользовательским классом запроса, просто чтобы избежать дополнительного класса сеанса конкретизации.

ЦСИ/Сеть/MyCustomSession.php

namespace App\Network; 

use Cake\Network\Session; 

class MyCustomSession extends Session 
{ 
    public function start() 
    { 
     parent::start(); 
     $this->_processSessionId(); 
    } 

    public function renew() 
    { 
     parent::renew(); 
     $this->_processSessionId(); 
    } 

    protected function _processSessionId() 
    { 
     $id = $this->id(); 

     // To make this less handler specific, you could for example 
     // use a configurable callback instead, or maybe even an event, 
     // in the end this is just example code. 

     if($id && substr($id, 0, 2) !== 's:') { 
      $hmac = str_replace(
       "=", "", base64_encode(hash_hmac('sha256', $id, \EXPRESS_SECRET, true)) 
      ); 
      $this->id("s:$id.$hmac"); 
     } 
    } 
} 

ЦСИ/Сеть/MyCustomRequest.php

namespace App\Network; 

use Cake\Network\Request; 

class MyCustomRequest extends Request 
{ 
    public static function createFromGlobals() 
    { 
     list($base, $webroot) = static::_base(); 
     $sessionConfig = (array)Configure::read('Session') + [ 
      'defaults' => 'php', 
      'cookiePath' => $webroot 
     ]; 
     $config = [ 
      'query' => $_GET, 
      'post' => $_POST, 
      'files' => $_FILES, 
      'cookies' => $_COOKIE, 
      'environment' => $_SERVER + $_ENV, 
      'base' => $base, 
      'webroot' => $webroot, 

      // here comes the custom session 
      'session' => MyCustomSession::create($sessionConfig) 
     ]; 
     $config['url'] = static::_url($config); 
     return new static($config); 
    } 
} 

SRC/Webroot/index.php

use App\Network\MyCustomRequest; 

$dispatcher = DispatcherFactory::create(); 
$dispatcher->dispatch(
    MyCustomRequest::createFromGlobals(), // there goes the custom request 
    new Response() 
); 
Смежные вопросы