使用PHP的基本RESTful API示例

时间:2013-08-30 10:20:53

标签: php api .htaccess rest

我正在努力获得一个基本的RESTful API示例。目前我正在使用我发现here的示例,但它有一些错误并且不完整。

我已经将以下几行添加到我的.htaccess中,如下所示。

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule api/v1/(.*)$ api/v1/MyAPI.php?request=$1 [QSA,NC,L]
</IfModule>

然而我的问题只是让我的具体课程打印“12”。我不知道要访问哪个URL才能在屏幕上显示消息“12”。

这是我的抽象类代码:

<?php
abstract class API 
{
    /** 
     * Property: method
     * The HTTP method this request was made in, either GET, POST, PUT or DELETE
     */
    protected $method = ''; 
    /** 
     * Property: endpoint
     * The Model requested in the URI. eg: /files
     */
    protected $endpoint = ''; 
    /** 
     * Property: verb
     * An optional additional descriptor about the endpoint, used for things that can
     * not be handled by the basic methods. eg: /files/process
     */
    protected $verb = ''; 
    /** 
     * Property: args
     * Any additional URI components after the endpoint and verb have been removed, in our
     * case, an integer ID for the resource. eg: /<endpoint>/<verb>/<arg0>/<arg1>
     * or /<endpoint>/<arg0>
     */
    protected $args = Array();
    /** 
     * Property: file
     * Stores the input of the PUT request
     */
     protected $file = Null;

    /** 
     * Constructor: __construct
     * Allow for CORS, assemble and pre-process the data
     */
    public function __construct($request) {
        header("Access-Control-Allow-Orgin: *"); //any origin can be processed by this page
        header("Access-Control-Allow-Methods: *"); //any HTTP method can be accepted
        header("Content-Type: application/json");

        $this->args = explode('/', rtrim($request, '/'));
        $this->endpoint = array_shift($this->args);
        if (array_key_exists(0, $this->args) && !is_numeric($this->args[0])) {
            $this->verb = array_shift($this->args);
        }

        $this->method = $_SERVER['REQUEST_METHOD'];
        if ($this->method == 'POST' && array_key_exists('HTTP_X_HTTP_METHOD', $_SERVER)) {
            if ($_SERVER['HTTP_X_HTTP_METHOD'] == 'DELETE') {
                $this->method = 'DELETE';
            } else if ($_SERVER['HTTP_X_HTTP_METHOD'] == 'PUT') {
                $this->method = 'PUT';
            } else {
                throw new Exception("Unexpected Header");
            }
        }

        switch($this->method) {
        case 'DELETE':
        case 'POST':
            $this->request = $this->_cleanInputs($_POST);
            break;
        case 'GET':
            $this->request = $this->_cleanInputs($_GET);
            break;
        case 'PUT':
            $this->request = $this->_cleanInputs($_GET);
            $this->file = file_get_contents("php://input");
            break;
        default:
            $this->_response('Invalid Method', 405);
            break;
        }
    }

    /**
     * Determine if the concrete class implements a method for the endpoint that the client requested. If it does, then it calls that method, otherwise a 404 
     * response is returned
     */
    public function processAPI() {
        if ((int)method_exists($this->endpoint) > 0) {
            return $this->_response($this->{$this->endpoint}($this->args));
        }
        return $this->_response('', 400);
    }

    private function _response($data, $status = 200) {
        header("HTTP/1.1 " . $status . " " . $this->_requestStatus($status));
        return json_encode($data);
    }

    private function _cleanInputs($data) {
        $clean_input = Array();
        if (is_array($data)) {
            foreach ($data as $k => $v) {
                $clean_input[$k] = $this->_cleanInputs($v);
            }
        } else {
            $clean_input = trim(strip_tags($data));
        }
        return $clean_input;
    }

    private function _requestStatus($code) {
        $status = 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 ($status[$code])?$status[$code]:$status[500];
    }
}

这是我的具体类代码(第8行的麻烦):

<?php
require_once 'API.php';
class MyAPI extends API 
{
    protected $User;

    public function __construct($request, $origin)
    {
        echo "12";
        parent::__construct($request);

        // Abstracted out for example
        //$APIKey = new Models\APIKey();
        //$User = new Models\User();

        if (!array_key_exists('apiKey', $this->request)) {
            throw new Exception('No API Key provided');
        } else if (!$APIKey->verifyKey($this->request['apiKey'], $origin)) {
            throw new Exception('Invalid API Key');
        } else if (array_key_exists('token', $this->request) && !$User->get('token', $this->request['token'])){
            throw new Exception('Invalid User Token');
        }

        //$this->User = $User;
    }   

    /** 
     * Example of an Endpoint
     */
    protected function example()
    {
        if ($this->method == 'GET') {
            return "Your name is " . $this->User->name;
        } else {
            return "Only accepts GET requests";
        }
    }   
}

正如您所看到的那样,具体类(在构造函数中)的第8行永远不会被打印出来。目前我正试图通过以下方式使我的示例工作:

www.mysite.com/api/myAPI.php?request=get

2 个答案:

答案 0 :(得分:3)

不确定你是否还需要一个答案,但我只是通过一些调整来完成我的工作。您的设置存在一些问题。首先是.htaccess文件。你有它指向MyAPI.php,但如果你阅读教程,他实际上有第三个文件,api.php,实例化MyAPI类。这一行:

RewriteRule api/v1/(.*)$ api/v1/MyAPI.php?request=$1 [QSA,NC,L]

应该是:

RewriteRule api/v1/(.*)$ api/v1/api.php?request=$1 [QSA,NC,L]

您不应该尝试直接访问MyAPI.php文件。相反,apache应该指向api.php,传递请求详细信息。 api.php文件的内容(每个CM网站)是:

<?php
require_once 'MyAPI.php';
if (!array_key_exists('HTTP_ORIGIN', $_SERVER)) {
    $_SERVER['HTTP_ORIGIN'] = $_SERVER['SERVER_NAME'];
}

try {
    $API = new MyAPI($_REQUEST['request'], $_SERVER['HTTP_ORIGIN']);
    echo $API->processAPI();
} catch (Exception $e) {
    echo json_encode(Array('error' => $e->getMessage()));
}
?>

第二个问题是您的网址 - 您应该按照他传递端点的示例(在他/我的情况下,/ api / v1 / example)。这将生成MyAPI构造函数中的文本(如果您将其留在您的文本中),以及来自示例端点函数的消息。为了它的价值,我剥离了所有关键和用户的东西,这样我才能让它运行起来。所以我的MyAPI.php文件看起来像:

<?php
require_once 'AbstractAPI.php';
class MyAPI extends API 
{
    protected $testmessage;
    public function __construct($request, $origin) {
        parent::__construct($request);
        $this->testmessage = "Test String";
    }
    protected function example()
    {
        return $this->testmessage;  
    }
}
?>

我开始简单,以后再打扮#34;做法。祝你好运!

答案 1 :(得分:2)

在我看来,这个URL违反了REST原则

www.mysite.com/api/myAPI.php?request=get

如果在网址request=get中提及,那么使用HTTP GET的目的就会消失 RESTful网址应该类似于

 www.mysite.com/api/myAPI.php

并且对此网址的HTTP GET请求应该可以正常工作。