ket4z / restserver
轻量级的PHP REST服务器。从Jacob Wright的RestServer派生
Requires
- php: >=5.3.3
This package is auto-updated.
Last update: 2024-08-31 17:02:40 UTC
README
一个用于提供非常轻量级REST API的PHP REST服务器。非常容易设置和启动。与其他库和框架独立。支持HTTP认证。
从Jacwright的RESTServer(v1.2.0)派生,主要目的是添加图像响应类型和修复一些错误。考虑到与Jacwright的API完全向后兼容,其他所有内容基本保留(包括此README),主要差异限制于
- 添加对
image/png返回类型的支持(通过Accept头和png格式) - 添加对HEAD HTTP请求的支持
- 重构命名空间
Jacwright为Ket4z以避免相应的命名空间冲突 - 添加缺失的关于接受/返回格式的README章节(包括关于返回图像的如何做指南),请参阅下面的
响应格式章节 - 修复README中的某些错别字
简单的PHP REST服务器
在构建了几个RESTful服务后使用Zend Framework,我决定创建一个极其简单的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中有一个新类型的doc-comment标签。@url将一个URL映射到下面的方法,其格式为
@url <REQUEST_METHOD> <URL>
在这个特定的例子中,当有人对http://www.example.com/(假设example.com是我们的服务所在的位置)进行GET请求时,它将打印出
"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 => Manda]。
我将处理请求的这些类称为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的方法来添加您自己的自定义错误处理逻辑。
响应格式
有几种方法可以请求特定的响应格式。最明显(也是推荐的一种)是使用请求中的Accept头并请求可用的响应格式之一,如application/json。另一种方法是使用有效负载/查询中的format键,如xml。还有另一种更复杂的方法,即在请求的端点路由中使用“点表示法”。我将不会在文档中记录这一点,以免鼓励其使用,如果您必须查找它,请从代码中查找:)。
请注意,如果没有指定格式,将返回text/plain。
如果输出图像,直接从处理方法返回图像的二进制数据,不要尝试使用任何结构。例如。
/** * @url GET /displayimage */ public function displayImage($query) { $imageGenerator = new YourImageGenerator(); $imageData = $imageGenerator->getImageData($query); return $imageData; }
安装
通过手工
cd <your project>
mkdir -p vendor/ket4z/RestServer
cd vendor/Ket4z/RestServer
git clone https://github.com/ket4z/RestServer .
composer install
通过Packagist
cd <your project>
composer require 'ket4z/restserver:dev-master'