Action.class.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006-2012 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. /**
  12. * ThinkPHP RESTFul 控制器基类 抽象类
  13. * @category Think
  14. * @package Think
  15. * @subpackage Core
  16. * @author liu21st <liu21st@gmail.com>
  17. */
  18. abstract class Action {
  19. // 当前Action名称
  20. private $name = '';
  21. // 视图实例
  22. protected $view = null;
  23. protected $_method = ''; // 当前请求类型
  24. protected $_type = ''; // 当前资源类型
  25. // 输出类型
  26. protected $_types = array();
  27. /**
  28. * 架构函数 取得模板对象实例
  29. * @access public
  30. */
  31. public function __construct() {
  32. //实例化视图类
  33. $this->view = Think::instance('View');
  34. defined('__EXT__') or define('__EXT__','');
  35. if(''== __EXT__ || false === stripos(C('REST_CONTENT_TYPE_LIST'),__EXT__)) {
  36. // 资源类型没有指定或者非法 则用默认资源类型访问
  37. $this->_type = C('REST_DEFAULT_TYPE');
  38. }else{
  39. $this->_type = __EXT__;
  40. }
  41. // 请求方式检测
  42. $method = strtolower($_SERVER['REQUEST_METHOD']);
  43. if(false === stripos(C('REST_METHOD_LIST'),$method)) {
  44. // 请求方式非法 则用默认请求方法
  45. $method = C('REST_DEFAULT_METHOD');
  46. }
  47. $this->_method = $method;
  48. // 允许输出的资源类型
  49. $this->_types = C('REST_OUTPUT_TYPE');
  50. //控制器初始化
  51. if(method_exists($this,'_initialize'))
  52. $this->_initialize();
  53. }
  54. /**
  55. * 获取当前Action名称
  56. * @access protected
  57. */
  58. protected function getActionName() {
  59. if(empty($this->name)) {
  60. // 获取Action名称
  61. $this->name = substr(get_class($this),0,-6);
  62. }
  63. return $this->name;
  64. }
  65. /**
  66. * 是否AJAX请求
  67. * @access protected
  68. * @return bool
  69. */
  70. protected function isAjax() {
  71. if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) ) {
  72. if('xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH']))
  73. return true;
  74. }
  75. if(!empty($_POST[C('VAR_AJAX_SUBMIT')]) || !empty($_GET[C('VAR_AJAX_SUBMIT')]))
  76. // 判断Ajax方式提交
  77. return true;
  78. return false;
  79. }
  80. /**
  81. * 魔术方法 有不存在的操作的时候执行
  82. * @access public
  83. * @param string $method 方法名
  84. * @param array $args 参数
  85. * @return mixed
  86. */
  87. public function __call($method,$args) {
  88. if( 0 === strcasecmp($method,ACTION_NAME.C('ACTION_SUFFIX'))) {
  89. if(method_exists($this,$method.'_'.$this->_method.'_'.$this->_type)) { // RESTFul方法支持
  90. $fun = $method.'_'.$this->_method.'_'.$this->_type;
  91. $this->$fun();
  92. }elseif($this->_method == C('REST_DEFAULT_METHOD') && method_exists($this,$method.'_'.$this->_type) ){
  93. $fun = $method.'_'.$this->_type;
  94. $this->$fun();
  95. }elseif($this->_type == C('REST_DEFAULT_TYPE') && method_exists($this,$method.'_'.$this->_method) ){
  96. $fun = $method.'_'.$this->_method;
  97. $this->$fun();
  98. }elseif(method_exists($this,'_empty')) {
  99. // 如果定义了_empty操作 则调用
  100. $this->_empty($method,$args);
  101. }elseif(file_exists_case(C('TMPL_FILE_NAME'))){
  102. // 检查是否存在默认模版 如果有直接输出模版
  103. $this->display();
  104. }else{
  105. // 抛出异常
  106. throw_exception(L('_ERROR_ACTION_').ACTION_NAME);
  107. }
  108. }else{
  109. switch(strtolower($method)) {
  110. // 获取变量 支持过滤和默认值 调用方式 $this->_post($key,$filter,$default);
  111. case '_get': $input =& $_GET;break;
  112. case '_post':$input =& $_POST;break;
  113. case '_put':
  114. case '_delete':parse_str(file_get_contents('php://input'), $input);break;
  115. case '_request': $input =& $_REQUEST;break;
  116. case '_session': $input =& $_SESSION;break;
  117. case '_cookie': $input =& $_COOKIE;break;
  118. case '_server': $input =& $_SERVER;break;
  119. default:
  120. throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_'));
  121. }
  122. if(isset($input[$args[0]])) { // 取值操作
  123. $data = $input[$args[0]];
  124. $fun = $args[1]?$args[1]:C('DEFAULT_FILTER');
  125. $data = $fun($data); // 参数过滤
  126. }else{ // 变量默认值
  127. $data = isset($args[2])?$args[2]:NULL;
  128. }
  129. return $data;
  130. }
  131. }
  132. /**
  133. * 模板显示
  134. * 调用内置的模板引擎显示方法,
  135. * @access protected
  136. * @param string $templateFile 指定要调用的模板文件
  137. * 默认为空 由系统自动定位模板文件
  138. * @param string $charset 输出编码
  139. * @param string $contentType 输出类型
  140. * @return void
  141. */
  142. protected function display($templateFile='',$charset='',$contentType='') {
  143. $this->view->display($templateFile,$charset,$contentType);
  144. }
  145. /**
  146. * 模板变量赋值
  147. * @access protected
  148. * @param mixed $name 要显示的模板变量
  149. * @param mixed $value 变量的值
  150. * @return void
  151. */
  152. protected function assign($name,$value='') {
  153. $this->view->assign($name,$value);
  154. }
  155. public function __set($name,$value) {
  156. $this->view->assign($name,$value);
  157. }
  158. /**
  159. * 设置页面输出的CONTENT_TYPE和编码
  160. * @access public
  161. * @param string $type content_type 类型对应的扩展名
  162. * @param string $charset 页面输出编码
  163. * @return void
  164. */
  165. public function setContentType($type, $charset=''){
  166. if(headers_sent()) return;
  167. if(empty($charset)) $charset = C('DEFAULT_CHARSET');
  168. $type = strtolower($type);
  169. if(isset($this->_types[$type])) //过滤content_type
  170. header('Content-Type: '.$this->_types[$type].'; charset='.$charset);
  171. }
  172. /**
  173. * 输出返回数据
  174. * @access protected
  175. * @param mixed $data 要返回的数据
  176. * @param String $type 返回类型 JSON XML
  177. * @param integer $code HTTP状态
  178. * @return void
  179. */
  180. protected function response($data,$type='',$code=200) {
  181. $this->sendHttpStatus($code);
  182. exit($this->encodeData($data,strtolower($type)));
  183. }
  184. /**
  185. * 编码数据
  186. * @access protected
  187. * @param mixed $data 要返回的数据
  188. * @param String $type 返回类型 JSON XML
  189. * @return void
  190. */
  191. protected function encodeData($data,$type='') {
  192. if(empty($data)) return '';
  193. if(empty($type)) $type = $this->_type;
  194. if('json' == $type) {
  195. // 返回JSON数据格式到客户端 包含状态信息
  196. $data = json_encode($data);
  197. }elseif('xml' == $type){
  198. // 返回xml格式数据
  199. $data = xml_encode($data);
  200. }elseif('php'==$type){
  201. $data = serialize($data);
  202. }// 默认直接输出
  203. $this->setContentType($type);
  204. header('Content-Length: ' . strlen($data));
  205. return $data;
  206. }
  207. // 发送Http状态信息
  208. protected function sendHttpStatus($code) {
  209. static $_status = array(
  210. // Informational 1xx
  211. 100 => 'Continue',
  212. 101 => 'Switching Protocols',
  213. // Success 2xx
  214. 200 => 'OK',
  215. 201 => 'Created',
  216. 202 => 'Accepted',
  217. 203 => 'Non-Authoritative Information',
  218. 204 => 'No Content',
  219. 205 => 'Reset Content',
  220. 206 => 'Partial Content',
  221. // Redirection 3xx
  222. 300 => 'Multiple Choices',
  223. 301 => 'Moved Permanently',
  224. 302 => 'Moved Temporarily ', // 1.1
  225. 303 => 'See Other',
  226. 304 => 'Not Modified',
  227. 305 => 'Use Proxy',
  228. // 306 is deprecated but reserved
  229. 307 => 'Temporary Redirect',
  230. // Client Error 4xx
  231. 400 => 'Bad Request',
  232. 401 => 'Unauthorized',
  233. 402 => 'Payment Required',
  234. 403 => 'Forbidden',
  235. 404 => 'Not Found',
  236. 405 => 'Method Not Allowed',
  237. 406 => 'Not Acceptable',
  238. 407 => 'Proxy Authentication Required',
  239. 408 => 'Request Timeout',
  240. 409 => 'Conflict',
  241. 410 => 'Gone',
  242. 411 => 'Length Required',
  243. 412 => 'Precondition Failed',
  244. 413 => 'Request Entity Too Large',
  245. 414 => 'Request-URI Too Long',
  246. 415 => 'Unsupported Media Type',
  247. 416 => 'Requested Range Not Satisfiable',
  248. 417 => 'Expectation Failed',
  249. // Server Error 5xx
  250. 500 => 'Internal Server Error',
  251. 501 => 'Not Implemented',
  252. 502 => 'Bad Gateway',
  253. 503 => 'Service Unavailable',
  254. 504 => 'Gateway Timeout',
  255. 505 => 'HTTP Version Not Supported',
  256. 509 => 'Bandwidth Limit Exceeded'
  257. );
  258. if(isset($_status[$code])) {
  259. header('HTTP/1.1 '.$code.' '.$_status[$code]);
  260. // 确保FastCGI模式下正常
  261. header('Status:'.$code.' '.$_status[$code]);
  262. }
  263. }
  264. /**
  265. * 析构方法
  266. * @access public
  267. */
  268. public function __destruct() {
  269. // 保存日志
  270. if(C('LOG_RECORD')) Log::save();
  271. // 执行后续操作
  272. tag('action_end');
  273. }
  274. }