1<?php 2 3class DokuAJAXColidingParamException extends Exception { 4 private $param = ''; 5 public function param() { return $this->param; } 6 public function __construct($param) { $this->param = $param; } 7} 8 9 10/** 11 * The base class for all AJAX handlers 12 * @author Junling Ma <junlingm@gmail.com> 13 */ 14abstract class Doku_AJAX { 15 private $required = array(); 16 private $optional = array(); 17 18 /** 19 * returns the name of the component 20 * Note different types of components can have identical names, 21 * but components of the same type cannot. 22 * @return string the name of the component. 23 */ 24 abstract public function name(); 25 26 /** 27 * return an error mesage to the client 28 * @param numeric $code the error code; 29 * @param string msg (optional) the error message 30 */ 31 protected function error($code, $msg='') { 32 if (function_exists('http_response_code') && !$msg) { 33 http_response_code($code); 34 exit; 35 } 36 if (!$msg) { 37 switch ($code) { 38 case 200: $msg = 'OK'; break; 39 case 400: $msg = 'Bad request'; break; 40 case 401: $msg = 'Unauthorized'; break; 41 case 403: $msg = 'Forbidden'; break; 42 case 404: $msg = 'Not Found'; break; 43 case 416: $msg = 'Requested Range Not Satisfiable'; break; 44 default: $code = 200; $msg = "OK"; break; 45 } 46 } 47 header("HTTP/1.0 $code $msg"); 48 exit; 49 } 50 51 /** 52 * send the result back to the client and exit 53 * @param mixed $result the result to send back to the client 54 */ 55 protected function respond($result) { 56 header('Content-Type: application/json'); 57 $json = new JSON(); 58 echo $json->encode($result); 59 exit; 60 } 61 62 /** 63 * check whether the caller has enough auth level 64 * @param array params the array of aprameters for this call, 65 * with the keys as the parameter names and the values as the parameter values 66 * @return bool whether the call is authorized 67 */ 68 abstract protected function auth($params); 69 70 /** 71 * call the ajax function 72 * @param array $params the array of parameters passed in, 73 * with the keys as parameter names and the value as their values; 74 * @return mixed the value to be returned to the client; 75 */ 76 abstract protected function call($params); 77 78 /** 79 * the default constructor 80 * @param array $required (optional) array of required parameters with 81 * the variable name as the key and its type as the value. 82 * @param array $optional (optional) array of optional parameters with 83 * the variable name as the key and its type as the value. 84 */ 85 public function __construct($required=array(), $optional=array()) { 86 $this->required = $required; 87 $this->optional = $optional; 88 } 89 90 /** 91 * handles the call 92 */ 93 public function handle() { 94 $params = array(); 95 $types = array(); 96 foreach ($this->required as $var => $type) { 97 $params[$var] = TRUE; 98 $types[$var] = $type; 99 } 100 foreach ($this->optional as $var => $type) { 101 if (isset($vars[$var])) throw new DokuAJAXColidingParamException($var); 102 $params[$var] = FALSE; 103 $types[$var] = $type; 104 } 105 $vars = array(); 106 107 global $INPUT; 108 // check security token 109 $sectok = $INPUT->str('sectok'); 110 if (!checkSecurityToken($sectok)) 111 $this->error(403); 112 // check the presence of parameters 113 $json = new JSON; 114 foreach ($params as $var => $req) { 115 if ($INPUT->has($var)) { 116 $value = $INPUT->param($var); 117 if (is_array($value)) $type = 'array'; 118 else if (is_string($value)) { 119 if ($types[$var] == 'array') { 120 $value = $json->decode($value); 121 $type = is_array($value) ? 'array' : NULL; 122 } else $type = 'string'; 123 } 124 else if (is_integer($value)) $type = 'int'; 125 else if (is_float($value)) $type = 'float'; 126 else if (is_bool($value)) $type = 'bool'; 127 else $type = NULL; 128 if ($type !== $types[$var]) { 129 $this->error(400, $var . ' is expected to be ' . $types[$var] . ' : '.$type); 130 } 131 $vars[$var] = $value; 132 } else if ($req) $this->error(400); 133 } 134 135 if (!$this->auth($vars)) $this->error(403); 136 $this->respond($this->call($vars)); 137 } 138}