PHP 5 RESTful
REST(英文:Representational State Transfer) ,指的是一组架构约束条件和原则
符合 REST 设计风格的 Web API 称为 RESTful API
它从以下三个方面资源进行定义:
- 直观简短的资源地址:URI,比如:
http://example.com/resources/
- 传输的资源:Web 服务接受与返回的互联网媒体类型,比如:JSON,XML,YAML
- 对资源的操作:Web 服务在该资源上所支持的一系列请求方法(比如:POST,GET,PUT或DELETE)
本教程我们使用纯 PHP (不用框架) 来创建一个 RESTful web service
我们会在本章内容中讲述一下内容
- 创建一个 RESTful Webservice
- 使用原生 PHP, 不依赖任何框架
- URI 模式需要遵循 REST 规则
- RESTful service 接受与返回的格式可以是 JSON, XML 等
- 根据不同情况响应对应的 HTTP 状态码
- 演示请求头的使用
- 使用 REST 客户端来测试 RESTful web service
现在,就让我们一步一步来开发一个简单的 Web Services 把
1. 创建 site.php
<?php /* * 简单编程 RESTful 演示范例 * RESTful 服务类 */ class Site { private $sites = array ( 1 => 'TaoBao', 2 => 'Google', 3 => 'Twle', 4 => 'Baidu', 5 => 'Weibo', 6 => 'Sina' ); public function getAllSite() { return $this->sites; } public function getSite($id) { return array($id => ($this->sites[$id]) ? $this->sites[$id] : $this->sites[1]); } }
2. 添加 RESTful Services URI 映射
RESTful Services URI 应该设置为一个直观简短的资源地址
Apache 服务器的 .htaccess 应设置好对应的 Rewrite 规则
在本范例中,我们将使用两个 URI 规则
-
获取所有站点列表
http://localhost/rest/site/list
-
使用 id 获取指定的站点,以下 URI 为获取 id 为 3 的站点
http://localhost/rest/site/list/3
项目的 .htaccess 文件配置规则如下所示
# 开启 rewrite 功能 Options +FollowSymlinks RewriteEngine on # 重写规则 RewriteRule ^/rest/site/list/$ RestController.php?view=all [nc,qsa] RewriteRule ^/rest/site/list/([0-9]+)/$ RestController.php?view=single&id=$1 [nc,qsa]
3. 添加 RESTful Web Service 控制器
在 .htaccess 文件中,我们通过设置参数 'view' 来获取 RestController.php 文件中对应的请求,通过获取 'view' 不同的参数来分发到不同的方法上
RestController.php
<?php require_once("RestHandler.php"); $view = ""; if(isset($_GET["view"])) $view = $_GET["view"]; /* * RESTful service 控制器 * URL 映射 */ switch($view) { case "all": // 处理 REST Url /rest/site/list/ $siteRestHandler = new SiteRestHandler(); $siteRestHandler->getAllSites(); break; case "single": // 处理 REST Url /rest/site/show/<id>/ $siteRestHandler = new SiteRestHandler(); $siteRestHandler->getSite( intval($_GET["id"])); break; case "" : //404 - not found; break; }
4. 简单的 RESTful 基础类
下面我们来创建一个 RESTful 的一个基类,用于处理响应请求的 HTTP 状态码
SimpleRest.php
<?php /* * 一个简单的 RESTful web services 基类 * 我们可以基于这个类来扩展需求 */ class SimpleRest { private $httpVersion = "HTTP/1.1"; public function setHttpHeaders($contentType, $statusCode) { $statusMessage = $this -> getHttpStatusMessage($statusCode); header($this->httpVersion. " ". $statusCode ." ". $statusMessage); header("Content-Type:". $contentType); } public function getHttpStatusMessage($statusCode) { $httpStatus = 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 ($httpStatus[$statusCode]) ? $httpStatus[$statusCode] : $status[500]; } }
5. 创建 RESTful Web Service 处理类
现在来创建一个 RESTful Web Service 处理类 RestHandler.php,继承自 SimpleRest
类中通过判断请求的参数来决定返回的 HTTP 状态码及数据格式
代码中我们提供了三种数据格式: "application/json" 、 "application/xml" 或 "text/html"
RestHandler.php
<?php require_once("SimpleRest.php"); require_once("Site.php"); class SiteRestHandler extends SimpleRest { function getAllSites() { $site = new Site(); $rawData = $site->getAllSite(); if(empty($rawData)) { $statusCode = 404; $rawData = array('error' => 'No sites found!'); } else { $statusCode = 200; } $requestContentType = $_SERVER['HTTP_ACCEPT']; $this ->setHttpHeaders($requestContentType, $statusCode); if(strpos($requestContentType,'application/json') !== false) { $response = $this->encodeJson($rawData); echo $response; } else if(strpos($requestContentType,'text/html') !== false) { $response = $this->encodeHtml($rawData); echo $response; } else if(strpos($requestContentType,'application/xml') !== false) { $response = $this->encodeXml($rawData); echo $response; } } public function encodeHtml($responseData) { $htmlResponse = "<table border='1'>"; foreach($responseData as $key=>$value) { $htmlResponse .= "<tr><td>". $key. "</td><td>". $value. "</td></tr>"; } $htmlResponse .= "</table>"; return $htmlResponse; } public function encodeJson($responseData) { $jsonResponse = json_encode($responseData); return $jsonResponse; } public function encodeXml($responseData) { // 创建 SimpleXMLElement 对象 $xml = new SimpleXMLElement('<?xml version="1.0"?><site></site>'); foreach($responseData as $key=>$value) { $xml->addChild($key, $value); } return $xml->asXML(); } public function getSite($id) { $site = new Site(); $rawData = $site->getSite($id); if(empty($rawData)) { $statusCode = 404; $rawData = array('error' => 'No sites found!'); } else { $statusCode = 200; } $requestContentType = $_SERVER['HTTP_ACCEPT']; $this ->setHttpHeaders($requestContentType, $statusCode); if(strpos($requestContentType,'application/json') !== false) { $response = $this->encodeJson($rawData); echo $response; } else if(strpos($requestContentType,'text/html') !== false) { $response = $this->encodeHtml($rawData); echo $response; } else if(strpos($requestContentType,'application/xml') !== false) { $response = $this->encodeXml($rawData); echo $response; } } }
接下来就可以通过访问 http://localhost/rest/site/list/
RESTful Web Service 客户端
我们使用 Google Chrome 浏览器的 "Advance Rest Client" 作为 RESTful Web Service 客户端来请求我们的服务