rasuvaeff/yii3-ab-testing-web
最新稳定版本:v1.0.0
Composer 安装命令:
composer require rasuvaeff/yii3-ab-testing-web
包简介
Cookie identity and sticky-variant store for Yii3 A/B testing
README 文档
README
Web identity and sticky-variant layer for Yii3 A/B testing. Gives every visitor a stable subject id (so deterministic assignment holds across visits) and, when you need it, pins a subject to a variant across weight changes via a signed cookie.
Using an AI coding assistant? llms.txt contains a compact API reference you can ingest in your prompt context.
Requirements
- PHP 8.3+
rasuvaeff/yii3-ab-testing^1.2 (addsAssignmentStoreandAssignment::isSticky)yiisoft/cookies^1.2- a PSR-7 implementation (e.g.
nyholm/psr7) and a PSR-15 stack
Installation
composer require rasuvaeff/yii3-ab-testing-web
Identity vs stickiness
Assignment is deterministic in subjectId (sha256(salt:subjectId)), so a stable
id alone keeps a visitor in the same variant across visits — no variant is stored.
Two cookie roles solve two different problems:
| Need | Use |
|---|---|
| A stable id for anonymous visitors | SubjectIdMiddleware (cookie ab_id) |
| Keep a variant even after weights/variants change | CookieAssignmentStore + StickyAssignmentResolver |
A logged-in user already has a stable id (userId) — set it as the request
attribute upstream and the middleware leaves it alone.
Subject identity middleware
Add SubjectIdMiddleware to your PSR-15 stack. It resolves the subject id and
exposes it as a request attribute (ab.subjectId by default):
- if the attribute is already set (an upstream auth middleware put
userIdthere) it is kept — no cookie; - otherwise the
ab_idcookie is reused — only when its value matches the generated format (32 lowercase hex chars); a tampered or oversized value is discarded and regenerated; - otherwise a new opaque id is generated and a long-lived
HttpOnly,SameSite=Laxcookie is set.
use Rasuvaeff\Yii3AbTestingWeb\SubjectIdMiddleware; $middleware = new SubjectIdMiddleware(); // defaults: cookie 'ab_id', attribute 'ab.subjectId' // in your action/handler: $subjectId = $request->getAttribute('ab.subjectId'); $assignment = $ab->assign(experiment: 'checkout-button', subjectId: $subjectId);
For most experiments this is all you need.
Sticky variants
Changing weights or the variant set shifts bucket boundaries and reshuffles
subjects. To pin a subject across such changes, resolve through a
CookieAssignmentStore (a signed {experiment: variant} cookie) and a
StickyAssignmentResolver. Because the store is request-scoped, wire it in a thin
middleware that reads the cookie, exposes the store, and writes it back:
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; use Rasuvaeff\Yii3AbTestingWeb\CookieAssignmentStore; use Yiisoft\Cookies\CookieSigner; final class StickyCookieMiddleware implements MiddlewareInterface { public function __construct(private CookieSigner $signer) {} public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { $store = CookieAssignmentStore::fromRequest($request, $this->signer); $response = $handler->handle($request->withAttribute('ab.store', $store)); return $store->applyToResponse($response); } }
Then in your action:
use Rasuvaeff\Yii3AbTestingWeb\StickyAssignmentResolver; $store = $request->getAttribute('ab.store'); // CookieAssignmentStore $resolver = new StickyAssignmentResolver($ab, $store); $assignment = $resolver->resolve( experiment: 'checkout-button', subjectId: $request->getAttribute('ab.subjectId'), ); // first time: assigned and stored; later: the stored variant is returned
StickyAssignmentResolver keeps AbTesting::assign() pure: a forced variant
bypasses the store, a disabled experiment returns its fallback (the kill switch
always wins and nothing is stored), and a stored variant that is no longer part of
the experiment is re-assigned.
API reference
| Class | Description |
|---|---|
SubjectIdMiddleware |
PSR-15 middleware; stable subject id + ab_id cookie |
CookieAssignmentStore |
AssignmentStore over one signed cookie; fromRequest() / applyToResponse() |
StickyAssignmentResolver |
get-or-assign over AbTesting + any AssignmentStore |
Security & privacy
- The subject id is an opaque 128-bit token (
random_bytes), not a UUID, and carries no personal data — but it is a persistent identifier. Set the cookie only after consent where the law requires it. - The sticky cookie is signed (
yiisoft/cookiesCookieSigner); a missing, unsigned, tampered, or malformed cookie is ignored and yields an empty store — never a partial or attacker-controlled variant map. Provide a strong signing key. - Cookies are
HttpOnly,SameSite=Lax, andSecureby default. - The cookie is browser-scoped: the
$subjectIdargument of the store is ignored. A visitor who was anonymous then logged in keeps the variants from their anonymous identity.
Examples
See examples/ for a runnable script (no server required).
Development
composer build # full gate: validate + normalize + cs + psalm + test composer cs:fix # auto-fix code style composer psalm # static analysis composer test # run tests
License
BSD-3-Clause. See LICENSE.md.
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 2
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: BSD-3-Clause
- 更新时间: 2026-06-12