>  기사  >  백엔드 개발  >  세션을 캐시(redis), DB에 넣습니다.

세션을 캐시(redis), DB에 넣습니다.

WBOY
WBOY원래의
2016-08-08 09:30:38894검색

SESSION을 캐시에 저장해야 하는 이유

PHP의 경우, 언어 자체에서 지원하는 세션은 파일 형태로 디스크 파일에 저장되며, 지정된 폴더에 저장됩니다. 저장 경로는 구성 파일에서 설정하거나 기능을 사용할 수 있습니다. session_save_path()를 프로그램에서 설정하지만 이렇게 하면 단점이 있습니다.

첫 번째는 파일 시스템에 저장하는 방법인데, 세션을 사용하는 동안에는 지정된 sessionid를 여러 파일에서 검색하게 되므로 매우 비효율적입니다.

두 번째는 여러 서버를 사용할 경우 세션이 손실되는 문제가 발생할 수 있다는 것입니다(실제로는 다른 서버에 저장되어 있습니다).

물론 캐시에 저장하면 위의 문제를 해결할 수 있습니다. PHP 자체 세션 함수를 사용하는 경우 session_set_save_handler() 함수를 사용하면 세션 처리 프로세스를 쉽게 다시 제어할 수 있습니다. PHP의 세션 시리즈 함수를 사용하지 않는 경우 유사한 세션 함수를 직접 작성하는 것도 가능합니다. 이것은 현재 작업 중인 프로젝트입니다. 사용자의 mid 및 login을 기반으로 해시를 계산합니다. 요청할 때마다 sessionId를 추가해야 합법적입니다(처음 로그인할 때는 필요하지 않으며 이때 sessionId가 생성되어 클라이언트에 반환됩니다). 간결하고 효율적입니다. 물론, 내가 이 글에서 주로 이야기하고 있는 것은 PHP 자체 SESSION에서의 "사물 조작"이다.

캐시에 저장된 SESSION

PHP는 캐시를 redis에 저장합니다. 물론, 프로그램의 ini_set() 함수를 사용하여 수정할 수도 있습니다. 테스트에서는 이를 사용하겠습니다. 물론 프로덕션 환경에서는 구성 파일을 사용하는 것이 좋습니다.

<?<span>php
</span><span>ini_set</span>("session.save_handler", "redis"<span>);
</span><span>ini_set</span>("session.save_path", "tcp://localhost:6379"<span>);
</span><span>session_start</span><span>();
</span><span>header</span>("Content-type:text/html;charset=utf-8"<span>);
</span><span>if</span>(<span>isset</span>(<span>$_SESSION</span>['view'<span>])){
    </span><span>$_SESSION</span>['view'] = <span>$_SESSION</span>['view'] + 1<span>;
}</span><span>else</span><span>{
    </span><span>$_SESSION</span>['view'] = 1<span>;
}
</span><span>echo</span> "【view】{<span>$_SESSION</span>['view']}";

여기서 session.save_handler 메소드는 redis로 설정되어 있고, session.save_path는 redis의 주소와 포트입니다. 설정 후 새로고침 후 redis에서 생성된 sessionId를 확인하시면 됩니다. 브라우저에서 요청한 것과 동일합니다.

매우 편리하지 않나요? Redis에서 세션을 저장하려면 구성 파일만 변경하면 됩니다. 그런데 제가 여기서 이야기하고 싶은 것은 세션을 처리하고 이를 Redis나 DB에 저장하는 것입니다. 살펴 보겠습니다.

PHP에서 제공하는 인터페이스를 통해 세션 처리 기능을 직접 다시 작성

여기서 먼저 PHP의 session_set_save_handler 함수를 살펴보세요. PHP5.4 이상에서는 SessionHandlerInterface 인터페이스를 직접 구현할 수 있으며 코드가 더 간결해집니다. 다시 쓸 때 주로 다음과 같은 방법이 있습니다

open(string $savePath, string $sessionName); //open은 생성자와 유사하며 session_start() 함수를 사용한 후와 같이 세션을 시작할 때 호출됩니다.

close(); //클래스의 소멸자와 유사하며 쓰기 함수가 호출된 후에 호출됩니다.

도 session_write_close() 후에 실행됩니다.

read(string $sessionId); //세션을 읽을 때 호출됩니다

write(string $sessionId, string $data); //데이터 저장 시 호출

destory($sessionId); //세션(session_destory() 또는 session_regenerate_id())을 삭제하면

이 호출됩니다.

gc($lifeTime); //쓰레기 청소 기능, 만료된 데이터 정리

중요한 것은 이러한 방법을 구현하는 것입니다. 다양한 스토리지 드라이버에 따라 서로 다른 특정 방법을 설정할 수 있습니다. 세션 저장을 위해 mysql 데이터베이스와 redis라는 두 가지 드라이버를 구현했습니다. 확장은 직접 수행할 수 있습니다. 아주 쉽습니다. 편리함은 쉽습니다.

다음은 내 redis 구현입니다(db는 redis와 유사하고 redis 코드는 더 적으며 게시됨).

확장이 용이한 인터페이스 방식을 사용했는데, 그날은 memcached를 사용하고 싶어서 바로 추가해 줬어요

<?<span>php
</span><span>include_once</span> __DIR__."/interfaceSession.php"<span>;
</span><span>/*</span><span>*
 * 以db的方式存储session
 </span><span>*/</span>
<span>class</span> redisSession <span>implements</span><span> interfaceSession{
    </span><span>/*</span><span>*
     * 保存session的数据库表的信息
     </span><span>*/</span>
    <span>private</span> <span>$_options</span> = <span>array</span><span>(
        </span>'handler' => <span>null</span>, <span>//</span><span>数据库连接句柄</span>
        'host' => <span>null</span>,
        'port' => <span>null</span>,
        'lifeTime' => <span>null</span>,<span>
    );

    </span><span>/*</span><span>*
     * 构造函数
     * @param $options 设置信息数组
     </span><span>*/</span>
    <span>public</span> <span>function</span> __construct(<span>$options</span>=<span>array</span><span>()){
        </span><span>if</span>(!<span>class_exists</span>("redis", <span>false</span><span>)){
            </span><span>die</span>("必须安装redis扩展"<span>);
        }
        </span><span>if</span>(!<span>isset</span>(<span>$options</span>['lifeTime']) || <span>$options</span>['lifeTime'] <= 0<span>){
            </span><span>$options</span>['lifeTime'] = <span>ini_get</span>('session.gc_maxlifetime'<span>);
        }
        </span><span>$this</span>->_options = <span>array_merge</span>(<span>$this</span>->_options, <span>$options</span><span>);
    }

    </span><span>/*</span><span>*
     * 开始使用该驱动的session
     </span><span>*/</span>
    <span>public</span> <span>function</span><span> begin(){
        </span><span>if</span>(<span>$this</span>->_options['host'] === <span>null</span> ||
           <span>$this</span>->_options['port'] === <span>null</span> ||
           <span>$this</span>->_options['lifeTime'] === <span>null</span><span>
        ){
            </span><span>return</span> <span>false</span><span>;
        }
        </span><span>//</span><span>设置session处理函数</span>
        <span>session_set_save_handler</span><span>(
            </span><span>array</span>(<span>$this</span>, 'open'),
            <span>array</span>(<span>$this</span>, 'close'),
            <span>array</span>(<span>$this</span>, 'read'),
            <span>array</span>(<span>$this</span>, 'write'),
            <span>array</span>(<span>$this</span>, 'destory'),
            <span>array</span>(<span>$this</span>, 'gc'<span>)
        );
    }
    </span><span>/*</span><span>*
     * 自动开始回话或者session_start()开始回话后第一个调用的函数
     * 类似于构造函数的作用
     * @param $savePath 默认的保存路径
     * @param $sessionName 默认的参数名,PHPSESSID
     </span><span>*/</span>
    <span>public</span> <span>function</span> open(<span>$savePath</span>, <span>$sessionName</span><span>){
        </span><span>if</span>(<span>is_resource</span>(<span>$this</span>->_options['handler'])) <span>return</span> <span>true</span><span>;
        </span><span>//</span><span>连接redis</span>
        <span>$redisHandle</span> = <span>new</span><span> Redis();
        </span><span>$redisHandle</span>->connect(<span>$this</span>->_options['host'], <span>$this</span>->_options['port'<span>]);
        </span><span>if</span>(!<span>$redisHandle</span><span>){
            </span><span>return</span> <span>false</span><span>;
        }

        </span><span>$this</span>->_options['handler'] = <span>$redisHandle</span><span>;
        </span><span>$this</span>->gc(<span>null</span><span>);
        </span><span>return</span> <span>true</span><span>;

    }

    </span><span>/*</span><span>*
     * 类似于析构函数,在write之后调用或者session_write_close()函数之后调用
     </span><span>*/</span>
    <span>public</span> <span>function</span><span> close(){
        </span><span>return</span> <span>$this</span>->_options['handler']-><span>close();
    }

    </span><span>/*</span><span>*
     * 读取session信息
     * @param $sessionId 通过该Id唯一确定对应的session数据
     * @return session信息/空串
     </span><span>*/</span>
    <span>public</span> <span>function</span> read(<span>$sessionId</span><span>){
        </span><span>return</span> <span>$this</span>->_options['handler']->get(<span>$sessionId</span><span>);
    }

    </span><span>/*</span><span>*
     * 写入或者修改session数据
     * @param $sessionId 要写入数据的session对应的id
     * @param $sessionData 要写入的数据,已经序列化过了
     </span><span>*/</span>
    <span>public</span> <span>function</span> write(<span>$sessionId</span>, <span>$sessionData</span><span>){
        </span><span>return</span> <span>$this</span>->_options['handler']->setex(<span>$sessionId</span>, <span>$this</span>->_options['lifeTime'], <span>$sessionData</span><span>);
    }

    </span><span>/*</span><span>*
     * 主动销毁session会话
     * @param $sessionId 要销毁的会话的唯一id
     </span><span>*/</span>
    <span>public</span> <span>function</span> destory(<span>$sessionId</span><span>){
        </span><span>return</span> <span>$this</span>->_options['handler']->delete(<span>$sessionId</span>) >= 1 ? <span>true</span> : <span>false</span><span>;
    }

    </span><span>/*</span><span>*
     * 清理绘画中的过期数据
     * @param 有效期
     </span><span>*/</span>
    <span>public</span> <span>function</span> gc(<span>$lifeTime</span><span>){
        </span><span>//</span><span>获取所有sessionid,让过期的释放掉</span>
        <span>$this</span>->_options['handler']->keys("*"<span>);
        </span><span>return</span> <span>true</span><span>;
    }

}</span>

심플한 팩토리 패턴 살펴보기

<span>class</span><span> session {
    </span><span>/*</span><span>*
     * 驱动程序句柄保存
     </span><span>*/</span>
    <span>private</span> <span>static</span> <span>$_handler</span> = <span>null</span><span>;

    </span><span>/*</span><span>*
     * 创建session驱动程序
     </span><span>*/</span>
    <span>public</span> <span>static</span> <span>function</span> getSession(<span>$type</span>, <span>$options</span><span>){
        </span><span>//</span><span>单例</span>
        <span>if</span>(<span>isset</span>(<span>$handler</span><span>)){
            </span><span>return</span> self::<span>$_handler</span><span>;
        }

        </span><span>switch</span> (<span>$type</span><span>) {
            </span><span>case</span> 'db': <span>//</span><span>数据库驱动session类型</span>
                    <span>include_once</span> __DIR__."/driver/dbSession.php"<span>;
                    </span><span>$handler</span> = <span>new</span> dbSession(<span>$options</span><span>);
                </span><span>break</span><span>;
            
            </span><span>case</span> 'redis': <span>//</span><span>redis驱动session类型</span>
                    <span>include_once</span> __DIR__."/driver/redisSession.php"<span>;
                    </span><span>$handler</span> = <span>new</span> redisSession(<span>$options</span><span>);
                </span><span>break</span><span>;
            </span><span>default</span>:
                    <span>return</span> <span>false</span><span>;
                </span><span>break</span><span>;
        }

        </span><span>return</span> self::<span>$_handler</span> = <span>$handler</span><span>;
    }
}</span>

통화도 아주 간단해요,

session::getSession('redis',<span>array</span><span>(
        </span>'host' => "localhost",
        'port' => "6379",<span>
    ))</span>-><span>begin();

</span><span>session_start</span>();

데이터베이스 버전도 구성이 매우 간단합니다. 필요한 경우 여기에서 정식 버전과 데모

를 다운로드할 수 있습니다.

이 글의 저작권은 저자(luluyrt@163.com)에게 있습니다. 글을 재인쇄한 후, 저자와 원문 링크를 반드시 밝혀야 합니다. 기사 페이지의 명확한 위치에 제공되지 않으면 당사는 법적 책임 권리를 추구할 권리를 보유합니다.

위 내용은 세션을 캐시(redis)와 DB에 소개한 내용으로, PHP 튜토리얼에 관심이 있는 친구들에게 도움이 되길 바랍니다.

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.