Instead of:
$_SERVER['REQUEST_URI']
REQUEST_URI:index.php/products/xxx/yyy
Use:
$_SERVER['PATH_INFO']
PATH_INFO:/products/xxx/yyy
PATH_INFO is relative to the root URL. REQUEST_URI is not.
This leaves flexibility for the ROOT directory using relative URIs.
You can use various URLs and sub-domains.
URL: http://api.yoursite.com/post/index.php/parameters/
REQUEST_URI: /post/index.php/xxx/yyy<br>
PATH_INFO: /products/xxx/zzz
Would not be a bad idea to include a space in trim()
.
$called = explode('/', trim($_SERVER['PATH_INFO'],'\x20\x2f'));
preg_match_all() could provide error detection and correction (user typo) as will as doing the explode().
I would make the code function correctly within the definition of the rules. Although I would expand on it. I would NOT use the Request Method to determine any functionality.
The API should be architected where GET and POST Types can be used interchangeably. I would NEVER use them to select view, save, delete.
While on the subject of parameters I would suggest using integer parameters over string whenever possible.
Integer is compact keeping down the Request Header size, is the easiest to validate, and makes comparison functions faster.
Example: On a string true false parameter $param = intval($param);
, no need to do if(isset())
it's not there it's zero. And it resolves typing between numeric 1 and string '1' when it is used as an array dimension.
Instead of this:
if(isset($id[0])) { $product_id = $id[0]; } if(!is_numeric($product_id)) { header($_SERVER['SERVER_PROTOCOL']." 400 Bad Request"); die(); } $data = ""; if($product_id == 0) { $data = $this->model->getProducts(); }
Create a product with a product id of zero with a description of 'Invalid Product ID" and process it just like a valid product or process the same as an invalid product id number.
$product_id = $data = $this->model->getProducts(intval($id[0]));
If you want a product id to return a list of products use a non-zero id.
For delete, return an error status status on zero the same as if it were an invalid product id.
Consider using an extension other than .php
. Even html is easier than php for users to remember.
You could use the extension for the user to select the response type.
For Example: In the Apache config or .htaccess
<FilesMatch *.htm? *.xml *.jsn *.txt *.php > SetHandler php5-script </FilesMatch>
This is easier on the memory allocation, memory bus I/O, and retyping a variable from string to array.
$req_body = json_decode($file_get_contents('php://input'),true);
Than:
$req_body = json_decode($file_get_contents('php://input'); $req_body = json_decode($req_body,true);
This is confusing when the first passed argument is $parameters $controller->view($parameters, $req_body);
And the accepted 2nd argument is$parameters<br>
function view($id = "",$parameters)
This is poor on more than one level.
if(count($called) <= 3){ header($_SERVER['SERVER_PROTOCOL']." 400 Bad Request"); die(); }
Check validity of all passed parameters. Then determine the best, most specific and user friendly response.
The best user response is to fix the error when possible.
If a parameter is missing, add a default.
If you had an HTML error on your web page, do you expect it to render? Would you like it if a single HTML error returned a 404 response? If a Browser was that rigid it may not get much use, same goes for your API.
404 is not an appropriate response when the document URL (index.php) is correct. Additionally this will confuse some users as to why. They may just think your server is down and they go somewhere else.
Consider using an alternate response such as 409. You want to make it as easily as possible for the user to understand what their mistake was. 404 should be reserved for an error in the URL
Also for diagnostic and support issues, use various response codes for different issues and document them for the user.
You could use a text header and a message identifying the specifics problem with an error message.
header('Content-Type: text/plain; charset=utf-8'); echo $error;
Or follow the HTTP 4xx header with an error code in an additional header key value with the error code.
header("x-error: $error");
For Example: The W3C HTML Markup Validator puts the number of HTML errors in the header.
There are much better HTTP Response Codes to use over 404.
Better diagnostics reduces support and increases user satisfaction.
400 Bad Request
The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications.
403 Forbidden
The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead.
404 Not Found
The server has not found anything matching the Request-URI. No indication is given of whether the condition is temporary or permanent. The 410 (Gone) status code SHOULD be used if the server knows, through some internally configurable mechanism, that an old resource is permanently unavailable and has no forwarding address. This status code is commonly used when the server does not wish to reveal exactly why the request has been refused, or when no other response is applicable.
405 Method Not Allowed
The method specified in the Request-Line is not allowed for the resource identified by the Request-URI. The response MUST include an Allow header containing a list of valid methods for the requested resource.
406 Not Acceptable
The resource identified by the request is only capable of generating response entities which have content characteristics not acceptable according to the accept headers sent in the request.
409 Conflict
The request could not be completed due to a conflict with the current state of the resource. This code is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request. The response body SHOULD include enough
information for the user to recognize the source of the conflict. Ideally, the response entity would include enough information for the user or user agent to fix the problem; however, that might not be possible and is not required.
Conflicts are most likely to occur in response to a PUT request. For example, if versioning were being used and the entity being PUT included changes to a resource which conflict with those made by an earlier (third-party) request, the server might use the 409 response to indicate that it can't complete the request. In this case, the response entity would likely contain a list of the differences between the two versions in a format defined by the response Content-Type.
410 Gone
The requested resource is no longer available at the server and no forwarding address is known. This condition is expected to be considered permanent. Clients with link editing capabilities SHOULD delete references to the Request-URI after user approval. If the server does not know, or has no facility to determine, whether or not the condition is permanent, the status code 404 (Not Found) SHOULD be used instead. This response is cacheable unless indicated otherwise.
410 response is primarily intended to assist the task of web maintenance by notifying the recipient that the resource is intentionally unavailable and that the server owners desire that remote links to that resource be removed. Such an event is common for limited-time, promotional services and for resources belonging to individuals no longer working at the server's site. It is not necessary to mark all permanently unavailable resources as "gone" or to keep the mark for any length of time -- that is left to the discretion of the server owner.