I have built for myself a little library which i use because i couldn’t find something simple its quite flexible and this is the code for it:
API.class.php
<?php
abstract class API
{
/**
* Property: method
* The HTTP method this request was made in, either GET, POST, PUT or DELETE
*/
protected $method = '';
/**
* Property: endpoint
* The Model requested in the URI. eg: /files
*/
protected $endpoint = '';
/**
* Property: verb
* An optional additional descriptor about the endpoint, used for things that can
* not be handled by the basic methods. eg: /files/process
*/
protected $verb = '';
/**
* Property: args
* Any additional URI components after the endpoint and verb have been removed, in our
* case, an integer ID for the resource. eg: /<endpoint>/<verb>/<arg0>/<arg1>
* or /<endpoint>/<arg0>
*/
protected $args = Array();
/**
* Property: file
* Stores the input of the PUT request
*/
protected $file = Null;
/**
* Constructor: __construct
* Allow for CORS, assemble and pre-process the data
*/
public function __construct($request) {
header("Access-Control-Allow-Orgin: *");
header("Access-Control-Allow-Methods: *");
header("Content-Type: application/json");
$this->args = explode('/', rtrim($request, '/'));
$this->endpoint = array_shift($this->args);
if (array_key_exists(0, $this->args) && !is_numeric($this->args[0])) {
$this->verb = array_shift($this->args);
}
$this->method = $_SERVER['REQUEST_METHOD'];
if ($this->method == 'POST' && array_key_exists('HTTP_X_HTTP_METHOD', $_SERVER)) {
if ($_SERVER['HTTP_X_HTTP_METHOD'] == 'DELETE') {
$this->method = 'DELETE';
} else if ($_SERVER['HTTP_X_HTTP_METHOD'] == 'PUT') {
$this->method = 'PUT';
} else {
throw new Exception("Unexpected Header");
}
}
switch($this->method) {
case 'DELETE':
case 'POST':
$this->request = $this->_cleanInputs($_POST);
break;
case 'GET':
$this->request = $this->_cleanInputs($_GET);
break;
case 'PUT':
$this->request = $this->_cleanInputs($_GET);
$this->file = file_get_contents("php://input");
break;
default:
$this->_response('Invalid Method', 405);
break;
}
}
public function processAPI() {
if (method_exists($this, $this->endpoint)) {
return $this->_response($this->{$this->endpoint}($this->args));
}
return $this->_response("No Endpoint: $this->endpoint", 404);
}
private function _response($data, $status = 200) {
if($data === NULL)
return ;
else {
header("HTTP/1.1 " . $status . " " . $this->_requestStatus($status));
return json_encode($data);
}
}
private function _cleanInputs($data) {
$clean_input = Array();
if (is_array($data)) {
foreach ($data as $k => $v) {
$clean_input[$k] = $this->_cleanInputs($v);
}
} else {
$clean_input = trim(strip_tags($data));
}
return $clean_input;
}
private function _requestStatus($code) {
$status = array(
200 => 'OK',
404 => 'Not Found',
405 => 'Method Not Allowed',
500 => 'Internal Server Error',
);
return ($status[$code])?$status[$code]:$status[500];
}
}
?>
api.php
<?php
//error_reporting(E_ERROR | E_WARNING | E_PARSE);
error_reporting(E_ALL);
//error_reporting(E_ERROR | E_PARSE);
//ini_set('display_errors', 'on');
ini_set('display_errors',1);
set_time_limit(30);
date_default_timezone_set('Europe/Vienna');
require_once 'libs/MysqliDb.php';
require_once 'libs/dbObject.php';
require_once 'libs/php-ml/vendor/autoload.php';
require_once 'endpoint.class.php';
define('ROOT',realpath(dirname(__DIR__)).DIRECTORY_SEPARATOR);
// Allow from any origin
if (isset($_SERVER['HTTP_ORIGIN'])) {
// Decide if the origin in $_SERVER['HTTP_ORIGIN'] is one
// you want to allow, and if so:
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Max-Age: 86400'); // cache for 1 day
}
// Access-Control headers are received during OPTIONS requests
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
// may also be using PUT, PATCH, HEAD etc
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
exit(0);
}
if($_SERVER['REMOTE_ADDR'] == "127.0.0.1") {
// Initiate Database Connection
$db = new MysqliDb (Array (
'host' => 'localhost',
'username' => 'root',
'password' => '',
'db'=> '',
'charset' => 'utf8mb4'));
} else {
$db = new MysqliDb (Array (
'host' => 'localhost',
'username' => '',
'password' => '',
'db'=> '',
'charset' => 'utf8mb4'));
}
dbObject::autoload();
// Requests from the same server don't have a HTTP_ORIGIN header
if (!array_key_exists('HTTP_ORIGIN', $_SERVER)) {
$_SERVER['HTTP_ORIGIN'] = $_SERVER['SERVER_NAME'];
}
try {
$API = new endpoint($_REQUEST['request'], $_SERVER['HTTP_ORIGIN']);
echo $API->processAPI();
} catch (Exception $e) {
echo json_encode(Array('error' => $e->getMessage()));
}
?>
endpoint.class.php
<?php
//TODO Unified Account lookup
//define("PROTOCOL", strtolower(substr($_SERVER["SERVER_PROTOCOL"],0,strpos( $_SERVER["SERVER_PROTOCOL"],'/'))).'://');
require_once 'API.class.php';
require_once 'Models.APIKey.class.php';
class endpoint extends API
{
const API_ACCESS_KEY = 'AIzaSyCA50FSHQXYIa';
protected $user;
public function __construct($request, $origin) {
parent::__construct($request);
// Abstracted out for example
$APIKey = new Models\APIKey();
if (!array_key_exists('key', $this->request)) {
throw new Exception('NoAPIKeyProvided');
} else if (!$APIKey->verifyKey($this->request['key'], $origin)) {
throw new Exception('InvalidAPIKey');
}
if (array_key_exists('token', $this->request)) {
//Check token if valid
} else {
throw new Exception('LogIn');
}
}
/*
if(array_key_exists('version', $this->request)) {
} else {
throw new Exception('DeprecatedVersion');
}*/
}
//endpoint login
protected function login() {
return false
}
?>
in endpoint.php you can add your endpoints which do all the logic
and the last piece is the htaccess file:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule v1/(.*)$ api.php?request=$1 [QSA,NC,L]
</IfModule>
when you do an ajax request to an endpoint this is how the url can look like:
https://api.domain.com/v1/login?key=AIzaSyCA50FSHQXYIa&name=momo&password=123321
login is the in this case the endpoint, it can also be called by using the request query
the queries name & password will popup in the $this->request variable within our endpoint class
all functions in the endpoint class can return values which will automaticly translated into json hope that helps if you have any improvements or suggestions I would love to hear and get aswell!
this is just an example so dont take it seriouse obviously you shouldnt send your user password around like that haha
its fairly simple but works