Yii1.1 实现简单restful 框架
学习了下php的rest服务,将总结记录如下。采用Yii1.1版本,Yii2已经专门有restful专题(ps:暂时没有学习)
1.先用Yii创建项目
2.创建数据库(rest)和表(rest_user)及对应模型(user)[脚手架创建]
CREATE TABLE `rest_user` ( `id` int AUTO_INCREMENT COMMENT "用户账号", `name` char(32) NOT NULL COMMENT "用户姓名", PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; INSERT INTO `rest_user` VALUES ("1","考勤"), ("2","hu"), ("3","wang"), ("4","fan"), ("5","yuan");
3.在protected/config/main.php中配置路由
"urlManager"=>array( "urlFormat"=>"path", "showScriptName"=>false,//为优化URL去掉index.php入口文件名字准备 "rules"=>array( "user/<id:d+>/<title:.*?>"=>"user/view", "users/<tag:.*?>"=>"users/index", // REST patterns array("api/list", "pattern"=>"api/<model:w+>", "verb"=>"GET"), array("api/view", "pattern"=>"api/<model:w+>/<id:d+>", "verb"=>"GET"), array("api/update", "pattern"=>"api/<model:w+>/<id:d+>", "verb"=>"PUT"), array("api/delete", "pattern"=>"api/<model:w+>/<id:d+>", "verb"=>"DELETE"), array("api/create", "pattern"=>"api/<model:w+>", "verb"=>"POST"), // Other controllers "<controller:w+>/<action:w+>"=>"<controller>/<action>", ), ),
4.建立相关控制器处理rest请求(ApiController.php)
<?php class ApiController extends Controller { // {{{ *** Members *** /** * Key which has to be in HTTP USERNAME and PASSWORD headers */ Const APPLICATION_ID = "ASCCPE"; private $format = "json"; // }}} // {{{ filters /** * @return array action filters */ public function filters() { return array(); } // }}} // {{{ *** Actions *** // {{{ actionIndex public function actionIndex() { echo CJSON::encode(array(1, 2, 3)); } // }}} // {{{ actionList public function actionList() { $this->_checkAuth(); switch($_GET["model"]) { case "users": // {{{ $models = User::model()->findAll(); break; // }}} default: // {{{ $this->_sendResponse(501, sprintf("Error: Mode <b>list</b> is not implemented for model <b>%s</b>",$_GET["model"]) ); exit; // }}} } if(is_null($models)) { $this->_sendResponse(200, sprintf("No items where found for model <b>%s</b>", $_GET["model"]) ); } else { $rows = array(); foreach($models as $model) $rows[] = $model->attributes; $this->_sendResponse(200, CJSON::encode($rows)); } } // }}} // {{{ actionView /* Shows a single item * * @access public * @return void */ public function actionView() { //$this->_checkAuth(); // Check if id was submitted via GET if(!isset($_GET["id"])) $this->_sendResponse(500, "Error: Parameter <b>id</b> is missing" ); var_dump($_GET["id"]); var_dump($_GET["model"]); switch($_GET["model"]) { // Find respective model case "users": // {{{ $model = User::model()->findByPk($_GET["id"]); break; // }}} default: // {{{ $this->_sendResponse(501, sprintf("Mode <b>view</b> is not implemented for model <b>%s</b>",$_GET["model"]) ); exit; // }}} } if(is_null($model)) { $this->_sendResponse(404, "No Item found with id ".$_GET["id"]); } else { $this->_sendResponse(200, $this->_getObjectEncoded($_GET["model"], $model->attributes)); } } // }}} // {{{ actionCreate /** * Creates a new item * * @access public * @return void */ public function actionCreate() { //$this->_checkAuth(); switch($_GET["model"]) { // Get an instance of the respective model case "users": // {{{ $model = new User; break; // }}} default: // {{{ $this->_sendResponse(501, sprintf("Mode <b>create</b> is not implemented for model <b>%s</b>",$_GET["model"]) ); exit; // }}} } // Try to assign POST values to attributes foreach($_POST as $var=>$value) { // Does the model have this attribute? if($model->hasAttribute($var)) { $model->$var = $value; } else { // No, raise an error $this->_sendResponse(500, sprintf("Parameter <b>%s</b> is not allowed for model <b>%s</b>", $var, $_GET["model"]) ); } } // Try to save the model if($model->save()) { // Saving was OK $this->_sendResponse(200, $this->_getObjectEncoded($_GET["model"], $model->attributes) ); } else { // Errors occurred $msg = "<h1>Error</h1>"; $msg .= sprintf("Couldn"t create model <b>%s</b>", $_GET["model"]); $msg .= "<ul>"; foreach($model->errors as $attribute=>$attr_errors) { $msg .= "<li>Attribute: $attribute</li>"; $msg .= "<ul>"; foreach($attr_errors as $attr_error) { $msg .= "<li>$attr_error</li>"; } $msg .= "</ul>"; } $msg .= "</ul>"; $this->_sendResponse(500, $msg ); } var_dump($_REQUEST); } // }}} // {{{ actionUpdate /** * Update a single iten * * @access public * @return void */ public function actionUpdate() { // $this->_checkAuth(); // Get PUT parameters parse_str(file_get_contents("php://input"), $put_vars); switch($_GET["model"]) { // Find respective model case "users": // {{{ $model = User::model()->findByPk($_GET["id"]); break; // }}} default: // {{{ $this->_sendResponse(501, sprintf("Error: Mode <b>update</b> is not implemented for model <b>%s</b>",$_GET["model"]) ); exit; // }}} } if(is_null($model)) $this->_sendResponse(400, sprintf("Error: Didn"t find any model <b>%s</b> with ID <b>%s</b>.",$_GET["model"], $_GET["id"]) ); // Try to assign PUT parameters to attributes foreach($put_vars as $var=>$value) { // Does model have this attribute? if($model->hasAttribute($var)) { $model->$var = $value; } else { // No, raise error $this->_sendResponse(500, sprintf("Parameter <b>%s</b> is not allowed for model <b>%s</b>", $var, $_GET["model"]) ); } } // Try to save the model if($model->save()) { $this->_sendResponse(200, sprintf("The model <b>%s</b> with id <b>%s</b> has been updated.", $_GET["model"], $_GET["id"]) ); } else { $msg = "<h1>Error</h1>"; $msg .= sprintf("Couldn"t update model <b>%s</b>", $_GET["model"]); $msg .= "<ul>"; foreach($model->errors as $attribute=>$attr_errors) { $msg .= "<li>Attribute: $attribute</li>"; $msg .= "<ul>"; foreach($attr_errors as $attr_error) { $msg .= "<li>$attr_error</li>"; } $msg .= "</ul>"; } $msg .= "</ul>"; $this->_sendResponse(500, $msg ); } } // }}} // {{{ actionDelete /** * Deletes a single item * * @access public * @return void */ public function actionDelete() { // $this->_checkAuth(); switch($_GET["model"]) { // Load the respective model case "users": // {{{ $model = User::model()->findByPk($_GET["id"]); break; // }}} default: // {{{ $this->_sendResponse(501, sprintf("Error: Mode <b>delete</b> is not implemented for model <b>%s</b>",$_GET["model"]) ); exit; // }}} } // Was a model found? if(is_null($model)) { // No, raise an error $this->_sendResponse(400, sprintf("Error: Didn"t find any model <b>%s</b> with ID <b>%s</b>.",$_GET["model"], $_GET["id"]) ); } // Delete the model $num = $model->delete(); if($num>0) $this->_sendResponse(200, sprintf("Model <b>%s</b> with ID <b>%s</b> has been deleted.",$_GET["model"], $_GET["id"]) ); else $this->_sendResponse(500, sprintf("Error: Couldn"t delete model <b>%s</b> with ID <b>%s</b>.",$_GET["model"], $_GET["id"]) ); } // }}} // }}} End Actions // {{{ Other Methods // {{{ _sendResponse /** * Sends the API response * * @param int $status * @param string $body * @param string $content_type * @access private * @return void */ private function _sendResponse($status = 200, $body = "", $content_type = "text/html") { $status_header = "HTTP/1.1 " . $status . " " . $this->_getStatusCodeMessage($status); // set the status header($status_header); // set the content type header("Content-type: " . $content_type); // pages with body are easy if($body != "") { // send the body echo $body; exit; } // we need to create the body if none is passed else { // create some body messages $message = ""; // this is purely optional, but makes the pages a little nicer to read // for your users. Since you won"t likely send a lot of different status codes, // this also shouldn"t be too ponderous to maintain switch($status) { case 401: $message = "You must be authorized to view this page."; break; case 404: $message = "The requested URL " . $_SERVER["REQUEST_URI"] . " was not found."; break; case 500: $message = "The server encountered an error processing your request."; break; case 501: $message = "The requested method is not implemented."; break; } // servers don"t always have a signature turned on (this is an apache directive "ServerSignature On") $signature = ($_SERVER["SERVER_SIGNATURE"] == "") ? $_SERVER["SERVER_SOFTWARE"] . " Server at " . $_SERVER["SERVER_NAME"] . " Port " . $_SERVER["SERVER_PORT"] : $_SERVER["SERVER_SIGNATURE"]; // this should be templatized in a real-world solution $body = "<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <title>" . $status . " " . $this->_getStatusCodeMessage($status) . "</title> </head> <body> <h1>" . $this->_getStatusCodeMessage($status) . "</h1> <p>" . $message . "</p> <hr /> <address>" . $signature . "</address> </body> </html>"; echo $body; exit; } } // }}} // {{{ _getStatusCodeMessage /** * Gets the message for a status code * * @param mixed $status * @access private * @return string */ private function _getStatusCodeMessage($status) { // these could be stored in a .ini file and loaded // via parse_ini_file()... however, this will suffice // for an example $codes = Array( 100 => "Continue", 101 => "Switching Protocols", 200 => "OK", 201 => "Created", 202 => "Accepted", 203 => "Non-Authoritative Information", 204 => "No Content", 205 => "Reset Content", 206 => "Partial Content", 300 => "Multiple Choices", 301 => "Moved Permanently", 302 => "Found", 303 => "See Other", 304 => "Not Modified", 305 => "Use Proxy", 306 => "(Unused)", 307 => "Temporary Redirect", 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", 500 => "Internal Server Error", 501 => "Not Implemented", 502 => "Bad Gateway", 503 => "Service Unavailable", 504 => "Gateway Timeout", 505 => "HTTP Version Not Supported" ); return (isset($codes[$status])) ? $codes[$status] : ""; } // }}} // {{{ _checkAuth /** * Checks if a request is authorized * * @access private * @return void */ private function _checkAuth() { // Check if we have the USERNAME and PASSWORD HTTP headers set? if(!(isset($_SERVER["HTTP_X_".self::APPLICATION_ID."_USERNAME"]) and isset($_SERVER["HTTP_X_".self::APPLICATION_ID."_PASSWORD"]))) { // Error: Unauthorized $this->_sendResponse(401); } $username = $_SERVER["HTTP_X_".self::APPLICATION_ID."_USERNAME"]; $password = $_SERVER["HTTP_X_".self::APPLICATION_ID."_PASSWORD"]; // Find the user $user=User::model()->find("LOWER(username)=?",array(strtolower($username))); if($user===null) { // Error: Unauthorized $this->_sendResponse(401, "Error: User Name is invalid"); } else if(!$user->validatePassword($password)) { // Error: Unauthorized $this->_sendResponse(401, "Error: User Password is invalid"); } } // }}} // {{{ _getObjectEncoded /** * Returns the json or xml encoded array * * @param mixed $model * @param mixed $array Data to be encoded * @access private * @return void */ private function _getObjectEncoded($model, $array) { if(isset($_GET["format"])) $this->format = $_GET["format"]; if($this->format=="json") { return CJSON::encode($array); } elseif($this->format=="xml") { $result = "<?xml version="1.0">"; $result .= " <$model> "; foreach($array as $key=>$value) $result .= " <$key>".utf8_encode($value)."</$key> "; $result .= "</".$model.">"; return $result; } else { return; } } // }}} // }}} End Other Methods } /* vim:set ai sw=4 sts=4 et fdm=marker fdc=4: */ ?>
到此即生成简单的rest框架
下面的get请求id的效果
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。
- 上一篇: 从字符串中提取出汉字?
- 下一篇: Session原理解释,为什么使用session