alexsasharegan / http
一个超简单且轻量级的PHP库,使制作RESTful API更加容易。
Requires
- php: >=5.3.0
- sami/sami: ^3.3
This package is not auto-updated.
Last update: 2024-09-14 19:04:18 UTC
README
一个轻量级、无依赖的库,使在PHP中编写基于文件的RESTful JSON API端点更加容易。
设置
将仓库克隆到您的项目中。假设您的RESTful端点位于 /api
目录中,我建议创建一个 /api/vendor
文件夹或只是一个普通的 /api/libs
文件夹,并将此仓库克隆到其中。
- 在您的项目中,使用
require_once
包含到Http_Autoloader.php
的路径。
<?php require_once 'path/to/Http_Autoloader.php'; # ...or potentially... require_once 'project_root/dist/api/vendor/Http_lib/Http_Autoloader.php';
实例化
<?php $http = new Http;
属性
类 Http
的属性以JSON表示
{ "request": "type: class Http\Request", "response": "type: class Http\Response", "get": "type: callable (callback handle)", "post": "type: callable (callback handle)", "put": "type: callable (callback handle)", "patch": "type: callable (callback handle)", "delete": "type: callable (callback handle)" }
类 Http\Request
的某些示例属性以JSON表示(这些属性根据请求本身而有所不同)
{ "body": { "content": "this is some test content from a json request" }, "method": "POST", "requestURI": "/php/my_libs_tests/Http.test.php/1?stuff=some+stuff", "query": { "stuff": "some stuff" }, "file": "Http.test.php", "contentType": "application/json", "cookies": "PHPSESSID=01kf9mqndmpr8guqe6tk87nka7; _ga=GA1.1.162483231.1471457216", "host": "localhost", "port": "80", "pathInfo": "/1", "scriptName": "/php/my_libs_tests/Http.test.php", "URIComponents": { "path": "/php/my_libs_tests/Http.test.php/1", "query": "stuff=some+stuff" }, "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36" }
Http\Reponse
的属性是私有的。这允许响应对象管理响应数据并在发送时序列化它。
方法
Http
类为每个主要的HTTP动词(get、post、put、patch、delete)都提供了一个方法。这允许您将回调附加到每个适当的请求方法。您可以传入您回调的字符串名称,或者作为闭包内联编写您的函数。回调将使用 Http
的实例来调用。您可以将字符串名称传递给回调,或者直接以闭包的形式写入您的函数。
回调参考
<?php function myPostCallback($http) { # code ... } $http = new Http; $http->post('myPostCallback');
内联闭包
<?php $http = new Http; $http->post( function ($http) { # code ... } ); # also possible $myGlobalVar = [1,2,3]; (new Http) ->get( function ($http) { # code ... } ) ->post( function ($http, $myGlobalVar) { # code ... } , $myGlobalVar ) ->exec();
要获取解析的请求体的值,请调用 Http\Request::get( string $key )
。
在编写回调时,您可以使用两种方法构建响应
-
Http\Response::set( string $key, mixed $value )
参数
- key: 要设置的值的名称
- value: 要设置的值
-
Http\Response::set_array( array $array )
参数
- array: 要在响应中设置的值的关联数组
回调的最后一条语句将是调用 Http::send
。这将发送响应后完全退出执行。
-
Http::send( [ int $statusCode = 200, string $contentType = "application/json", string $content = '' ] )
参数
- statusCode: 要返回的有效HTTP状态码
- contentType: 要设置响应头的有效MIME类型
- content: 如果您将Content-Type设置为非json,则可以使用此参数发送自定义数据。不会对此内容执行序列化。
- 注意:任何未定义的路由都将返回状态码
405
和一个JSON格式的错误消息。
{ "error": "No route has been defined for this request method." }
如果您的错误处理中使用 try {} catch(Exception $e) {}
块,则可以在catch块中调用 Http::handleError( Exception $e )
,它将自动以 500
状态码和包含错误的JSON有效负载进行回复。
一旦您定义了所有必要的HTTP方法回调,您只需通过调用来让您的 Http
实例运行适当的回调
<?php $http->exec();
示例
<?php # this example uses the Database and Html library as well require_once 'path/to/vendor/autoload.php'; # alias our classes for cleanliness use Database\MySQL; use Http\Http; use Html\Html; # the callbacks for each http method # get called with the instance of Http\Http function get($http) { # instantiate our MySQL object with a connection config $db = new MySQL([ 'hostName' => '1.1.1.1', 'databaseName' => 'myDatabase', 'dbUserName' => 'admin', 'dbPassword' => 'adminPass', ]); # make a select query and pull $id from the request query string $db->query( "SELECT * FROM `sellers` WHERE `id` = {$http->request->query('id')}" ) # this func gets called once for each row # 'use' pulls in $http from the closure's parent scope # sometimes we need to pass by reference like this: use( &$var ) ->iterateResult( function ( $row ) use ( $http ){ $http->response->set_array($row); } ); # nesting operations to dumb the column names into response['sellers'] $http->response->set( 'sellersColumns', $db->getColumns('sellers') ); # test setting different types $http->response->set( 'test', [ 'one' => 1, 'two' => 'two', 'three' => true, 'four' => [1,2,3], ]); # send what's in our response object $http->send(); } # make our instance of Http\Http $http = new Http; # chain our calls together $http ->get( 'get' ) ->post( function ( $http ) { # code ... } ) # there is a default exception handler, # but you can set a custom exception handler # like this: ->error( function ( Exception $e ) use ( $http ) { $http->send(500, 'text/html', new Html('code', $e)); } ) # execute the route ->exec();
<?php require_once 'path/to/vendor/autoload.php'; use Http\Http; use Http\Response; Http::redirect('/index.html'); # this sends the location header & exits execution! # the redirect location defaults to '/' $current_http_status = Http::status(); # calling it without any arguments gets the current status code $prev_http_status = Http::status(404); # setting a new status will set the response code and return the old status Http::status(Response::HTTP_NOT_FOUND); # there are a number of constants available for valid status codes # while it can be verbose, it can add readability to your code # here is the fully namespaced list: Http\Response::HTTP_CONTINUE = 100; Http\Response::HTTP_SWITCHING_PROTOCOLS = 101; Http\Response::HTTP_PROCESSING = 102; // RFC2518 Http\Response::HTTP_OK = 200; Http\Response::HTTP_CREATED = 201; Http\Response::HTTP_ACCEPTED = 202; Http\Response::HTTP_NON_AUTHORITATIVE_INFORMATION = 203; Http\Response::HTTP_NO_CONTENT = 204; Http\Response::HTTP_RESET_CONTENT = 205; Http\Response::HTTP_PARTIAL_CONTENT = 206; Http\Response::HTTP_MULTI_STATUS = 207; // RFC4918 Http\Response::HTTP_ALREADY_REPORTED = 208; // RFC5842 Http\Response::HTTP_IM_USED = 226; // RFC3229 Http\Response::HTTP_MULTIPLE_CHOICES = 300; Http\Response::HTTP_MOVED_PERMANENTLY = 301; Http\Response::HTTP_FOUND = 302; Http\Response::HTTP_SEE_OTHER = 303; Http\Response::HTTP_NOT_MODIFIED = 304; Http\Response::HTTP_USE_PROXY = 305; Http\Response::HTTP_RESERVED = 306; Http\Response::HTTP_TEMPORARY_REDIRECT = 307; Http\Response::HTTP_PERMANENTLY_REDIRECT = 308; // RFC7238 Http\Response::HTTP_BAD_REQUEST = 400; Http\Response::HTTP_UNAUTHORIZED = 401; Http\Response::HTTP_PAYMENT_REQUIRED = 402; Http\Response::HTTP_FORBIDDEN = 403; Http\Response::HTTP_NOT_FOUND = 404; Http\Response::HTTP_METHOD_NOT_ALLOWED = 405; Http\Response::HTTP_NOT_ACCEPTABLE = 406; Http\Response::HTTP_PROXY_AUTHENTICATION_REQUIRED = 407; Http\Response::HTTP_REQUEST_TIMEOUT = 408; Http\Response::HTTP_CONFLICT = 409; Http\Response::HTTP_GONE = 410; Http\Response::HTTP_LENGTH_REQUIRED = 411; Http\Response::HTTP_PRECONDITION_FAILED = 412; Http\Response::HTTP_REQUEST_ENTITY_TOO_LARGE = 413; Http\Response::HTTP_REQUEST_URI_TOO_LONG = 414; Http\Response::HTTP_UNSUPPORTED_MEDIA_TYPE = 415; Http\Response::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416; Http\Response::HTTP_EXPECTATION_FAILED = 417; Http\Response::HTTP_I_AM_A_TEAPOT = 418; // RFC2324 Http\Response::HTTP_MISDIRECTED_REQUEST = 421; // RFC7540 Http\Response::HTTP_UNPROCESSABLE_ENTITY = 422; // RFC4918 Http\Response::HTTP_LOCKED = 423; // RFC4918 Http\Response::HTTP_FAILED_DEPENDENCY = 424; // RFC4918 Http\Response::HTTP_RESERVED_FOR_WEBDAV_ADVANCED_COLLECTIONS_EXPIRED_PROPOSAL = 425; // RFC2817 Http\Response::HTTP_UPGRADE_REQUIRED = 426; // RFC2817 Http\Response::HTTP_PRECONDITION_REQUIRED = 428; // RFC6585 Http\Response::HTTP_TOO_MANY_REQUESTS = 429; // RFC6585 Http\Response::HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; // RFC6585 Http\Response::HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451; Http\Response::HTTP_INTERNAL_SERVER_ERROR = 500; Http\Response::HTTP_NOT_IMPLEMENTED = 501; Http\Response::HTTP_BAD_GATEWAY = 502; Http\Response::HTTP_SERVICE_UNAVAILABLE = 503; Http\Response::HTTP_GATEWAY_TIMEOUT = 504; Http\Response::HTTP_VERSION_NOT_SUPPORTED = 505; Http\Response::HTTP_VARIANT_ALSO_NEGOTIATES_EXPERIMENTAL = 506; // RFC2295 Http\Response::HTTP_INSUFFICIENT_STORAGE = 507; // RFC4918 Http\Response::HTTP_LOOP_DETECTED = 508; // RFC5842 Http\Response::HTTP_NOT_EXTENDED = 510; // RFC2774 Http\Response::HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511;