牛骨文教育服务平台(让学习变的简单)
博文笔记

Yii1.1 实现简单restful 框架

创建时间:2014-11-13 投稿人: 浏览次数:3270

学习了下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的效果




声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。