雪狐 / restserver
用于非常轻量级REST API的PHP REST服务器
Requires
- php: >=5.3.3
This package is auto-updated.
Last update: 2024-09-25 21:27:39 UTC
README
这是一个PHP REST服务器,用于提供非常轻量级的REST API。非常容易设置和启动。独立于其他库和框架。支持HTTP认证。
简单的PHP REST服务器
在我使用 Zend Framework 构建了几个RESTful服务之后,我决定创建一个极其简单的REST服务器,这样我可以跳过所有我不需要的特性以及Zend Framework MVC附带的大量类。还有一些有用的功能可以添加(例如XML支持),但总的来说,我对我的成果相当满意。
我的解决方案 RestServer
目前是一个JSON REST服务器。添加对XML或其他格式的支持应该很简单,但需要对您的对象在XML中的外观做出假设(XML-RPC风格、自定义XML格式等)。首先,我们将查看您编写的处理请求的类,然后我们将查看如何在您的 index.php 文件中将其组合起来。
REST控制器
RestServer
类假设您正在使用URL重写,并查看请求中的URL以映射到必要的操作。将请求从URL映射到类方法的映射全部在类的文档注释中。以下是一个将处理一些用户操作的类的示例
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'];
// validate input and log the user in
}
/**
* 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 $user; // 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
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
}
}
让我们分析上面的 TestController
类,讨论展示的功能。首先,我们将查看 test
方法。您会注意到在 docblock 中有一个新的类型的文档注释标签。@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应用程序提供数据,使用会话可能更容易一些。
接下来是我们的 getUser
方法(你会注意到,我给方法命名其实并不重要,因为我们的 @url
指令定义了哪些 URL 映射到方法)。这里有几个要点。首先,这个方法有多个 @url
映射。其次,第一个 URL 映射中有一个奇怪的 /$id
。RestServer 将任何 :keyword
占位符视为 URL 中的通配符,并将该 URL 部分传递给方法中同名参数。在这个例子中,当访问 http://www.example.com/users/1234 时,$id
将等于 1234。当访问 http://www.example.com/users/current 时,$id
将等于 null。只要参数名与占位符(:id
和 $id
,:username
和 $username
)相同,参数的顺序无关紧要。当你有多个 URL 映射,并非所有都需要参数时,确保你的参数是可选的($id = null
)。否则,会抛出错误告诉你未传入所需的参数。
在 getUser
方法中,还有一个需要注意的最后一点:该方法简单地返回一个 User
对象。它被序列化为 JSON(或可能是 XML)并打印出来供应用程序消费。
接下来是 saveUser
方法。这里我们再次看到了多个 URL 映射。这一次,它们还有不同的 HTTP 方法(POST 和 PUT)用于创建和更新用户。这里的新特点是 $data
变量。这是一个特殊的参数,它将包含 POST 或 PUT 到服务器的值。这与常规的 Web POST 不同,因为它不只需要是键值对,还可以像 JSON 一样健壮,发送复杂对象。例如,常规的 Web POST 的主体,比如说登录请求,可能看起来像这样
username=bob&password=supersecretpassw0rd
但是,为我们的 saveUser 方法 POST 一个新用户对象可能看起来像这样
{ "username": "bob", "password": "supersecretpassword", "firstName": "Bob", "lastName": "Smith" }
因此,你能够允许同时 POST JSON 和常规的 Web 样式 POST。
最后,我们来到 listUsers
方法。它和 test
方法一样简单。但是,$query
参数是新的。这个特殊参数可以用来读取查询字符串,并将查询字符串参数作为关联数组保存。例如,如果客户端通过 URL /users?search=Manda
请求这个 API,则 $query
参数将包含 [search => Manada]
。
我把处理请求的这些类称为 Controllers
。它们可以完全自包含,包括 URL 映射、数据库配置等,因此你可以将它们无缝地集成到其他 RestServer 服务中。
REST index.php
为了启动整个服务器,你需要创建一个 index.php 文件,将 URL 重写指向它(这是一个其他地方可以学习的主题),并创建 RestServer 并添加控制器类来处理请求。RestServer 将使用 APC 或文件来缓存请求之间的 URL 映射,以加快请求速度。如果你使用自动加载和这个缓存,你不需要在每次请求时都加载每个控制器文件,只需加载所需的控制器即可。缓存仅在生产模式下运行。以下是一个示例 index.php 文件
spl_autoload_register(); // don't load our classes unless we use them
$mode = 'debug'; // 'debug' or 'production'
$server = new RestServer($mode);
// $server->refreshCache(); // uncomment momentarily to clear the cache if classes change in production mode
$server->addClass('TestController');
$server->addClass('ProductsController', '/products'); // adds this as a base to all the URLs in this class
$server->handle();
就这么多。你可以添加任意多的类。如果有冲突,后来添加的类将覆盖之前添加的重复 URL 映射。并且在 addClass 的第二个参数中可以是一个基础 URL,这将作为给定类中的 URL 映射的前缀,允许你更加模块化。
您可以查看RestServer类,复制它并用于自己的目的。该项目遵循MIT许可。待添加的功能包括XML支持和HTTP身份验证支持。如果您使这个类变得更优秀,请通过留言与大家分享您的更新。我会尽力保持这个类与新功能同步。希望您喜欢!
祝您好运,如果最终使用它,请告知我!
更新:我为可能需要的人包含了一个示例 .htaccess 文件。它只会重写对不存在的文件的请求,因此您可以在您的webroot中包含图像、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中很容易。通过简单地向您的Controller
添加一个名为authorize
的方法,所有请求都会首先调用该方法。如果authorize()
返回false,服务器将发出401未授权响应。如果authorize()
返回true,请求将继续调用正确的控制器操作。除非您在动作的文档中添加了@noAuth
,否则所有操作都会首先运行授权(我通常把它放在@url
映射之上)。
在您的身份验证方法中,您可以使用PHP的getallheaders
函数或$_COOKIE
来根据您的方式授权用户。这是您从数据库中加载用户对象并将其设置为$this->user = getUserFromDatabase()
的地方,这样动作就可以在稍后调用时访问它。
RestServer旨在将您的应用程序映射为一个REST API的简单机制。其余的细节由您决定。
跨源资源共享
出于安全原因,浏览器限制从脚本内部发起的跨源HTTP或REST请求。因此,使用浏览器从REST API中获取的Web应用程序,只能对其自己的域发起API请求。要覆盖此限制,可以在REST index.php文件中包含以下代码,以配置RestServer
允许跨源请求。
/**
*
* include following lines after $server = new RestServer($mode);
*/
$server->useCors = true;
$server->allowedOrigin = 'http://example.com';
// or use array of multiple origins
$server->allowedOrigin = array('http://example.com', 'https://example.com');
// or a wildcard
$server->allowedOrigin = '*';
抛出和处理错误
您可以通过抛出带有RestException
类的异常来轻松地为API用户提供错误。示例
/**
* 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
if (!$user) {
throw new RestException(404, 'User not found');
}
} else {
$user = $_SESSION['user'];
}
return $user; // serializes object into JSON
}
您控制您的REST服务如何处理错误。您可以使用$server->addErrorClass('ErrorController');
添加一个错误控制器。该控制器可以定义名为handle401
或handle404
的方法,以添加您自己的自定义错误处理逻辑。
安装
通过手工
cd <your project>
mkdir -p vendor/snowfox/RestServer
cd vendor/snowfox/RestServer
git clone https://github.com/snowfox/RestServer .
composer install
通过Packagist
cd <your project>
composer require 'snowfox/restserver:dev-master'