Thiết kế mạng xã hội với PHP - 38 potx

10 267 0
Thiết kế mạng xã hội với PHP - 38 potx

Đang tải... (xem toàn văn)

Thông tin tài liệu

Developing an API [ 352 ] Let's go with REST REST is now a very popular API architecture, with most social networks providing REST-based APIs. The way RESTful APIs rely on descriptive URIs for providing access to data makes them very easy for consumers to utilize, as the URIs provide information on what the request does, and what data it will return. Some implementations, such as the Twitter API even make it possible to change the format of the data returned, simply by changing a part of the URI. Requests Requests to a RESTful API use HTTP verbs to describe what the consumer is trying to do. The API requests are made to specic URIs, which dene the resource that the consumer is trying to perform the action (determined by the verbs) upon. HTTP verbs The HTTP verbs and their usage are described as follows: Verb Description GET Retrieve information POST Create records PUT Update records DELETE Delete records Resources RESTful APIs relate URIs to resources. Below are some examples: • http://ourdomain.com/profiles: To list or create proles • http://ourdomain.com/profiles/1: A specic user's prole Our RESTful API will be based within an API controller, thus prexing all URLs with api/, which goes slightly against the REST concept of a resource. Download from Wow! eBook <www.wowebook.com> Chapter 11 [ 353 ] Resources and verbs—the requests Let's look at how resources and verbs combined result in API requests. API operation HTTP verb Resource Creating a user POST http://ourdomain.com/api/profiles Listing users GET http://ourdomain.com/api/profiles Viewing a user's prole GET http://ourdomain.com/api/profiles/1 Updating a prole PUT http://ourdomain.com/api/profiles/1 Deleting a prole DELETE http://ourdomain.com/api/profiles/1 In the above resources, the number 1 represents the ID of a user's prole. Responses The response to an API request is generally made up of two parts. The rst part of the response is the HTTP header containing an appropriate status code. Some examples of HTTP status codes are below: HTTP status code Meaning 200 OK 201 Created 400 Bad request 404 Not found Within PHP, HTTP status codes are set as follows: header("HTTP/1.0404NotFound"); The second part of the response is the data itself; for instance, if the API request was for a list of users, the response would be the list of users. Commonly, response data is sent as XML or JSON. Some APIs allow the consumer to request the format of the response by supplying the format to the API. We are going to use JSON. If we have an array of data that we want to return as JSON, we simply do the following: echo json_encode( $users_list_array ); exit(); Download from Wow! eBook <www.wowebook.com> Developing an API [ 354 ] Further reading There are numerous resources available regarding web services and REST. Following are the resources you may nd particularly useful. RESTful PHP Web Services Packt has a book dedicated to creating RESTful APIs in PHP—RESTful PHP Web Services, by Samisa Abeysinghe, https://www.packtpub.com/restful-php-web- services/book. This book details the concepts of a REST architecture, how to make use of existing RESTful APIs in your framework, how to create a RESTful API for other applications to interact with, as well as debugging information and case studies. Conference talks Lorna Jane Mitchell (http://www.lornajane.net), a widely-respected developer and conference speaker on PHP-related topics, has recently spoken at a number of conferences on the subject of web service design. Slides from related talks are available online: http://www.slideshare.net/lornajane/best-practices-in- web-service-design , http://www.slideshare.net/lornajane/php-and-web- services-perfect-partners. Implementation Now that we know what sort of API we are going to develop, we can move onto the implementation. In this chapter we will only implement a small sub-set of the API's functionality. Feel free to extend this to match the entire functionality of Dino Space, if you wish. Data format Most commonly, RESTful APIs either return their data in XML format or as JSON. Some APIs allow the consumer to specify the return type by adding .xml or .json to the end of the URL. For the purposes of our implementation, let's stick to JSON, as it is simpler to convert data to JSON (simply by passing the data to the json_encode function). Download from Wow! eBook <www.wowebook.com> Chapter 11 [ 355 ] API controller Our API controller itself won't do very much; instead it will pass control to delegate controllers, which contain logic specic to the various sections of the site. <?php /** * API Controller */ class Apicontroller{ To indicate which les are available for control to be delegated to, we should maintain an array of allowable API controllers. For our work in this chapter, we will create the profiles delegate. /** * Allowable API Controllers, for control to be delegated to */ private $allowableAPIControllers = array( 'profiles' ); /** * Request data */ private $requestData = array(); The object's constructor simply sets the registry object, gets the value of the API delegate that should be used, and calls the delegator method (delegateControl). /** * API Controller Constructor * @param Registry $registry the registry * @param boolean $directCall * @return void */ public function __construct( Registry $registry, $directCall=true ) { $this->registry = $registry; $apiController = $registry->getObject('url')->getURLBit(1); $this->delegateControl( $apiController ); } Download from Wow! eBook <www.wowebook.com> Developing an API [ 356 ] The delegateControl method checks that the delegate controller is within the allowed delegates. If it is, then it includes the appropriate controller, instantiates it, and passes the registry and the API controller object to it. There are a number of methods that will be common to all API delegates. These methods are stored in this object, and called by the delegate referencing this object. If the requested controller is not allowable, then we generate an appropriate HTTP status code; in this case: 404 Not Found. /** * Pass control to a delegate * @param String $apiController the delegate * @return void */ private function delegateControl( $apiController ) { if( $apiController != '' && in_array( $apiController, $this->allowableAPIControllers ) ) { require_once( FRAMEWORK_PATH . 'controllers/api/' . $apiController . '.php' ); $api = new APIDelegate( $this->registry, $this ); } else { header('HTTP/1.0 404 Not Found'); exit(); } } A shared method is required by our delegates. This is called if a delegate requires the API user to be an authenticated user on the site. It generates a basic authentication prompt (this is presented to users viewing the site in their browsers, but for API users the username and password are passed as part of the HTTP request). Download from Wow! eBook <www.wowebook.com> Chapter 11 [ 357 ] Alternatives to basic authentication Basic authentication isn't the best option in terms of security, especially if many websites begin offering services utilizing our API. Our users' passwords could be stored (with their permission) within these websites, putting reliance on the integrity and security of those sites and their owners. An alternative is OAuth, where the API provider deals with the authentication, and provides consumers with an API key for their users. If a user then wishes to stop a third-party service utilizing their account via the API, they can simply revoke access. We will discuss this option more in the security section of this chapter. If the authentication fails, then the 401 Unauthorized status code is issued. /** * Request authentication for access to API methods, called by delegates * @return void */ public function requireAuthentication() { if( !isset( $_SERVER['PHP_AUTH_USER'] ) ) { header('WWW-Authenticate: Basic realm="DinoSpace API Login"'); header('HTTP/1.0 401 Unauthorized'); exit(); } else { $user = $_SERVER['PHP_AUTH_USER']; $password = $_SERVER['PHP_AUTH_PW']; $this->registry->getObject('authenticate')->postAuthenticate( $user, $password, false ); if( ! $this->registry->getObject('authenticate')- >isLoggedIn() ) { header('HTTP/1.0 401 Unauthorized'); exit(); } } } Download from Wow! eBook <www.wowebook.com> Developing an API [ 358 ] PUT and DELETE data (technically, there should never be DELETE data sent on a DELETE request) cannot be accessed through super globals as POST and GET data can ($_POST and $_GET), so we need a mechanism to get the request data, regardless of the type of request. /** * Get the type of request * @return array */ public function getRequestData() { if( $_SERVER['REQUEST_METHOD'] == 'GET' ) { $this->requestData = $_GET; } elseif( $_SERVER['REQUEST_METHOD'] == 'POST' ) { $this->requestData = $_POST; } elseif( $_SERVER['REQUEST_METHOD'] == 'PUT' ) { parse_str(file_get_contents('php://input'), $this->requestData ); } elseif( $_SERVER['REQUEST_METHOD'] == 'DELETE' ) { parse_str(file_get_contents('php://input'), $this->requestData ); } return $this->requestData; } } ?> php://input php://input is an input stream wrapper in PHP, which allows us to read raw request data. More detailed information is available on the PHP website: http://php.net/manual/en/wrappers.php.php/. Download from Wow! eBook <www.wowebook.com> Chapter 11 [ 359 ] Wait—no models? That's right; we don't need to create any models for our API. All of the functionality our API needs to provide already exists through the various models we have created. So instead of creating API-specic models, we will create some additional API controllers, which work with the pre-existing models to get the data and present it to the consumer. Authentication Keeping with the RESTful way of leveraging HTTP, we can make use of HTTP authentication to authenticate the user. This is where authentication details are passed as part of the HTTP request from our API consumer. You will have seen examples of this if you have ever visited a web page, and your browser has opened a pop up prompting for authentication details before loading the page. In this case, your browser reads the server's request for authentication, and then requests login details before sending the authentication request to the server. More information You can read more about HTTP authentication with PHP here: http://php.net/manual/en/features.http-auth.php Sessions lead to unREST! REST is a stateless architecture, which means all of the information required for a particular operation or request should be included within that request. It shouldn't rely on information from a previous request or other information such as sessions and cookies. To that end, we should amend our authenticate registry object and our index.php le. Amending the authenticate registry object We need to amend the authenticate registry class (registry/authenticate. class.php ) to only set $_SESSION data if that is required, so that we can indicate, from our API controller, that we don't want $_SESSION data to be created. Download from Wow! eBook <www.wowebook.com> Developing an API [ 360 ] We should add an optional parameter to the postAuthenticate method to indicate if $_SESSION data should be set, with a default value of true so it doesn't impact on other aspects of our site, which we have already implemented. public function postAuthenticate( $u, $p, $sessions=true ) { $this->justProcessed = true; require_once(FRAMEWORK_PATH.'registry/user.class.php'); $this->user = new User( $this->registry, 0, $u, $p ); if( $this->user->isValid() ) { if( $this->user->isActive() == false ) { $this->loggedIn = false; $this->loginFailureReason = 'inactive'; } elseif( $this->user->isBanned() == true ) { $this->loggedIn = false; $this->loginFailureReason = 'banned'; } else { $this->loggedIn = true; If the sessions parameter for this method has been set to true, then we set the appropriate session. If it has been set to false (for example, by our API controller), then it is not set. if( $sessions == true ) { $_SESSION['sn_auth_session_uid'] = $this->user->getUserID(); } } } else { $this->loggedIn = false; $this->loginFailureReason = 'invalidcredentials'; } } Download from Wow! eBook <www.wowebook.com> Chapter 11 [ 361 ] Amending index.php Our index.php le by default checks for SESSION data for authentication. See Chapter 2, or take a look at the index.php le to refresh your memory. <?php session_start(); DEFINE("FRAMEWORK_PATH", dirname( __FILE__ ) ."/" ); require('registry/registry.class.php'); $registry = new Registry(); // setup our core registry objects $registry->createAndStoreObject( 'template', 'template' ); $registry->createAndStoreObject( 'mysqldb', 'db' ); $registry->createAndStoreObject( 'authenticate', 'authenticate' ); $registry->createAndStoreObject( 'urlprocessor', 'url' ); $registry->getObject('url')->getURLData(); // database settings include(FRAMEWORK_PATH . 'config.php'); // create a database connection $registry->getObject('db')->newConnection( $configs['db_host_sn'], $configs['db_user_sn'], $configs['db_pass_sn'], $configs['db_name_sn']); Firstly, we need to move the line that sets the controller variable to just before authentication is checked. We then wrap the authentication check line in an IF statement, so that it is only executed if the controller being requested isn't the API controller. $controller = $registry->getObject('url')->getURLBit(0); if( $controller != 'api' ) { $registry->getObject('authenticate')->checkForAuthentication(); } // store settings in our registry $settingsSQL = "SELECT `key`, `value` FROM settings"; $registry->getObject('db')->executeQuery( $settingsSQL ); while( $setting = $registry->getObject('db')->getRows() ) { $registry->storeSetting( $setting['value'], $setting['key'] ); } Download from Wow! eBook <www.wowebook.com> . online: http://www.slideshare.net/lornajane/best-practices-in- web-service-design , http://www.slideshare.net/lornajane /php- and-web- services-perfect-partners. Implementation Now that we know what. useful. RESTful PHP Web Services Packt has a book dedicated to creating RESTful APIs in PHP RESTful PHP Web Services, by Samisa Abeysinghe, https://www.packtpub.com/restful -php- web- services/book. . $this->user->isActive() == false ) { $this->loggedIn = false; $this->loginFailureReason = 'inactive'; } elseif( $this->user->isBanned() == true ) { $this->loggedIn

Ngày đăng: 06/07/2014, 18:20

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan