PageRenderTime 58ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/source/Library/Think/Controller/RestController.class.php

https://gitlab.com/fangjianwei/weifenxiao
PHP | 234 lines | 150 code | 10 blank | 74 comment | 18 complexity | 8ae9db1509e35e1c126d91cf9e8d525c MD5 | raw file
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. namespace Think\Controller;
  12. use Think\Controller;
  13. /**
  14. * ThinkPHP REST控制器类
  15. */
  16. class RestController extends Controller {
  17. // 当前请求类型
  18. protected $_method = '';
  19. // 当前请求的资源类型
  20. protected $_type = '';
  21. // REST允许的请求类型列表
  22. protected $allowMethod = array('get','post','put','delete');
  23. // REST默认请求类型
  24. protected $defaultMethod = 'get';
  25. // REST允许请求的资源类型列表
  26. protected $allowType = array('html','xml','json','rss');
  27. // 默认的资源类型
  28. protected $defaultType = 'html';
  29. // REST允许输出的资源类型列表
  30. protected $allowOutputType= array(
  31. 'xml' => 'application/xml',
  32. 'json' => 'application/json',
  33. 'html' => 'text/html',
  34. );
  35. /**
  36. * 架构函数
  37. * @access public
  38. */
  39. public function __construct() {
  40. // 资源类型检测
  41. if(''==__EXT__) { // 自动检测资源类型
  42. $this->_type = $this->getAcceptType();
  43. }elseif(!in_array(__EXT__,$this->allowType)) {
  44. // 资源类型非法 则用默认资源类型访问
  45. $this->_type = $this->defaultType;
  46. }else{
  47. // 检测实际资源类型
  48. $this->_type = $this->getAcceptType() == __EXT__ ? __EXT__ : $this->defaultType;
  49. }
  50. // 请求方式检测
  51. $method = strtolower(REQUEST_METHOD);
  52. if(!in_array($method,$this->allowMethod)) {
  53. // 请求方式非法 则用默认请求方法
  54. $method = $this->defaultMethod;
  55. }
  56. $this->_method = $method;
  57. parent::__construct();
  58. }
  59. /**
  60. * 魔术方法 有不存在的操作的时候执行
  61. * @access public
  62. * @param string $method 方法名
  63. * @param array $args 参数
  64. * @return mixed
  65. */
  66. public function __call($method,$args) {
  67. if( 0 === strcasecmp($method,ACTION_NAME.C('ACTION_SUFFIX'))) {
  68. if(method_exists($this,$method.'_'.$this->_method.'_'.$this->_type)) { // RESTFul方法支持
  69. $fun = $method.'_'.$this->_method.'_'.$this->_type;
  70. $this->$fun();
  71. }elseif($this->_method == $this->defaultMethod && method_exists($this,$method.'_'.$this->_type) ){
  72. $fun = $method.'_'.$this->_type;
  73. $this->$fun();
  74. }elseif($this->_type == $this->defaultType && method_exists($this,$method.'_'.$this->_method) ){
  75. $fun = $method.'_'.$this->_method;
  76. $this->$fun();
  77. }elseif(method_exists($this,'_empty')) {
  78. // 如果定义了_empty操作 则调用
  79. $this->_empty($method,$args);
  80. }elseif(file_exists_case($this->view->parseTemplate())){
  81. // 检查是否存在默认模版 如果有直接输出模版
  82. $this->display();
  83. }else{
  84. E(L('_ERROR_ACTION_').':'.ACTION_NAME);
  85. }
  86. }
  87. }
  88. /**
  89. * 获取当前请求的Accept头信息
  90. * @return string
  91. */
  92. protected function getAcceptType(){
  93. $type = array(
  94. 'html' => 'text/html,application/xhtml+xml,*/*',
  95. 'xml' => 'application/xml,text/xml,application/x-xml',
  96. 'json' => 'application/json,text/x-json,application/jsonrequest,text/json',
  97. 'js' => 'text/javascript,application/javascript,application/x-javascript',
  98. 'css' => 'text/css',
  99. 'rss' => 'application/rss+xml',
  100. 'yaml' => 'application/x-yaml,text/yaml',
  101. 'atom' => 'application/atom+xml',
  102. 'pdf' => 'application/pdf',
  103. 'text' => 'text/plain',
  104. 'png' => 'image/png',
  105. 'jpg' => 'image/jpg,image/jpeg,image/pjpeg',
  106. 'gif' => 'image/gif',
  107. 'csv' => 'text/csv'
  108. );
  109. foreach($type as $key=>$val){
  110. $array = explode(',',$val);
  111. foreach($array as $k=>$v){
  112. if(stristr($_SERVER['HTTP_ACCEPT'], $v)) {
  113. return $key;
  114. }
  115. }
  116. }
  117. return false;
  118. }
  119. // 发送Http状态信息
  120. protected function sendHttpStatus($code) {
  121. static $_status = array(
  122. // Informational 1xx
  123. 100 => 'Continue',
  124. 101 => 'Switching Protocols',
  125. // Success 2xx
  126. 200 => 'OK',
  127. 201 => 'Created',
  128. 202 => 'Accepted',
  129. 203 => 'Non-Authoritative Information',
  130. 204 => 'No Content',
  131. 205 => 'Reset Content',
  132. 206 => 'Partial Content',
  133. // Redirection 3xx
  134. 300 => 'Multiple Choices',
  135. 301 => 'Moved Permanently',
  136. 302 => 'Moved Temporarily ', // 1.1
  137. 303 => 'See Other',
  138. 304 => 'Not Modified',
  139. 305 => 'Use Proxy',
  140. // 306 is deprecated but reserved
  141. 307 => 'Temporary Redirect',
  142. // Client Error 4xx
  143. 400 => 'Bad Request',
  144. 401 => 'Unauthorized',
  145. 402 => 'Payment Required',
  146. 403 => 'Forbidden',
  147. 404 => 'Not Found',
  148. 405 => 'Method Not Allowed',
  149. 406 => 'Not Acceptable',
  150. 407 => 'Proxy Authentication Required',
  151. 408 => 'Request Timeout',
  152. 409 => 'Conflict',
  153. 410 => 'Gone',
  154. 411 => 'Length Required',
  155. 412 => 'Precondition Failed',
  156. 413 => 'Request Entity Too Large',
  157. 414 => 'Request-URI Too Long',
  158. 415 => 'Unsupported Media Type',
  159. 416 => 'Requested Range Not Satisfiable',
  160. 417 => 'Expectation Failed',
  161. // Server Error 5xx
  162. 500 => 'Internal Server Error',
  163. 501 => 'Not Implemented',
  164. 502 => 'Bad Gateway',
  165. 503 => 'Service Unavailable',
  166. 504 => 'Gateway Timeout',
  167. 505 => 'HTTP Version Not Supported',
  168. 509 => 'Bandwidth Limit Exceeded'
  169. );
  170. if(isset($_status[$code])) {
  171. header('HTTP/1.1 '.$code.' '.$_status[$code]);
  172. // 确保FastCGI模式下正常
  173. header('Status:'.$code.' '.$_status[$code]);
  174. }
  175. }
  176. /**
  177. * 编码数据
  178. * @access protected
  179. * @param mixed $data 要返回的数据
  180. * @param String $type 返回类型 JSON XML
  181. * @return string
  182. */
  183. protected function encodeData($data,$type='') {
  184. if(empty($data)) return '';
  185. if('json' == $type) {
  186. // 返回JSON数据格式到客户端 包含状态信息
  187. $data = json_encode($data);
  188. }elseif('xml' == $type){
  189. // 返回xml格式数据
  190. $data = xml_encode($data);
  191. }elseif('php'==$type){
  192. $data = serialize($data);
  193. }// 默认直接输出
  194. $this->setContentType($type);
  195. //header('Content-Length: ' . strlen($data));
  196. return $data;
  197. }
  198. /**
  199. * 设置页面输出的CONTENT_TYPE和编码
  200. * @access public
  201. * @param string $type content_type 类型对应的扩展名
  202. * @param string $charset 页面输出编码
  203. * @return void
  204. */
  205. public function setContentType($type, $charset=''){
  206. if(headers_sent()) return;
  207. if(empty($charset)) $charset = C('DEFAULT_CHARSET');
  208. $type = strtolower($type);
  209. if(isset($this->allowOutputType[$type])) //过滤content_type
  210. header('Content-Type: '.$this->allowOutputType[$type].'; charset='.$charset);
  211. }
  212. /**
  213. * 输出返回数据
  214. * @access protected
  215. * @param mixed $data 要返回的数据
  216. * @param String $type 返回类型 JSON XML
  217. * @param integer $code HTTP状态
  218. * @return void
  219. */
  220. protected function response($data,$type='',$code=200) {
  221. $this->sendHttpStatus($code);
  222. exit($this->encodeData($data,strtolower($type)));
  223. }
  224. }