@@ -32,6 +32,7 @@ class Cookie
3232
3333 private bool $ raw ;
3434 private ?string $ sameSite = null ;
35+ private bool $ partitioned = false ;
3536 private bool $ secureDefault = false ;
3637
3738 private const RESERVED_CHARS_LIST = "=,; \t\r\n\v\f" ;
@@ -51,6 +52,7 @@ public static function fromString(string $cookie, bool $decode = false): static
5152 'httponly ' => false ,
5253 'raw ' => !$ decode ,
5354 'samesite ' => null ,
55+ 'partitioned ' => false ,
5456 ];
5557
5658 $ parts = HeaderUtils::split ($ cookie , ';= ' );
@@ -66,17 +68,20 @@ public static function fromString(string $cookie, bool $decode = false): static
6668 $ data ['expires ' ] = time () + (int ) $ data ['max-age ' ];
6769 }
6870
69- return new static ($ name , $ value , $ data ['expires ' ], $ data ['path ' ], $ data ['domain ' ], $ data ['secure ' ], $ data ['httponly ' ], $ data ['raw ' ], $ data ['samesite ' ]);
71+ return new static ($ name , $ value , $ data ['expires ' ], $ data ['path ' ], $ data ['domain ' ], $ data ['secure ' ], $ data ['httponly ' ], $ data ['raw ' ], $ data ['samesite ' ], $ data [ ' partitioned ' ] );
7072 }
7173
7274 /**
7375 * @see self::__construct
7476 *
7577 * @param self::SAMESITE_*|''|null $sameSite
78+ * @param bool $partitioned
7679 */
77- public static function create (string $ name , string $ value = null , int |string |\DateTimeInterface $ expire = 0 , ?string $ path = '/ ' , string $ domain = null , bool $ secure = null , bool $ httpOnly = true , bool $ raw = false , ?string $ sameSite = self ::SAMESITE_LAX ): self
80+ public static function create (string $ name , string $ value = null , int |string |\DateTimeInterface $ expire = 0 , ?string $ path = '/ ' , string $ domain = null , bool $ secure = null , bool $ httpOnly = true , bool $ raw = false , ?string $ sameSite = self ::SAMESITE_LAX /* , bool $partitioned = false */ ): self
7881 {
79- return new self ($ name , $ value , $ expire , $ path , $ domain , $ secure , $ httpOnly , $ raw , $ sameSite );
82+ $ partitioned = 9 < \func_num_args () ? func_get_arg (9 ) : false ;
83+
84+ return new self ($ name , $ value , $ expire , $ path , $ domain , $ secure , $ httpOnly , $ raw , $ sameSite , $ partitioned );
8085 }
8186
8287 /**
@@ -92,7 +97,7 @@ public static function create(string $name, string $value = null, int|string|\Da
9297 *
9398 * @throws \InvalidArgumentException
9499 */
95- public function __construct (string $ name , string $ value = null , int |string |\DateTimeInterface $ expire = 0 , ?string $ path = '/ ' , string $ domain = null , bool $ secure = null , bool $ httpOnly = true , bool $ raw = false , ?string $ sameSite = self ::SAMESITE_LAX )
100+ public function __construct (string $ name , string $ value = null , int |string |\DateTimeInterface $ expire = 0 , ?string $ path = '/ ' , string $ domain = null , bool $ secure = null , bool $ httpOnly = true , bool $ raw = false , ?string $ sameSite = self ::SAMESITE_LAX , bool $ partitioned = false )
96101 {
97102 // from PHP source code
98103 if ($ raw && false !== strpbrk ($ name , self ::RESERVED_CHARS_LIST )) {
@@ -112,6 +117,7 @@ public function __construct(string $name, string $value = null, int|string|\Date
112117 $ this ->httpOnly = $ httpOnly ;
113118 $ this ->raw = $ raw ;
114119 $ this ->sameSite = $ this ->withSameSite ($ sameSite )->sameSite ;
120+ $ this ->partitioned = $ partitioned ;
115121 }
116122
117123 /**
@@ -237,6 +243,17 @@ public function withSameSite(?string $sameSite): static
237243 return $ cookie ;
238244 }
239245
246+ /**
247+ * Creates a cookie copy that is tied to the top-level site in cross-site context.
248+ */
249+ public function withPartitioned (bool $ partitioned = true ): static
250+ {
251+ $ cookie = clone $ this ;
252+ $ cookie ->partitioned = $ partitioned ;
253+
254+ return $ cookie ;
255+ }
256+
240257 /**
241258 * Returns the cookie as a string.
242259 */
@@ -268,18 +285,22 @@ public function __toString(): string
268285 $ str .= '; domain= ' .$ this ->getDomain ();
269286 }
270287
271- if (true === $ this ->isSecure ()) {
288+ if ($ this ->isSecure ()) {
272289 $ str .= '; secure ' ;
273290 }
274291
275- if (true === $ this ->isHttpOnly ()) {
292+ if ($ this ->isHttpOnly ()) {
276293 $ str .= '; httponly ' ;
277294 }
278295
279296 if (null !== $ this ->getSameSite ()) {
280297 $ str .= '; samesite= ' .$ this ->getSameSite ();
281298 }
282299
300+ if ($ this ->isPartitioned ()) {
301+ $ str .= '; partitioned ' ;
302+ }
303+
283304 return $ str ;
284305 }
285306
@@ -365,6 +386,14 @@ public function isRaw(): bool
365386 return $ this ->raw ;
366387 }
367388
389+ /**
390+ * Checks whether the cookie should be tied to the top-level site in cross-site context.
391+ */
392+ public function isPartitioned (): bool
393+ {
394+ return $ this ->partitioned ;
395+ }
396+
368397 /**
369398 * @return self::SAMESITE_*|null
370399 */
0 commit comments