Files
CLOAK/lib/Cloak/CloakSession.php
T

138 lines
3.7 KiB
PHP
Raw Normal View History

2026-06-15 22:42:59 +08:00
<?php
/**
* Session 与 f_check 跨域(CORS)辅助
*/
class CloakSession
{
public static function start()
{
if (session_status() === PHP_SESSION_ACTIVE) {
return;
}
$domain = function_exists('cloak_fingerprint_cookie_domain')
? cloak_fingerprint_cookie_domain()
: '';
if ($domain !== '' && PHP_VERSION_ID >= 70300) {
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'domain' => $domain,
'secure' => function_exists('cloak_request_is_https') && cloak_request_is_https(),
'httponly' => true,
'samesite' => 'Lax',
]);
} elseif ($domain !== '') {
session_set_cookie_params(
0,
'/',
$domain,
function_exists('cloak_request_is_https') && cloak_request_is_https(),
true
);
}
session_start();
}
}
class CloakFcheckCors
{
/**
* OPTIONS 预检:在 session/bootstrap 之前调用。
*/
public static function handlePreflight()
{
if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'OPTIONS') {
return;
}
self::emitHeaders();
http_response_code(204);
exit;
}
/**
* 响应头(含 AJAX 跨子域 withCredentials
*/
public static function emitHeaders()
{
$origin = (string) ($_SERVER['HTTP_ORIGIN'] ?? '');
if ($origin !== '' && self::isAllowedOrigin($origin)) {
header('Access-Control-Allow-Origin: ' . $origin);
header('Access-Control-Allow-Credentials: true');
header('Vary: Origin');
}
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
header('Access-Control-Max-Age: 86400');
}
/**
* @param string $origin
*/
private static function isAllowedOrigin($origin)
{
$originHost = parse_url($origin, PHP_URL_HOST);
if (!is_string($originHost) || $originHost === '') {
return false;
}
$requestHost = (string) ($_SERVER['HTTP_HOST'] ?? '');
if ($requestHost !== '' && strcasecmp($originHost, $requestHost) === 0) {
return true;
}
$suffix = self::registrableSuffix($requestHost);
if ($suffix === '') {
return false;
}
$originSuffix = self::registrableSuffix($originHost);
if ($originSuffix === '' || strcasecmp($originSuffix, $suffix) !== 0) {
return false;
}
return self::hostMatchesSuffix($originHost, $suffix);
}
/**
* @param string $host
*/
private static function registrableSuffix($host)
{
$host = strtolower(trim($host));
if ($host === '') {
return '';
}
if (function_exists('cloak_fingerprint_cookie_domain')) {
$cookieDomain = ltrim(cloak_fingerprint_cookie_domain(), '.');
if ($cookieDomain !== '' && self::hostMatchesSuffix($host, $cookieDomain)) {
return $cookieDomain;
}
}
$parts = explode('.', $host);
if (count($parts) < 2) {
return $host;
}
return $parts[count($parts) - 2] . '.' . $parts[count($parts) - 1];
}
/**
* @param string $host
* @param string $suffix
*/
private static function hostMatchesSuffix($host, $suffix)
{
$host = strtolower($host);
$suffix = strtolower($suffix);
return $host === $suffix || substr($host, -strlen('.' . $suffix)) === '.' . $suffix;
}
}