-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHttpCors.php
More file actions
132 lines (127 loc) · 4.01 KB
/
HttpCors.php
File metadata and controls
132 lines (127 loc) · 4.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
<?php
class HttpCors
{
private $map = array();
private $preflight_request = FALSE;
public function __construct(){}
public function addRule($origin, array $rule=array())
{
$this->map[$origin] = array_merge(
array(
'allowMethods' => array(),
'allowHeaders' => array(),
'exposeHeaders' => array(),
'credentials' => FALSE,
'maxAge' => 0,
),
$rule
);
$this->map[$origin]['allowMethods'] = self::_mapTranform($this->map[$origin]['allowMethods']);
$this->map[$origin]['allowHeaders'] = self::_mapTranform($this->map[$origin]['allowHeaders']);
$this->map[$origin]['exposeHeaders'] = self::_mapTranform($this->map[$origin]['exposeHeaders']);
}
/* 调整转换录入的 mapRule 的内容 */
private static function _mapTranform($input)
{
if( is_array($input) ){
foreach ($input as $key => $value) {
$input[$key] = strtolower(trim((string)$value));
}
return $input;
}else{
return array();
}
}
public function response($isReturn = FALSE)
{
$origin = strtolower( self::_getHeader('origin') );
$method = strtolower( self::_getHeader('method') );
$ACRMethod = strtolower( self::_getHeader('access-control-request-method') );
$ACRHeader = strtolower( self::_getHeader('access-control-request-header') );
/* Normal Request : 因为不携带 Origin 头信息 */
if( !$origin ){
return TRUE;
}
/* White List Filter : 不允许访问的 Origin,程序终止响应 */
$current = $this->_getMatchMap( $origin );
if( !$current || !is_array( $current ) ){
header('Sorry: '.$origin.'Not Allow Access');
if( $isReturn ) { return FALSE; } else { exit; }
}
/* Preflight Check Request : 预检请求 */
if( 'options'==$method and $ACRMethod){
$this->preflight_request = TRUE;
/* 告知 User Agent 浏览器 允许的范畴 */
header('Access-Control-Allow-Methods:'.implode(', ', $current['allowMethods']));
header('Access-Control-Allow-Headers:'.implode(', ', $current['allowHeaders']));
/* 是否为准许实际请求的 Method */
if( !in_array($ACRMethod, $current['allowMethods']) ){
header("Sorry: Method '{$ACRMethod}' Not Allow");
if( $isReturn ) { return FALSE; } else { exit; }
}
/* 是否为准许的实际请求的 Header */
if( $ACRHeader ){
$ACRHeaders = explode(',', $ACRHeader);
foreach($ACRHeaders as $v){
$v = trim((string)$v);
if( !in_array($v, $current['allowHeaders']) ){
header("Sorry: Real Request Header '{$v}' Not Allow");
if( $isReturn ) { return FALSE; } else { exit; }
}
}
}
if( $current['maxAge'] ){
header('Access-Control-Max-Age:'.$current['maxAge']);
}
}
/* Simple CORS Request */
else{
if( count($current['exposeHeaders']) ){
header('Access-Control-Expose-Headers:'.implode(', ', $current['exposeHeaders']));
}
}
if( $current['credentials'] ){
header('Access-Control-Allow-Credentials: true');
}
header('Access-Control-Allow-Origin:'.$origin);
if( $this->preflight_request ){
if( $isReturn ) { return FALSE; } else { exit; }
}
return TRUE;
}
/* 获取 Request Header 头信息 */
private static function _getHeader($header)
{
$header = strtoupper(str_replace('-', '_', $header));
$prefix = ('METHOD'==$header) ? 'REQUEST_' : 'HTTP_';
$header = $prefix.$header;
return isset( $_SERVER[$header] ) ? $_SERVER[$header] : NULL;
}
/* return FALSE or the current Key */
private function _getMatchMap( $origin )
{
if( isset($this->map[$origin]) ){
return $this->map[$origin];
}
$origins = array_keys($this->map);
/* 是否存在 * 通配规则 */
foreach ($origins as $mapkey) {
if( '*' == $mapkey ){
return $this->map[$mapkey];
}
}
/* 是否存在 *.domain 通配规则 */
foreach ($origins as $mapkey) {
$domain1 = strstr($mapkey, '://*.');
if( !$domain1 ) continue;
$domain1 = substr($domain1, 5);//字符串 ://*. 长度为5
if( !$domain1 ) continue;
$domain2 = stristr($origin, $domain1);
if( $domain1 == $domain2 ){
return $this->map[$mapkey];
}
}
return NULL;
}
}
?>