* @version 1.0.0 * @uses yaml_parse_file http://php.net/manual/en/book.yaml.php */ class Routing { static $klein; // The base url prefix static $prefix = "/path/api"; // The API version static $version = "v1"; static $mapped_url = ["menu", "posts"]; // The response static $j = []; /** * The main method */ public static function run() { self::$klein = new \Klein\Klein(); self::$j["id"] = ""; self::$j["date"] = self::getDate(); self::$j["status"] = new stdClass(); self::$j["errors"] = new stdClass(); self::$j["response"] = new stdClass(); self::$j["request"] = new stdClass(); self::showError(200); self::route_checkVersion(); self::route_getGeneralRoute(); self::route_getMenu(); self::route_getPosts(); self::$klein->dispatch(); } /** * Load current error data * and generate the errors object data in the response object * @see errors.yml * @uses yaml_parse_file * @link http://php.net/manual/en/book.yaml.php * * @param int $error The error code to load * @return object The error data */ private static function showError($error, $request = "") { $errors = json_decode(json_encode(yaml_parse_file("errors.yml"))); if(is_object($errors->$error)) { self::$j = array_merge(self::$j, (array)$errors->$error); } self::$j["id"] = self::generateID($request); self::$j["request"] = self::generateRequest($request); return self::$j; } /** * Extract current date in multiple formats * @return object The generated date object */ private static function getDate() { $d = new stdClass(); $d->UTC = gmdate("Y-m-d\TH:i:s\Z"); $d->readable = date("l, F j, Y"); $date = new DateTime(); $d->timestamp = $date->getTimestamp(); return $d; } /** * Generate an ID from the request * @param string $request The GET request * @return string The generated data */ private static function generateID($request) { return sha1($request); } /** * Generate a request summary object from the request * @param string $request The GET request * @return object The generated data */ private static function generateRequest($request) { $req = new stdClass(); $req->hash = md5($request); $req->length = strlen($request); $req->text = $request; return $req; } /* ------------------------------------------------------------------------- ROUTING ------------------------------------------------------------------------- */ /** * If not in the "$version" path redirect to the correct url */ public static function route_checkVersion() { $klein = self::$klein; /** * If not in the "$version" path return an error */ $klein->respond("GET", "!@^/" . self::$version . "/", function($request, $response) use($klein) { $right_url = preg_replace('/[^a-zA-Z0-9\/]+/', "", str_replace(self::$prefix, "", self::$version . $request->uri())); $info = explode("/", trim($request->uri(), "/")); if("/" . $info[0] . "/" . $info[1] == self::$prefix && (!isset($info[2]) || isset($info[2]) && $info[2] !== self::$version)) { // Redirect to correct url $klein->response()->redirect(self::$prefix . "/" . $right_url); } }); } /** * Intercept general routes */ public static function route_getGeneralRoute() { $klein = self::$klein; $klein->with(self::$prefix . "/" . self::$version, function() use ($klein) { $klein->respond("GET", "/?", function($request, $response) { return $response->json(self::showError(411)); }); $klein->respond("GET", "/[*:action]", function($request, $response) use($klein) { $dirname = pathinfo($request->action)["dirname"]; $basename = pathinfo($request->action)["basename"]; $filename = pathinfo($request->action)["filename"]; $root = ($dirname == ".") ? $basename : $dirname; if(strlen(trim(preg_replace('/[^a-zA-Z0-9\/]+/', "", $request->action))) > 0) { // Handle non-mapped requests if(in_array($root, self::$mapped_url) === false) { return $response->json(self::showError(400, $request->action)); } } else { // $right_url = preg_replace('/[^a-zA-Z0-9\/]+/', "", $request->uri()); // $klein->response()->redirect($right_url); } }); }); } /** * Get the menu * @uses yaml_parse_file * @link http://php.net/manual/en/book.yaml.php */ public static function route_getMenu() { $klein = self::$klein; $klein->with(self::$prefix . "/" . self::$version, function() use ($klein) { $klein->with("/menu", function() use($klein) { $klein->respond("GET", "/?", function($request, $response) { // Parse YAML file $menu = json_decode(json_encode(yaml_parse_file(YML_DIR . "menu.yml"))); self::$j["response"]->id = 1; self::$j["response"]->type = "menu"; self::$j["response"]->data = $menu; self::$j["request"] = self::generateRequest("/menu"); return $response->json(self::$j); }); $klein->respond("GET", "/[:action]", function($request, $response, $service) use($klein) { $klein->response()->redirect("./"); }); }); }); } /** * Get posts */ public static function route_getPosts() { $klein = self::$klein; $klein->with(self::$prefix . "/" . self::$version, function() use ($klein) { $klein->with("/posts", function() use($klein) { /** * All posts */ $klein->respond("GET", "/?", function($request, $response) { // return "select * from `table`"; self::$j["response"]->id = "*"; self::$j["response"]->type = "posts"; self::$j["response"]->data = ""; // Database query response return $response->json(self::$j); }); /** * Single post */ $klein->respond("GET", "/[:id]", function($request, $response, $service) use($klein) { $klein->onError(function($klein, $err_msg) { $klein->response()->redirect("./" . preg_replace('/[^0-9]+/', "", $klein->request()->id)); }); $service->validateParam("id", "Please enter a valid id")->isChars("0-9"); // return "select * from `table` where `id` = '" . $request->id . "'"; $query = ""; // Database query response if(!is_null($query)) { self::$j["response"]->id = $request->id; self::$j["response"]->type = "posts"; self::$j["response"]->data = $query; header("Content-type: application/json"); return json_encode(self::$j, JSON_NUMERIC_CHECK); } else { return $response->json(self::showError(404)); } }); }); }); } } Routing::run(); ?>