| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 |
- <?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\App;
- use Think\Controller;
- /**
- * 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;
- App::invokeAction($this, $fun);
- } elseif ($this->_method == $this->defaultMethod && method_exists($this, $method . '_' . $this->_type)) {
- $fun = $method . '_' . $this->_type;
- App::invokeAction($this, $fun);
- } elseif ($this->_type == $this->defaultType && method_exists($this, $method . '_' . $this->_method)) {
- $fun = $method . '_' . $this->_method;
- App::invokeAction($this, $fun);
- } elseif (method_exists($this, '_empty')) {
- // 如果定义了_empty操作 则调用
- $this->_empty($method, $args);
- } elseif (file_exists_case($this->view->parseTemplate())) {
- // 检查是否存在默认模版 如果有直接输出模版
- $this->display();
- } else {
- E(L('_ERROR_ACTION_') . ':' . ACTION_NAME);
- }
- }
- }
- /**
- * 获取当前请求的Accept头信息
- * @return string
- */
- protected function getAcceptType()
- {
- $type = array(
- 'html' => 'text/html,application/xhtml+xml,*/*',
- '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',
- );
- foreach ($type as $key => $val) {
- $array = explode(',', $val);
- foreach ($array as $k => $v) {
- if (array_key_exists('HTTP_ACCEPT', $_SERVER)) {
- if (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 (version_compare(PHP_VERSION, '5.4.0', '<')) {
- $this->arrayRecursive($data, 'urlencode', true);
- $data = urldecode(json_encode($data));
- } else {
- $data = json_encode($data, JSON_UNESCAPED_UNICODE);
- }
- } elseif ('xml' == $type) {
- // 返回xml格式数据
- $data = xml_encode($data);
- } elseif ('php' == $type) {
- $data = serialize($data);
- } // 默认直接输出
- $this->setContentType($type);
- //header('Content-Length: ' . strlen($data));
- return $data;
- }
- /**************************************************************
- *
- * 使用特定function对数组中所有元素做处理
- * @param string|array &$array 要处理的字符串或者数组
- * @param string $function 要执行的函数
- * @return boolean $apply_to_keys_also 是否也应用到key上
- * @access protected
- *
- *************************************************************/
- protected function arrayRecursive(&$array, $function, $apply_to_keys_also = false)
- {
- static $recursive_counter = 0;
- if (++$recursive_counter > 1000) {
- die('possible deep recursion attack');
- }
- foreach ($array as $key => $value) {
- if (is_array($value)) {
- $this->arrayRecursive($array[$key], $function, $apply_to_keys_also);
- } elseif (is_string($value)) {
- $array[$key] = $function($value);
- }
- if ($apply_to_keys_also && is_string($key)) {
- $new_key = $function($key);
- if ($new_key != $key) {
- $array[$new_key] = $array[$key];
- unset($array[$key]);
- }
- }
- }
- $recursive_counter--;
- }
- /**
- * 设置页面输出的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)));
- }
- }
|