restful设计架构,例子
1 /** 2 * Project: imooc-restful 3 * User: xialei 4 * Date: 2016/9/18 0018 5 * Time: 9:35 6 */ 7 require_once __DIR__ . '/../handler/User.php'; 8 require_once __DIR__ . '/../handler/Article.php'; 9 require_once __DIR__ . '/../handler/MyHttpException.php'; 10 11 class Bridge 12 { 13 /** 14 * @var User 15 */ 16 private $user; 17 /** 18 * @var Article 19 */ 20 private $article; 21 /** 22 * @var string 请求方法 23 */ 24 private $method; 25 /** 26 * @var string 请求实体 27 */ 28 private $entity; 29 30 /** 31 * @var integer ID 32 */ 33 private $id; 34 35 /** 36 * @var array 允许请求的实体类 37 */ 38 private $allowEntities = ['users', 'articles']; 39 40 private $allowMethods = ['GET', 'POST', 'PUT', 'OPTIONS', 'HEAD', 'DELETE']; 41 42 /** 43 * Bridge constructor. 44 */ 45 public function __construct() 46 { 47 $pdo = require_once __DIR__ . '/../db.php'; 48 $this->user = new User($pdo); 49 $this->article = new Article($pdo); 50 $this->setupRequestMethod(); 51 $this->setupEntity(); 52 } 53 54 /** 55 * 初始化实体 56 */ 57 private function setupEntity() 58 { 59 $pathinfo = $_SERVER['PATH_INFO']; 60 if (empty($pathinfo)) 61 { 62 static::sendHttpStatus(400); 63 } 64 $params = explode('/', $pathinfo); 65 $this->entity = $params[1]; 66 if (!in_array($this->entity, $this->allowEntities)) 67 { 68 //实体不存在 69 static::sendHttpStatus(404); 70 } 71 if (!empty($params[2])) 72 { 73 $this->id = $params[2]; 74 } 75 } 76 77 /** 78 * 发送HTTP响应状态码 79 * @param $code 80 * @param string $error 81 * @param array|null $data 82 * @internal param null $message 83 */ 84 static function sendHttpStatus($code, $error = '', $data = null) 85 { 86 static $_status = array( 87 // Informational 1xx 88 100 => 'Continue', 89 101 => 'Switching Protocols', 90 // Success 2xx 91 200 => 'OK', 92 201 => 'Created', 93 202 => 'Accepted', 94 203 => 'Non-Authoritative Information', 95 204 => 'No Content', 96 205 => 'Reset Content', 97 206 => 'Partial Content', 98 // Redirection 3xx 99 300 => 'Multiple Choices', 100 301 => 'Moved Permanently', 101 302 => 'Found', // 1.1 102 303 => 'See Other', 103 304 => 'Not Modified', 104 305 => 'Use Proxy', 105 // 306 is deprecated but reserved 106 307 => 'Temporary Redirect', 107 // Client Error 4xx 108 400 => 'Bad Request', 109 401 => 'Unauthorized', 110 402 => 'Payment Required', 111 403 => 'Forbidden', 112 404 => 'Not Found', 113 405 => 'Method Not Allowed', 114 406 => 'Not Acceptable', 115 407 => 'Proxy Authentication Required', 116 408 => 'Request Timeout', 117 409 => 'Conflict', 118 410 => 'Gone', 119 411 => 'Length Required', 120 412 => 'Precondition Failed', 121 413 => 'Request Entity Too Large', 122 414 => 'Request-URI Too Long', 123 415 => 'Unsupported Media Type', 124 416 => 'Requested Range Not Satisfiable', 125 417 => 'Expectation Failed', 126 422 => 'Unprocessable Entity', 127 // Server Error 5xx 128 500 => 'Internal Server Error', 129 501 => 'Not Implemented', 130 502 => 'Bad Gateway', 131 503 => 'Service Unavailable', 132 504 => 'Gateway Timeout', 133 505 => 'HTTP Version Not Supported', 134 509 => 'Bandwidth Limit Exceeded' 135 ); 136 if (isset($_status[$code])) 137 { 138 header('HTTP/1.1 ' . $code . ' ' . $_status[$code]); 139 header('Content-Type:application/json;charset=utf-8'); 140 if ($code == 200) //2xx状态码 141 { 142 echo json_encode($data, JSON_UNESCAPED_UNICODE); 143 } 144 else if ($code == 204) 145 { 146 //无响应体 147 } 148 else 149 { 150 if (empty($error)) 151 { 152 $error = $_status[$code]; 153 } 154 echo json_encode(['error' => $error], JSON_UNESCAPED_UNICODE); 155 } 156 } 157 exit(0); 158 } 159 160 /** 161 * 初始化请求方法 162 */ 163 private function setupRequestMethod() 164 { 165 $this->method = $_SERVER['REQUEST_METHOD']; 166 if (!in_array($this->method, $this->allowMethods)) 167 { 168 //请求方法不被允许 169 static::sendHttpStatus(405); 170 } 171 } 172 173 /** 174 * 处理请求 175 */ 176 public function handle() 177 { 178 try 179 { 180 if ($this->entity == 'users') 181 { 182 $this->handleUser(); 183 } 184 if ($this->entity == 'articles') 185 { 186 $this->handleArticle(); 187 } 188 } 189 catch (MyHttpException $e) 190 { 191 static::sendHttpStatus($e->getStatusCode(), $e->getMessage()); 192 } 193 } 194 195 /** 196 * 获取请求体 197 * @return mixed|null 198 */ 199 private function getBodyParams() 200 { 201 $raw = file_get_contents('php://input'); 202 if (empty($raw)) 203 { 204 return []; 205 } 206 return json_decode($raw, true); 207 } 208 209 private function getBodyParam($name, $defaultValue = null) 210 { 211 $data = $this->getBodyParams(); 212 return isset($data[$name]) ? $data[$name] : $defaultValue; 213 } 214 215 /** 216 * 要求认证 217 * @return bool|array 218 * @throws MyHttpException 219 */ 220 private function requestAuth() 221 { 222 if (!empty($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_PW'])) 223 { 224 try 225 { 226 $user = $this->user->login($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']); 227 return $user; 228 } 229 catch (MyHttpException $e) 230 { 231 if ($e->getStatusCode() != 422) 232 { 233 throw $e; 234 } 235 } 236 } 237 header("WWW-Authenticate:Basic realm='Private'"); 238 header('HTTP/1.0 401 Unauthorized'); 239 print "You are unauthorized to enter this area."; 240 exit(0); 241 } 242 243 /** 244 * 处理访问用户的请求 245 */ 246 private function handleUser() 247 { 248 if ($this->method == 'GET') 249 { 250 if (empty($this->id)) 251 { 252 //客户端需要获取所有用户的信息,访问有效,但是无权限 253 throw new MyHttpException(403); 254 } 255 static::sendHttpStatus(200, null, $this->user->view($this->id)); 256 } 257 else if ($this->method == 'POST') 258 { 259 $data = $this->getBodyParams(); 260 if (empty($data['username'])) 261 { 262 throw new MyHttpException(422, '用户名不能为空'); 263 } 264 if (empty($data['password'])) 265 { 266 throw new MyHttpException(422, '密码不能为空'); 267 } 268 static::sendHttpStatus(200, null, $this->user->register($data['username'], $data['password'])); 269 } 270 else if ($this->method == 'PUT') 271 { 272 if (empty($this->id)) 273 { 274 throw new MyHttpException(400); 275 } 276 $params = $this->getBodyParams(); 277 if (empty($params) || empty($params['password'])) 278 { 279 throw new MyHttpException(422, '密码不能为空'); 280 } 281 //检测认证参数 282 $user = $this->requestAuth(); 283 $result = $this->user->update($user['userId'], $params['password']); 284 static::sendHttpStatus(200, null, $result); 285 } 286 else 287 { 288 throw new MyHttpException(405); 289 } 290 } 291 292 private function getQueryParam($name, $defaultValue = null) 293 { 294 return isset($_GET[$name]) ? $_GET[$name] : $defaultValue; 295 } 296 297 /** 298 * 处理访问文章的请求 299 */ 300 private function handleArticle() 301 { 302 if ($this->method == 'GET') 303 { 304 $user = $this->requestAuth(); 305 if (empty($this->id)) 306 { 307 $list = $this->article->all($user['userId'], $this->getQueryParam('page', 1), $this->getQueryParam('size', 10)); 308 self::sendHttpStatus(200, null, $list); 309 } 310 self::sendHttpStatus(200, null, $this->article->view($this->id)); 311 } 312 else if ($this->method == 'POST') 313 { 314 $user = $this->requestAuth(); 315 $data = $this->getBodyParams(); 316 if (empty($data['title'])) 317 { 318 throw new MyHttpException(422, '标题不能为空'); 319 } 320 if (empty($data['content'])) 321 { 322 throw new MyHttpException(422, '内容不能为空'); 323 } 324 $article = $this->article->create($data['title'], $data['content'], $user['userId']); 325 static::sendHttpStatus(200, null, $article); 326 } 327 else if ($this->method == 'PUT') 328 { 329 if (empty($this->id)) 330 { 331 throw new MyHttpException(400); 332 } 333 $user = $this->requestAuth(); 334 $data = $this->getBodyParams(); 335 $title = isset($data['title']) ? $data['title'] : null; 336 $content = isset($data['content']) ? $data['content'] : null; 337 $article = $this->article->update($this->id, $title, $content, $user['userId']); 338 static::sendHttpStatus(200, null, $article); 339 } 340 else if ($this->method == 'DELETE') 341 { 342 if (empty($this->id)) 343 { 344 throw new MyHttpException(400); 345 } 346 $user = $this->requestAuth(); 347 $this->article->delete($this->id, $user['userId']); 348 static::sendHttpStatus(204, null, null); 349 } 350 } 351 } 352 353 354 $bridge = new Bridge(); 355 $bridge->handle();
转于:https://www.imooc.com/video/14365 ,微信xialeistudio
完整代码:https://github.com/xialeistudio/imooc-restful