Guest User

Untitled

a guest
Mar 26th, 2017
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.32 KB | None | 0 0
  1. <?php
  2.  
  3. /*
  4. * REST API module for phpVMS
  5. *
  6. * @author Tom Sterritt
  7. * @link http://sterri.tt/phpvms
  8. * @license The ☺ license (http://license.visualidiot.com)
  9. *
  10. */
  11.  
  12. // Force inclusion of classes that might want to be used
  13. // Because phpVMS doesn't load everything for us
  14. // Bit hacky don't love it...
  15. foreach(glob("core/common/api.*.class.php") as $object){
  16. include_once $object;
  17. }
  18.  
  19. // Main router
  20. class API extends CodonModule {
  21.  
  22. // Store GET/POST/PUT vars for easier access
  23. public static $vars;
  24.  
  25. // Store the user ID on a request
  26. public static $user;
  27.  
  28. // Sensitive keys to remove from output
  29.  
  30.  
  31. // Allow registering other classes to handle requests
  32. private static $externalPaths = array();
  33.  
  34. public static function RegisterClassNameForPath($classname, $path){
  35.  
  36. // No classname
  37. if(!isset($classname) || strlen($classname) < 1){
  38. trigger_error("No classname given trying to register as API resource", E_USER_WARNING);
  39. return;
  40. }
  41.  
  42. // Doesn't even exist
  43. if(!class_exists($classname)){
  44. trigger_error("Cannot register class ".$classname." as API resource - class is not defined", E_USER_WARNING);
  45. return;
  46. }
  47. // Isn't an APIResource
  48. if(!method_exists(new $classname(), 'processPath')){
  49. trigger_error("Cannot register class ".$classname." as API resource - it doesn't implement processPath", E_USER_WARNING);
  50. return;
  51. }
  52.  
  53. // No path
  54. if(!isset($path) || strlen($path) < 1){
  55. trigger_error("No path given trying to register class ".$classname." for API resource", E_USER_WARNING);
  56. return;
  57. }
  58.  
  59. // Already exists
  60. if(array_key_exists($path, self::$externalPaths)){
  61. trigger_error("Cannot register ".$classname." for API path ".$path." - already registered by ".self::$externalPaths[$path], E_USER_WARNING);
  62. return;
  63. }
  64.  
  65. // Gratz you made it
  66. self::$externalPaths[$path] = $classname;
  67. }
  68.  
  69.  
  70. // Access to request method
  71. public static function requestMethod($checkMethod){
  72. return strtoupper(trim($_SERVER['REQUEST_METHOD'])) === $checkMethod;
  73. }
  74.  
  75. // Some pre-request setup
  76. private static function setup(){
  77. header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
  78. header('Content-Type: application/json');
  79.  
  80. // All requests need credentials, let's check those
  81. self::checkUser();
  82.  
  83. if(self::requestMethod("GET")){
  84. self::$vars = $_GET;
  85. } elseif(self::requestMethod("POST") || self::requestMethod("PUT")){
  86. self::$vars = json_decode(file_get_contents("php://input"), true);
  87. }
  88. }
  89.  
  90. // Authenticate the user
  91. private static function checkUser(){
  92. // Check an authorization header has been sent
  93. if(array_key_exists('PHP_AUTH_USER', $_SERVER)){
  94. // PHP has done the work for us
  95. $username = $_SERVER['PHP_AUTH_USER'];
  96. $password = $_SERVER['PHP_AUTH_PW'];
  97. } elseif (array_key_exists('HTTP_AUTHORIZATION', $_SERVER)){
  98. // If not, decode it
  99. if (strpos(strtolower($_SERVER['HTTP_AUTHORIZATION']), 'basic') === 0){
  100. list($username, $password) = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
  101. }
  102. } else {
  103. self::exitWithHeader(401);
  104. }
  105.  
  106. // Check these credentials are ok and they've been approved
  107. // (so people can't just register and immediately gain API access)
  108. $user = PilotData::getPilotData($username);
  109. if(!$user || $user->confirmed != 1 || !Auth::ProcessLogin($username, $password)){
  110. self::exitWithHeader(401);
  111. }
  112.  
  113. // Store the user for later
  114. self::$user = $user;
  115. }
  116.  
  117. // Authorise the user
  118. // Indended to be called at the start of each request type
  119. // Pass the minimum required permissions to complete the request
  120. public static function checkPerms($requiredPermission = NO_ADMIN_ACCESS){
  121. // Now check they have the required permission to complete this action
  122. // We can assume everyone has at least NO_ADMIN_ACCESS by this point
  123. if($requiredPermission > NO_ADMIN_ACCESS){
  124. $groups = PilotGroups::getUserGroups(self::$user->pilotid);
  125. if(!PilotGroups::group_has_perm($groups, $requiredPermission)){
  126. self::exitWithHeader(403);
  127. }
  128. }
  129. }
  130.  
  131. // Send a HTTP Status code or other header
  132. public static function sendHeader($header){
  133. if(is_numeric($header)){
  134. // Send a HTTP status code
  135. switch($header){
  136. case 200: $text = 'OK'; break;
  137. case 201: $text = 'Created'; break;
  138. case 204: $text = 'No Content'; break;
  139. case 400: $text = 'Bad Request'; break;
  140. case 401: $text = 'Unauthorized'; break;
  141. case 403: $text = 'Forbidden'; break;
  142. case 404: $text = 'Not Found'; break;
  143. case 405: $text = 'Method Not Allowed'; break;
  144. case 409: $text = 'Conflict'; break;
  145. case 429: $text = 'Too Many Requests'; break;
  146. case 500: $text = 'Internal Server Error'; break;
  147. default: break;
  148. }
  149.  
  150. $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
  151.  
  152. header($protocol.' '.$header.' '.$text);
  153. } else {
  154. header($header);
  155. }
  156. }
  157.  
  158. // Send a HTTP Status code or other header and exit
  159. public static function exitWithHeader($header){
  160. self::sendHeader($header);
  161. exit;
  162. }
  163.  
  164. // Remove sensitive information from responses
  165. // Uses a default array of sensitive information, but can be overridden if necessary
  166. private static function unsetSensitiveInfo($arr, $sensitiveInfo){
  167. $sensitiveInfo = !$sensitiveInfo ? self::$sensitiveItems : $sensitiveInfo;
  168. foreach($sensitiveInfo as $key){
  169. if(is_object($arr)){
  170. if(property_exists($arr, $key)){
  171. unset($arr->$key);
  172. }
  173. }
  174. if(is_array($arr)){
  175. if(isset($arr[$key]) || array_key_exists($key, $arr)){
  176. unset($arr[$key]);
  177. }
  178. foreach($arr as $item){
  179. if(is_array($item) || is_object($item)){
  180. self::unsetSensitiveInfo($item, $sensitiveInfo);
  181. }
  182. }
  183. }
  184. }
  185. return $arr;
  186. }
  187.  
  188. // Output formatted JSON, removing sensitive items
  189. public static function sendJSON($arr, $sensitiveInfo = NULL){
  190. print_r(json_encode(self::unsetSensitiveInfo($arr, $sensitiveInfo)));
  191. exit;
  192. }
  193.  
  194. // Call at the end of each function, when no other methods complete
  195. public static function noMethod(){
  196. self::exitWithHeader(405);
  197. }
  198.  
  199. // Generate a link URL for a resource
  200. public static function resourceURL($end){
  201. return fileurl('/index.php/api/'.$end);
  202. }
  203.  
  204. //
  205. // - Default index
  206. //
  207. public function index(){
  208. self::setup();
  209.  
  210. $arr = array(
  211. "version" => "0.1.0",
  212. "message" => "Please do not edit or remove this default message. It can be useful for clients to check you have the module installed, and at a compatible version, before attempting to make requests."
  213. );
  214. self::sendJSON($arr);
  215. }
  216.  
  217. // Handle methods not defined here
  218. public function __call($name, $args){
  219. self::setup();
  220.  
  221. if(array_key_exists($name, self::$externalPaths)){
  222. $class = new self::$externalPaths[$name]();
  223. call_user_func_array(array($class, "processPath"), $args);
  224. return;
  225. }
  226.  
  227. self::noMethod();
  228. }
  229.  
  230. }
  231.  
  232. ?>
Add Comment
Please, Sign In to add comment