RestController.class.php
10.4 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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Controller;
use Think\Controller;
use Think\Build;
/**
* ThinkPHP REST控制器类
*/
class RestController extends Controller
{
// 当前请求类型
protected $_method = '';
// 当前请求的资源类型
protected $_type = '';
// REST允许的请求类型列表
protected $allowMethod = array(
'get',
'post',
'put',
'delete'
);
// REST默认请求类型
protected $defaultMethod = 'get';
// REST允许请求的资源类型列表
protected $allowType = array(
'html',
'xml',
'json',
'rss'
);
// 默认的资源类型
protected $defaultType = 'html';
// REST允许输出的资源类型列表
protected $allowOutputType = array(
'xml' => 'application/xml',
'json' => 'application/json',
'html' => 'text/html'
);
/**
* 架构函数
*
* @access public
*/
public function __construct()
{
// 资源类型检测
if ('' == __EXT__) { // 自动检测资源类型
$this->_type = $this->getAcceptType();
} elseif (! in_array(__EXT__, $this->allowType)) {
// 资源类型非法 则用默认资源类型访问
$this->_type = $this->defaultType;
} else {
$this->_type = __EXT__;
}
// 请求方式检测
$method = strtolower(REQUEST_METHOD);
if (! in_array($method, $this->allowMethod)) {
// 请求方式非法 则用默认请求方法
$method = $this->defaultMethod;
}
$this->_method = $method;
parent::__construct();
}
/**
* 魔术方法 有不存在的操作的时候执行
*
* @access public
*
* @param string $method 方法名
* @param array $args 参数
*
* @return mixed
*/
public function __call($method, $args)
{
if (0 === strcasecmp($method, ACTION_NAME . C('ACTION_SUFFIX'))) {
if (method_exists($this, $method . '_' . $this->_method . '_' . $this->_type)) { // RESTFul方法支持
$fun = $method . '_' . $this->_method . '_' . $this->_type;
$this->$fun();
} elseif ($this->_method == $this->defaultMethod && method_exists($this, $method . '_' . $this->_type)) {
$fun = $method . '_' . $this->_type;
$this->$fun();
} elseif ($this->_type == $this->defaultType && method_exists($this, $method . '_' . $this->_method)) {
$fun = $method . '_' . $this->_method;
$this->$fun();
} elseif (method_exists($this, '_empty')) {
// 如果定义了_empty操作 则调用
$this->_empty($method, $args);
} elseif (file_exists_case($this->view->parseTemplate())) {
// 检查是否存在默认模版 如果有直接输出模版
$this->display();
} else {
if ($this->_build_action()) {
// 报生成成功信息
E(__CLASS__ . ':' . $method . '_' . $this->_method . L('METHOD_CREATED'));
}
E(L('_ERROR_ACTION_') . ':' . ACTION_NAME);
}
}
}
// by zhuxun begin.
// 创建不存在的方法
protected function _build_action()
{
if (APP_DEBUG && cfg('CREATE_ACTION_ON') && I('request._create')) {
// 获取类名
$classname = get_class($this);
// 默认控制层名称
$c_layer = ucfirst(C('DEFAULT_C_LAYER'));
$classname = preg_replace("/" . $c_layer . "$/is", '', $classname);
// 切分路径
$paths = explode("/", str_replace("\\", "/", $classname));
// 获取模块名称
$module = array_shift($paths);
// 剔除控制层目录
array_shift($paths);
// 重新拼接控制层
$controller = implode("/", $paths);
// 创建操作方法
Build::buildAction($module, $controller, ACTION_NAME, true);
return true;
}
return false;
}
/**
* 显示异常
*
* @param mixed $data 异常信息
* @param string $tpl 模板
*
* @return bool
*/
public function showException($data = null, $tpl = '')
{
$this->_response($data);
return true;
}
// end.
/**
* 获取当前请求的Accept头信息
*
* @return string
*/
protected function getAcceptType()
{
$type = array(
'xml' => 'application/xml,text/xml,application/x-xml',
'json' => 'application/json,text/x-json,application/jsonrequest,text/json',
'js' => 'text/javascript,application/javascript,application/x-javascript',
'css' => 'text/css',
'rss' => 'application/rss+xml',
'yaml' => 'application/x-yaml,text/yaml',
'atom' => 'application/atom+xml',
'pdf' => 'application/pdf',
'text' => 'text/plain',
'png' => 'image/png',
'jpg' => 'image/jpg,image/jpeg,image/pjpeg',
'gif' => 'image/gif',
'csv' => 'text/csv',
'html' => 'text/html,application/xhtml+xml,*/*'
);
foreach ($type as $key => $val) {
$array = explode(',', $val);
foreach ($array as $k => $v) {
if (isset($_SERVER['HTTP_ACCEPT']) && stristr($_SERVER['HTTP_ACCEPT'], $v)) {
return $key;
}
}
}
return false;
}
// 发送Http状态信息
protected function sendHttpStatus($code)
{
static $_status = array(
// Informational 1xx
100 => 'Continue',
101 => 'Switching Protocols',
// Success 2xx
200 => 'OK',
201 => 'Created',
202 => 'Accepted',
203 => 'Non-Authoritative Information',
204 => 'No Content',
205 => 'Reset Content',
206 => 'Partial Content',
// Redirection 3xx
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Moved Temporarily ', // 1.1
303 => 'See Other',
304 => 'Not Modified',
305 => 'Use Proxy',
// 306 is deprecated but reserved
307 => 'Temporary Redirect',
// Client Error 4xx
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Timeout',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Requested Range Not Satisfiable',
417 => 'Expectation Failed',
// Server Error 5xx
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
503 => 'Service Unavailable',
504 => 'Gateway Timeout',
505 => 'HTTP Version Not Supported',
509 => 'Bandwidth Limit Exceeded'
);
if (isset($_status[$code])) {
header('HTTP/1.1 ' . $code . ' ' . $_status[$code]);
// 确保FastCGI模式下正常
header('Status:' . $code . ' ' . $_status[$code]);
}
}
/**
* 编码数据
*
* @access protected
*
* @param mixed $data 要返回的数据
* @param String $type 返回类型 JSON XML
*
* @return string
*/
protected function encodeData($data, $type = '')
{
if (empty($data)) {
return '';
}
if ('json' == $type) {
// 返回JSON数据格式到客户端 包含状态信息
if (PHP_VERSION > '5.5') {
$data = json_encode($data, JSON_UNESCAPED_UNICODE|JSON_PARTIAL_OUTPUT_ON_ERROR);
} elseif (PHP_VERSION > '5.4') {
$data = json_encode($data, JSON_UNESCAPED_UNICODE);
} else {
$data = json_encode($data);
}
} elseif ('xml' == $type) {
// 返回xml格式数据
$data = xml_encode($data);
} elseif ('php' == $type) {
$data = serialize($data);
}
// 默认直接输出
$this->setContentType($type);
// header('Content-Length: ' . strlen($data));
return $data;
}
/**
* 设置页面输出的CONTENT_TYPE和编码
*
* @access public
*
* @param string $type content_type 类型对应的扩展名
* @param string $charset 页面输出编码
*
* @return void
*/
public function setContentType($type, $charset = '')
{
if (headers_sent()) {
return;
}
if (empty($charset)) {
$charset = C('DEFAULT_CHARSET');
}
$type = strtolower($type);
if (isset($this->allowOutputType[$type])) { // 过滤content_type
header('Content-Type: ' . $this->allowOutputType[$type] . '; charset=' . $charset);
}
}
/**
* 输出返回数据
*
* @access protected
*
* @param mixed $data 要返回的数据
* @param String $type 返回类型 JSON XML
* @param integer $code HTTP状态
*
* @return void
*/
protected function _response($data, $type = '', $code = 200)
{
$this->sendHttpStatus($code);
exit($this->encodeData($data, strtolower($type)));
}
}