PageRenderTime 49ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/app/controllers/ApiController.php

https://bitbucket.org/Crisu83/webgames
PHP | 200 lines | 110 code | 33 blank | 57 comment | 10 complexity | 369ce40568f760be2cb107a1dfdc93a1 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, GPL-3.0, LGPL-2.0, LGPL-2.1, BSD-2-Clause
  1. <?php
  2. class ApiController extends Controller
  3. {
  4. // Error codes
  5. const ERROR_NONE = 0;
  6. const ERROR_APP_KEY_INVALID = 100;
  7. const ERROR_TOKEN_INVALID = 200;
  8. const ERROR_ACTION_INVALID = 300;
  9. const ERROR_PARAMS_INVALID = 400;
  10. // HTTP status codes
  11. const HTTP_STATUS_OK = 200;
  12. const HTTP_STATUS_BAD_REQUEST = 400;
  13. const HTTP_STATUS_UNAUTHORIZED = 401;
  14. const HTTP_STATUS_INTERNAL_SERVER_ERROR = 500;
  15. private $_game;
  16. /**
  17. * Outputs an access token which is required to access the api.
  18. */
  19. public function actionRequestToken()
  20. {
  21. $token = $this->_generateToken();
  22. $key = $this->_resolveTokenKey();
  23. Yii::app()->session[$key] = $token;
  24. echo $token;
  25. Yii::app()->end();
  26. }
  27. /**
  28. * Processes calls made to the api.
  29. */
  30. public function actionCall()
  31. {
  32. $request = Yii::app()->getRequest();
  33. $key = $request->getParam('k');
  34. $query = $request->getParam('r');
  35. $game = $this->_loadGameByApiKey($key);
  36. if (!$game instanceof Game)
  37. $this->_endRequest(self::HTTP_STATUS_BAD_REQUEST, self::ERROR_APP_KEY_INVALID);
  38. $query = $this->_decryptQuery($query, $game->apiSecret);
  39. if (!isset($query['token']))
  40. $this->_endRequest(self::HTTP_STATUS_UNAUTHORIZED, self::ERROR_TOKEN_INVALID);
  41. $clientToken = $query['token'];
  42. $tokenKey = $this->_resolveTokenKey();
  43. if (!isset(Yii::app()->session[$tokenKey]))
  44. $this->_endRequest(self::HTTP_STATUS_UNAUTHORIZED, self::ERROR_TOKEN_INVALID);
  45. $serverToken = Yii::app()->session[$tokenKey];
  46. if ($clientToken !== $serverToken)
  47. $this->_endRequest(self::HTTP_STATUS_UNAUTHORIZED, self::ERROR_TOKEN_INVALID);
  48. if (!isset($query['action']))
  49. $this->_endRequest(self::HTTP_STATUS_BAD_REQUEST, self::ERROR_ACTION_INVALID);
  50. $method = $this->_resolveMethodNameByAction($query['action']);
  51. if (!method_exists($this, $method))
  52. $this->_endRequest(self::HTTP_STATUS_BAD_REQUEST, self::ERROR_ACTION_INVALID);
  53. $params = isset($query['params']) ? $query['params'] : array();
  54. $result = call_user_func_array(array($this, $method), array($params, $game));
  55. if ($result === false)
  56. $this->_endRequest(self::HTTP_STATUS_INTERNAL_SERVER_ERROR, self::ERROR_ACTION_INVALID);
  57. $this->_endRequest();
  58. }
  59. /**
  60. * Registers a score for the active player.
  61. * @param array $params the request parameters.
  62. * @param Game $game the active game.
  63. * @return boolean the result.
  64. */
  65. protected function _doRegisterScore($params, $game)
  66. {
  67. if (!isset($params['score']))
  68. $this->_endRequest(self::HTTP_STATUS_BAD_REQUEST, self::ERROR_PARAMS_INVALID);
  69. $score = new Score();
  70. $score->gameID = $game->id;
  71. $score->playerID = Yii::app()->user->getPlayerID();
  72. $score->score = $params['score'];
  73. return $score->save();
  74. }
  75. /**
  76. * Decrypts the given request.
  77. * @param string $query the encrypted request.
  78. * @param string $secret the secret key.
  79. * @return array the decrypted request.
  80. */
  81. protected function _decryptQuery($query, $secret)
  82. {
  83. return CJSON::decode($this->_decrypt($query, $secret));
  84. }
  85. /**
  86. * Ends the request.
  87. * @param int $statusCode the http status code.
  88. * @param int $errorCode the error code.
  89. * @throws CHttpException if an error occurred.
  90. */
  91. protected function _endRequest($statusCode = self::HTTP_STATUS_OK, $errorCode = self::ERROR_NONE)
  92. {
  93. if ($errorCode !== self::ERROR_NONE)
  94. throw new CHttpException($statusCode, 'FAILURE. Error Code: '.$errorCode);
  95. echo 'SUCCESS';
  96. Yii::app()->end();
  97. }
  98. /**
  99. * Returns the active game.
  100. * @params string $key the api key.
  101. * @return CActiveRecord the game.
  102. */
  103. protected function _loadGameByApiKey($key)
  104. {
  105. if ($this->_game !== null)
  106. return $this->_game;
  107. else
  108. {
  109. $game = Game::model()->findByAttributes(array(
  110. 'apiKey' => $key,
  111. ));
  112. return $this->_game = $game;
  113. }
  114. }
  115. /**
  116. * Encrypts a string using the given secret key.
  117. * @param string $value the string to encrypt.
  118. * @param string $secret the secret key.
  119. * @return string the encrypted string.
  120. * todo: make sure that this method actually works, it has not been tested.
  121. */
  122. protected function _encrypt($value, $secret)
  123. {
  124. $ivSize = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
  125. $padding = $ivSize - (strlen((binary) $value) % $ivSize);
  126. $value .= str_repeat(chr($padding), $padding);
  127. return base64_encode(mcrypt_encrypt(MCRYPT_BLOWFISH, $secret, $value, MCRYPT_MODE_ECB));
  128. }
  129. /**
  130. * Decrypts a string using the given secret key.
  131. * @param string $value the string to decrypt.
  132. * @param string $secret the secret key.
  133. * @return string the decrypted string.
  134. */
  135. protected function _decrypt($value, $secret)
  136. {
  137. $bytes = mcrypt_decrypt(MCRYPT_BLOWFISH, $secret, base64_decode($value), MCRYPT_MODE_ECB);
  138. $length = strlen($bytes);
  139. $padding = ord($bytes[$length - 1]);
  140. return substr($bytes, 0, $length - $padding);
  141. }
  142. /**
  143. * Creates a unique token.
  144. * @return string the token.
  145. */
  146. protected function _generateToken()
  147. {
  148. return md5(__CLASS__.'_token_'.uniqid(true, true));
  149. }
  150. /**
  151. * Returns the token key for the current player.
  152. * @return string the key.
  153. */
  154. protected function _resolveTokenKey()
  155. {
  156. return __CLASS__.'_token_'.Yii::app()->user->getPlayerID();
  157. }
  158. /**
  159. * Returns the method name for the given action.
  160. * @param string $name the action name.
  161. * @return string the method name.
  162. */
  163. protected function _resolveMethodNameByAction($action)
  164. {
  165. return '_do'.ucfirst($action);
  166. }
  167. }