1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Class Header |
4
|
|
|
* |
5
|
|
|
* @link https://www.icy2003.com/ |
6
|
|
|
* @author icy2003 <[email protected]> |
7
|
|
|
* @copyright Copyright (c) 2017, icy2003 |
8
|
|
|
*/ |
9
|
|
|
|
10
|
|
|
namespace icy2003\php\ihelpers; |
11
|
|
|
|
12
|
|
|
use icy2003\php\I; |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* 对 header 函数的一些封装 |
16
|
|
|
*/ |
17
|
|
|
class Header |
18
|
|
|
{ |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* 发送原生 HTTP 头 |
22
|
|
|
* |
23
|
|
|
* - 兼容 Workerman 的 header 头 |
24
|
|
|
* |
25
|
|
|
* @param string $string 头字符串 |
26
|
|
|
* @param boolean $replace 是否用后面的头替换前面相同类型的头,默认是 |
27
|
|
|
* @param integer $httpResponseCode 强制指定HTTP响应的值,默认不强制 |
28
|
|
|
* |
29
|
|
|
* @return void |
30
|
|
|
*/ |
31
|
|
|
public static function send($string, $replace = true, $httpResponseCode = null) |
32
|
|
|
{ |
33
|
|
|
if (method_exists('\Workerman\Protocols\Http', 'header')) { |
34
|
|
|
call_user_func_array('\Workerman\Protocols\Http::header', [$string, $replace, $httpResponseCode]); |
35
|
|
|
} else { |
36
|
|
|
header($string, $replace, $httpResponseCode); |
37
|
|
|
} |
38
|
|
|
} |
39
|
|
|
/** |
40
|
|
|
* 正常访问 |
41
|
|
|
* |
42
|
|
|
* HTTP 返回 200 |
43
|
|
|
* |
44
|
|
|
* @return void |
45
|
|
|
*/ |
46
|
|
|
public static function ok() |
47
|
|
|
{ |
48
|
|
|
self::send('HTTP/1.1 200 OK'); |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* 页面不存在 |
53
|
|
|
* |
54
|
|
|
* HTTP 返回 404 |
55
|
|
|
* |
56
|
|
|
* @return void |
57
|
|
|
*/ |
58
|
|
|
public static function notFound() |
59
|
|
|
{ |
60
|
|
|
self::send('HTTP/1.1 404 Not Found'); |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* 跳转到一个新的地址 |
65
|
|
|
* |
66
|
|
|
* HTTP 返回 302 |
67
|
|
|
* |
68
|
|
|
* @param string|null $url 新地址,如果不给这个值,表示刷新当前页面 |
69
|
|
|
* @param integer $time 延迟时间,单位秒 |
70
|
|
|
* |
71
|
|
|
* @return void |
72
|
|
|
*/ |
73
|
|
|
public static function redirect($url = null, $time = 0) |
74
|
|
|
{ |
75
|
|
|
null === $url && $url = ''; |
76
|
|
|
if ($time < 0) { |
77
|
|
|
throw new \Exception('time 参数不能小于 0 '); |
78
|
|
|
} else { |
79
|
|
|
self::send('HTTP/1.1 302 Found'); |
80
|
|
|
self::send('Refresh: ' . $time . '; ' . $url); |
81
|
|
|
} |
82
|
|
|
die; |
|
|
|
|
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* 永久跳转 |
87
|
|
|
* |
88
|
|
|
* HTTP 返回 301 |
89
|
|
|
* |
90
|
|
|
* @param string $url 永久跳转的地址 |
91
|
|
|
* |
92
|
|
|
* @return void |
93
|
|
|
*/ |
94
|
|
|
public static function redirectPermanently($url) |
95
|
|
|
{ |
96
|
|
|
self::send('HTTP/1.1 301 Moved Permanently'); |
97
|
|
|
self::send('Location: ' . $url); |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* 设置网页编码为 UTF-8 |
102
|
|
|
* |
103
|
|
|
* @return void |
104
|
|
|
*/ |
105
|
|
|
public static function utf8() |
106
|
|
|
{ |
107
|
|
|
self::send('Content-Type: text/html; charset=utf-8'); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
/** |
111
|
|
|
* 内容类型为 JSON |
112
|
|
|
* |
113
|
|
|
* @return void |
114
|
|
|
*/ |
115
|
|
|
public static function json() |
116
|
|
|
{ |
117
|
|
|
self::send('Content-Type: application/json'); |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* 内容类型为 XML |
122
|
|
|
* |
123
|
|
|
* @return void |
124
|
|
|
*/ |
125
|
|
|
public static function xml() |
126
|
|
|
{ |
127
|
|
|
self::send('Content-Type: text/xml'); |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* 设置可跨域的域名 |
132
|
|
|
* |
133
|
|
|
* @param array|string $urls 跨域域名列表,格式例如:http://127.0.0.1:8080 |
134
|
|
|
* |
135
|
|
|
* @return void |
136
|
|
|
*/ |
137
|
|
|
public static function allowOrigin($urls = '*') |
138
|
|
|
{ |
139
|
|
|
if ('*' === $urls) { |
140
|
|
|
self::send('Access-Control-Allow-Origin:*'); |
141
|
|
|
} else { |
142
|
|
|
$origin = I::get($_SERVER, 'HTTP_ORIGIN'); |
143
|
|
|
$urls = Strings::toArray($urls); |
144
|
|
|
if (is_array($urls) && in_array($origin, $urls)) { |
145
|
|
|
self::send('Access-Control-Allow-Origin:' . $origin); |
146
|
|
|
} |
147
|
|
|
} |
148
|
|
|
self::send('Access-Control-Max-Age:86400'); |
149
|
|
|
self::send('Access-Control-Allow-Credentials:true'); |
150
|
|
|
self::send('Access-Control-Allow-Methods:*'); |
151
|
|
|
self::send('Access-Control-Allow-Headers:Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With'); |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
/** |
155
|
|
|
* 修改 X-Powered-By信息 |
156
|
|
|
* |
157
|
|
|
* @param string $string |
158
|
|
|
* |
159
|
|
|
* @return void |
160
|
|
|
*/ |
161
|
|
|
public static function xPoweredBy($string = 'icy2003') |
162
|
|
|
{ |
163
|
|
|
self::send('X-Powered-By: ' . $string); |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* 告诉浏览器文档内容没有发生改变 |
168
|
|
|
* |
169
|
|
|
* @return void |
170
|
|
|
*/ |
171
|
|
|
public static function notModified() |
172
|
|
|
{ |
173
|
|
|
self::send('HTTP/1.1 304 Not Modified'); |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
/** |
177
|
|
|
* 禁用缓存 |
178
|
|
|
* |
179
|
|
|
* @return void |
180
|
|
|
*/ |
181
|
|
|
public static function noCache() |
182
|
|
|
{ |
183
|
|
|
self::send('Cache-Control: no-cache, no-store, max-age=0, must-revalidate'); |
184
|
|
|
self::send('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
/** |
188
|
|
|
* 设置 X-Frame-Options 选项 |
189
|
|
|
* |
190
|
|
|
* - 部分浏览器可能不支持,@link https://developer.mozilla.org/zh-CN/docs/Web/HTTP/X-Frame-Options |
191
|
|
|
* |
192
|
|
|
* @param boolean|string $asFrame 取值如下: |
193
|
|
|
* - false:X-Frame-Options: deny 表示该页面不允许在 frame 中展示,即便是在相同域名的页面中嵌套也不允许 |
194
|
|
|
* - true:X-Frame-Options: sameorigin 表示该页面可以在相同域名页面的 frame 中展示 |
195
|
|
|
* - 字符串:X-Frame-Options: allow-from https://example.com/ 表示该页面可以在指定来源的 frame 中展示 |
196
|
|
|
* |
197
|
|
|
* @return void |
198
|
|
|
*/ |
199
|
|
|
public static function frame($asFrame = true) |
200
|
|
|
{ |
201
|
|
|
if (true === $asFrame) { |
202
|
|
|
self::send('X-Frame-Options: sameorigin'); |
203
|
|
|
} elseif (false === $asFrame) { |
204
|
|
|
self::send('X-Frame-Options: deny'); |
205
|
|
|
} else { |
206
|
|
|
$asFrame = (string) $asFrame; |
207
|
|
|
self::send('X-Frame-Options: allow-from ' . $asFrame); |
208
|
|
|
} |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* 是否禁用 mine 嗅探 |
213
|
|
|
* |
214
|
|
|
* - 部分浏览器不支持,@link https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/X-Content-Type-Options |
215
|
|
|
* - 下面两种情况的请求将被阻止: |
216
|
|
|
* 1. 请求类型是"style" 但是 MIME 类型不是 "text/css", |
217
|
|
|
* 2. 请求类型是"script" 但是 MIME 类型不是 |
218
|
|
|
* |
219
|
|
|
* @param boolean $disabled 默认禁用 |
220
|
|
|
* |
221
|
|
|
* @return void |
222
|
|
|
*/ |
223
|
|
|
public static function mimeSniffing($disabled = true) |
224
|
|
|
{ |
225
|
|
|
if (true === $disabled) { |
226
|
|
|
self::send('X-Content-Type-Options: nosniff'); |
227
|
|
|
} |
228
|
|
|
} |
229
|
|
|
} |
230
|
|
|
|
In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.