141 lines
3.9 KiB
PHP
Executable File
141 lines
3.9 KiB
PHP
Executable File
<?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' => ltrim($domain, '.'),
|
||
'secure' => function_exists('cloak_request_is_https') && cloak_request_is_https(),
|
||
'httponly' => true,
|
||
'samesite' => 'Lax',
|
||
]);
|
||
} elseif ($domain !== '') {
|
||
session_set_cookie_params(
|
||
0,
|
||
'/',
|
||
ltrim($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 = function_exists('cloak_normalize_request_host')
|
||
? cloak_normalize_request_host($_SERVER['HTTP_HOST'] ?? '')
|
||
: strtolower(trim((string) ($_SERVER['HTTP_HOST'] ?? '')));
|
||
$originHost = function_exists('cloak_normalize_request_host')
|
||
? cloak_normalize_request_host($originHost)
|
||
: strtolower(trim($originHost));
|
||
|
||
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)
|
||
{
|
||
if (function_exists('cloak_registrable_domain')) {
|
||
return cloak_registrable_domain($host);
|
||
}
|
||
|
||
$host = strtolower(trim($host));
|
||
if ($host === '') {
|
||
return '';
|
||
}
|
||
|
||
$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;
|
||
}
|
||
}
|