本技能介绍 Bitrix 框架的会话(Session)机制,基线为 main 23.0+,验证于 main 26.800.0。核心原则是不要直接操作 $_SESSION,因为它会绕过延迟启动、只读和虚拟模式。
一、基本用法 通过 Application::getInstance()->getSession() 获取会话对象,它实现 SessionInterface 与 ArrayAccess。可用 set() 写入、get() 读取(缺失返回 null)、has() 判断、remove() 删除,并在登录或权限变更后调用 regenerateId() 重新生成 ID。键名建议以模块 ID 为前缀,只存储标量或数组。
二、会话写入时机与限制 会话在后台任务和代理运行之前就已写入并关闭,因此 addBackgroundJob() 中的写入会丢失。CLI、代理和 Messenger 没有会话。
三、本地会话(会话缓存) 通过 Application::getInstance()->getLocalSession('vendor_cart') 获取按名称分隔的容器,可用 set() 或数组方式读写。它存储在缓存引擎(Redis/Memcache/APC)中,以会话 ID 为键,在请求结束时保存;若使用文件缓存则回退到 $_SESSION。TTL 可在 .settings.php 的 session_local_storage 中配置,例如 ttl => 86400。适用于购物车、筛选器、向导草稿等较大或频繁变化、不应使主会话膨胀或加锁的数据。
四、内核会话 Application::getInstance()->getKernelSession() 保存内核数据(认证、sessid)。默认模式下它就是主会话;分离模式下是加密 Cookie(crypto_key),不含对象。不要在其中存放应用数据。
五、模式(需在 prolog_before.php 之前定义) BX_SECURITY_SESSION_READONLY:处理程序无锁读取且从不写入,适用于并行只读 AJAX(如建议、计数器),更改会被丢弃。 BX_SECURITY_SESSION_VIRTUAL:内存会话,无 Cookie,不存储任何内容,适用于令牌认证的 REST/Webhook。 BX_FORCE_DISABLE_SEPARATED_SESSION_MODE:为脚本强制使用默认模式。
六、session 配置段(bitrix-settings) 在 .settings.php 中配置 session,包含 mode(default 或 separated)、lifetime(仅分离模式的内核 Cookie 生命周期)、handlers(kernel 仅允许 encrypted_cookies;general 的 type 可为 file、database、redis、memcache、null,并含 host、port、keyPrefix 等)、regenerateIdAfterLogin、ignoreSessionStartErrors 等。分离模式下内核数据在 Cookie 中,通用会话在首次访问时延迟启动,未触及它的匿名请求不会访问存储。Redis/Memcache 的通用会话 TTL 由 php.ini 的 session.gc_maxlifetime 决定,而非 lifetime。
Redis 选项包括 host、port、password、servers(集群列表)、serializer、persistent、failover、timeout、readTimeout、keyPrefix、exclusiveLock(锁值等于请求页面,会显示在锁超时错误中)。Memcache 选项包括 host、port、servers、connectionTimeout、keyPrefix、exclusiveLock。文件存储用 savePath,数据库存储使用 b_user_session 表。若没有 session 段且 php.ini 的 session.save_handler 不是 files,则直接使用 PHP 自身的处理程序。
每个可写会话在整个请求期间都会被锁定(Redis/Memcache 最多等待约 60 秒后致命错误),同一用户的并行 AJAX 会串行执行,因此在不写入的场景应使用 BX_SECURITY_SESSION_READONLY。
七、安全 会话 Cookie 始终为 HttpOnly;Secure/SameSite 来自 php.ini 的 session.cookie_secure / session.cookie_samesite。登录和权限变更时应重新生成 ID(regenerateIdAfterLogin 或 regenerateId())。切勿在会话中存储机密或完整用户对象,并应在每个请求重新检查权限。