/app/controllers/ApiController.php
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
- <?php
-
- class ApiController extends Controller
- {
- // Error codes
- const ERROR_NONE = 0;
- const ERROR_APP_KEY_INVALID = 100;
- const ERROR_TOKEN_INVALID = 200;
- const ERROR_ACTION_INVALID = 300;
- const ERROR_PARAMS_INVALID = 400;
-
- // HTTP status codes
- const HTTP_STATUS_OK = 200;
- const HTTP_STATUS_BAD_REQUEST = 400;
- const HTTP_STATUS_UNAUTHORIZED = 401;
- const HTTP_STATUS_INTERNAL_SERVER_ERROR = 500;
-
- private $_game;
-
- /**
- * Outputs an access token which is required to access the api.
- */
- public function actionRequestToken()
- {
- $token = $this->_generateToken();
- $key = $this->_resolveTokenKey();
- Yii::app()->session[$key] = $token;
- echo $token;
- Yii::app()->end();
- }
-
- /**
- * Processes calls made to the api.
- */
- public function actionCall()
- {
- $request = Yii::app()->getRequest();
- $key = $request->getParam('k');
- $query = $request->getParam('r');
-
- $game = $this->_loadGameByApiKey($key);
-
- if (!$game instanceof Game)
- $this->_endRequest(self::HTTP_STATUS_BAD_REQUEST, self::ERROR_APP_KEY_INVALID);
-
- $query = $this->_decryptQuery($query, $game->apiSecret);
-
- if (!isset($query['token']))
- $this->_endRequest(self::HTTP_STATUS_UNAUTHORIZED, self::ERROR_TOKEN_INVALID);
-
- $clientToken = $query['token'];
- $tokenKey = $this->_resolveTokenKey();
-
- if (!isset(Yii::app()->session[$tokenKey]))
- $this->_endRequest(self::HTTP_STATUS_UNAUTHORIZED, self::ERROR_TOKEN_INVALID);
-
- $serverToken = Yii::app()->session[$tokenKey];
-
- if ($clientToken !== $serverToken)
- $this->_endRequest(self::HTTP_STATUS_UNAUTHORIZED, self::ERROR_TOKEN_INVALID);
-
- if (!isset($query['action']))
- $this->_endRequest(self::HTTP_STATUS_BAD_REQUEST, self::ERROR_ACTION_INVALID);
-
- $method = $this->_resolveMethodNameByAction($query['action']);
-
- if (!method_exists($this, $method))
- $this->_endRequest(self::HTTP_STATUS_BAD_REQUEST, self::ERROR_ACTION_INVALID);
-
- $params = isset($query['params']) ? $query['params'] : array();
-
- $result = call_user_func_array(array($this, $method), array($params, $game));
-
- if ($result === false)
- $this->_endRequest(self::HTTP_STATUS_INTERNAL_SERVER_ERROR, self::ERROR_ACTION_INVALID);
-
- $this->_endRequest();
- }
-
- /**
- * Registers a score for the active player.
- * @param array $params the request parameters.
- * @param Game $game the active game.
- * @return boolean the result.
- */
- protected function _doRegisterScore($params, $game)
- {
- if (!isset($params['score']))
- $this->_endRequest(self::HTTP_STATUS_BAD_REQUEST, self::ERROR_PARAMS_INVALID);
-
- $score = new Score();
- $score->gameID = $game->id;
- $score->playerID = Yii::app()->user->getPlayerID();
- $score->score = $params['score'];
- return $score->save();
- }
-
- /**
- * Decrypts the given request.
- * @param string $query the encrypted request.
- * @param string $secret the secret key.
- * @return array the decrypted request.
- */
- protected function _decryptQuery($query, $secret)
- {
- return CJSON::decode($this->_decrypt($query, $secret));
- }
-
- /**
- * Ends the request.
- * @param int $statusCode the http status code.
- * @param int $errorCode the error code.
- * @throws CHttpException if an error occurred.
- */
- protected function _endRequest($statusCode = self::HTTP_STATUS_OK, $errorCode = self::ERROR_NONE)
- {
- if ($errorCode !== self::ERROR_NONE)
- throw new CHttpException($statusCode, 'FAILURE. Error Code: '.$errorCode);
-
- echo 'SUCCESS';
-
- Yii::app()->end();
- }
-
- /**
- * Returns the active game.
- * @params string $key the api key.
- * @return CActiveRecord the game.
- */
- protected function _loadGameByApiKey($key)
- {
- if ($this->_game !== null)
- return $this->_game;
- else
- {
- $game = Game::model()->findByAttributes(array(
- 'apiKey' => $key,
- ));
-
- return $this->_game = $game;
- }
- }
-
- /**
- * Encrypts a string using the given secret key.
- * @param string $value the string to encrypt.
- * @param string $secret the secret key.
- * @return string the encrypted string.
- * todo: make sure that this method actually works, it has not been tested.
- */
- protected function _encrypt($value, $secret)
- {
- $ivSize = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
- $padding = $ivSize - (strlen((binary) $value) % $ivSize);
- $value .= str_repeat(chr($padding), $padding);
- return base64_encode(mcrypt_encrypt(MCRYPT_BLOWFISH, $secret, $value, MCRYPT_MODE_ECB));
- }
-
- /**
- * Decrypts a string using the given secret key.
- * @param string $value the string to decrypt.
- * @param string $secret the secret key.
- * @return string the decrypted string.
- */
- protected function _decrypt($value, $secret)
- {
- $bytes = mcrypt_decrypt(MCRYPT_BLOWFISH, $secret, base64_decode($value), MCRYPT_MODE_ECB);
- $length = strlen($bytes);
- $padding = ord($bytes[$length - 1]);
- return substr($bytes, 0, $length - $padding);
- }
-
- /**
- * Creates a unique token.
- * @return string the token.
- */
- protected function _generateToken()
- {
- return md5(__CLASS__.'_token_'.uniqid(true, true));
- }
-
- /**
- * Returns the token key for the current player.
- * @return string the key.
- */
- protected function _resolveTokenKey()
- {
- return __CLASS__.'_token_'.Yii::app()->user->getPlayerID();
- }
-
- /**
- * Returns the method name for the given action.
- * @param string $name the action name.
- * @return string the method name.
- */
- protected function _resolveMethodNameByAction($action)
- {
- return '_do'.ucfirst($action);
- }
- }