GITHUB:https://github.com/jacwright/RestServer
简介:
一个PHP REST服务器,用于提供非常轻量级的REST API。很容易上手。独立于其他库和框架。支持HTTP身份验证。
参考Zend Framework,该框架省略了Zend Framework MVC附带的大量类。还有一些有用的功能要添加(例如XML支持)。
RestServer
到目前为止,该框架的解决方案是一个JSON REST服务器。添加对XML或其他格式的支持应该是微不足道的,但是必须假设您的对象在XML中的样子(XML-RPC样式,您自己的自定义XML格式等)。
首先,我们将查看您编写的用于处理请求的类,然后我们将查看如何在index.php文件中将它们绑定在一起。
使用教程:
从URL到类方法获取请求的映射都在类的doc-comments中。以下是处理某些用户操作的类的示例:
<?php use \Jacwright\RestServer\RestException; class TestController
{
/**
* Returns a JSON string object to the browser when hitting the root of the domain
*
* @url GET /
*/
public function test()
{
return "Hello World";
} /**
* Logs in a user with the given username and password POSTed. Though true
* REST doesn't believe in sessions, it is often desirable for an AJAX server.
*
* @url POST /login
*/
public function login()
{
$username = $_POST['username'];
$password = $_POST['password']; //@todo remove since it is not needed anywhere
return array("success" => "Logged in " . $username);
} /**
* Gets the user by id or current user
*
* @url GET /users/$id
* @url GET /users/current
*/
public function getUser($id = null)
{
// if ($id) {
// $user = User::load($id); // possible user loading method
// } else {
// $user = $_SESSION['user'];
// } return array("id" => $id, "name" => null); // serializes object into JSON
} /**
* Saves a user to the database
*
* @url POST /users
* @url PUT /users/$id
*/
public function saveUser($id = null, $data)
{
// ... validate $data properties such as $data->username, $data->firstName, etc.
// $data->id = $id;
// $user = User::saveUser($data); // saving the user to the database
$user = array("id" => $id, "name" => null);
return $user; // returning the updated or newly created user object
} /**
* Gets user list
*
* @url GET /users
*/
public function listUsers($query)
{
$users = array('Andra Combes', 'Valerie Shirkey', 'Manda Douse', 'Nobuko Fisch', 'Roger Hevey');
if (isset($query['search'])) {
$users = preg_grep("/{$query[search]}/i", $users);
}
return $users; // serializes object into JSON
} /**
* Get Charts
*
* @url GET /charts
* @url GET /charts/$id
* @url GET /charts/$id/$date
* @url GET /charts/$id/$date/$interval/
* @url GET /charts/$id/$date/$interval/$interval_months
*/
public function getCharts($id=null, $date=null, $interval = 30, $interval_months = 12)
{
echo "$id, $date, $interval, $interval_months";
} /**
* Throws an error
*
* @url GET /error
*/
public function throwError() {
throw new RestException(401, "Empty password not allowed");
}
}
让我们通过上面的TestController
课程来讨论所展示的功能。首先我们来看看这个test
方法。您会注意到docblock中有一种新的doc-comment标记。@url
将URL映射到它下面的方法,格式如下:
@url <REQUEST_METHOD> <URL>
在这个特定的例子中,当某人在http://www.example.com/上进行GET时(假设example.com是我们的服务所在的位置),它将打印出来:
"Hello World"
这是JSON中字符串的有效表示。
继续下一个方法,login
我们看到@url
将任何POST映射到http://www.example.com/login到该login
方法。从常规Web类型的POST获取数据与任何PHP应用程序相同,允许您将自己的验证或其他框架与此REST服务器结合使用。如果需要,也可以保留会话。虽然保持会话不是真正的REST风格,但我们通常只需要一个REST服务器来为我们的ajax应用程序提供数据,并且使用会话比使用RESTful更容易。
接下来我们有了我们的getUser
方法(你会注意到我命名我的方法并不重要,因为我们的@url
指令定义了哪些URL映射到方法)。你可以在这里看到几件事。首先,我们@url
为此方法提供了多个映射。第二,/$id
第一个URL映射有一个奇怪的地方。RestServer将任何:keyword
占位符视为URL中的通配符,并将获取URL的该部分并将其传递给方法中具有相同名称的参数。在此示例中,当访问http://www.example.com/users/1234时,$id
将等于1234.当访问http://www.example.com/users/current时,$id
将等于null。您的参数的顺序无关紧要,只要它们与占位符(:id
和$id
,:username
和$username
)具有相同的名称即可。$id = null
当您有多个不需要参数的URL映射时,您还需要确保将参数设置为optional()。否则,您将抛出一个错误,告诉您没有传入必需的参数。
最后要注意的getUser
是,此方法只返回一个User
对象。这会被序列化为JSON(或可能是XML)并打印出来供应用程序使用。
接下来我们必须saveUser
。你在这里看到我们再次有多个URL映射。这次他们还有不同的HTTP方法(POST和PUT)来创建和更新用户。这里的新东西是$data
变量。这是一个特殊的关键字参数,它将包含POSTed或PUT到服务器的值。这与常规Web POST不同,它不需要只是名称 - 值对,但可以像JSON一样,发送复杂对象。例如,常规Web POST的主体,比如登录请求,可能如下所示:
username=bob&password=supersecretpassw0rd
但为我们的saveUser方法发布一个新的用户对象可能如下所示
{ “ username ”:“ bob ”,“ password ”:“ supersecretpassword ”,“ firstName ”:“ Bob ”,“ lastName ”:“ Smith ” }
因此,除了常规的Web样式POST之外,您还可以允许POSTING JSON。
最后我们得到listUsers
方法。test
方法简单。但$query
参数是新的。此特殊参数可用于读取查询字符串。并将查询字符串参数保存为关联数组。例如,如果客户端使用url请求此API,/users?search=Manda
则$query
参数将保持[search => Manada]
。
我称这些类来处理请求Controllers
。并且它们可以通过URL映射,数据库配置等完全自包含,这样您就可以毫不费力地将它们放入其他RestServer服务中。
REST index.php
为了让整个服务器启动,你需要创建一个index.php文件,让你的URL重写直接请求(另一个你可以在其他地方学到的主题),然后创建RestServer并添加控制器类到它用于处理。RestServer将使用APC或文件缓存请求之间的URL映射以加速请求。如果使用自动加载和此缓存,则不必在每个请求上加载每个控制器文件,只需要请求所需的文件。缓存仅在生产模式下运行。这是一个示例index.php文件:
spl_autoload_register(); //除非我们使用它们,否则不要加载我们的类 $ mode = ' debug ' ; // 'debug'或'production'
$ server = new RestServer($ mode);
// $ server-> refreshCache(); //如果类在生产模式下更改,则暂时取消注释以清除缓存 $ server - > addClass(' TestController ');
$ server - > addClass(' ProductsController ',' / products '); //将此添加为此类中所有URL的基础 $ server - > handle();
而已。您可以根据需要添加任意数量的类。如果存在冲突,则稍后添加的类将覆盖先前添加的重复URL映射。addClass中的第二个参数可以是一个基本URL,它将作为给定类中URL映射的前缀,使您可以更加模块化。
您可以查看RestServer类,复制它并将其用于您自己的目的。它是在MIT许可下。要添加的功能包括XML支持和HTTP身份验证支持。如果您更好地完成此课程,请通过发表评论与大家分享您的更新。我将尝试使用新功能更新此类,因为它们是共享的。我希望你喜欢!
祝你好运,如果你最终使用它,请告诉我!
更新:我为可能需要它的人提供了一个示例.htaccess文件。它只会重写对不存在的文件的请求,因此您可以在webroot中拥有images,css或其他PHP文件,它们仍然有效。任何能给404的东西都会重定向到你的index.php文件。
DirectoryIndex index.php
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^$ index.php [QSA,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>
认证
身份验证对每个应用程序都是唯 但是将身份验证机制绑定到RestServer很容易。只需添加一个名为所有请求的方法authorize
,Controller
就会先调用该方法。如果authorize()
返回false,则服务器将发出401 Unauthorized响应。如果authorize()
返回true,则请求继续调用正确的控制器操作。除非您添加@noAuth
操作的文档(我通常将其置于@url
映射之上),否则所有操作都将首先运行授权。
在您的身份验证方法中,您可以使用PHP的getallheaders
功能或$_COOKIE
根据您的用户授权方式。这是您从数据库加载用户对象的位置,并将其设置为$this->user = getUserFromDatabase()
以便在以后调用时您的操作可以访问它。
RestServer是一种将应用程序映射到REST API的简单机制。其余细节由您决定。
跨域资源共享
出于安全原因,浏览器限制从脚本内发起的跨源HTTP或REST请求。因此,使用来自浏览器的REST API的Web应用程序只能向其自己的域发出API请求。RestServer
通过在REST index.php文件中包含以下代码,可以将覆盖此限制配置为允许交叉请求请求。
/*
* 在$ server = new RestServer($ mode)之后包含以下行;
* 或使用阵列中的多个起点的$服务器- > allowedOrigin = 阵列( ' http://example.com ', ' https://example.com ');
* 或通配符$ server - > allowedOrigin = ' * '
*/
$ server - > useCors = true ; $ server - > allowedOrigin = ' http://example.com ' ;
异常抛出错误处理
您可以通过在类中抛出一个例外来轻松地向API用户提供错误RestException
。例
/ **
* 按id或当前用户获取用户
*
* @url GET / users / $ id
* @url GET / users / current
* /
public function getUser( $ id = null) {
if( $ id){
$ user = User :: load( $ id); //可能的用户加载方法
if(!$ user){
throw new RestException(404,' User not found ');
}
} else {
$ user = $ _SESSION [ ' user ' ];
}
return $ user ; //将对象序列化为JSON
};
您可以控制REST服务处理错误的方式。您可以使用添加错误控制器$server->addErrorClass('ErrorController');
。
此控制器可以定义命名的方法handle401
或handle404
添加您自己的自定义错误处理逻辑。