/**
  * Parse signed message.
  *
  * @throws Exception
  * @param mixed $jsonStr
  * @param string $secretKey
  * @param array $config
  * @return mixed
  */
 static function parseMessage($jsonStr, $secretKey, $config = array())
 {
     if (empty($secretKey)) {
         throw new RublonException('Empty secret');
     }
     if (empty($jsonStr)) {
         throw new RublonException('Empty response', RublonException::CODE_INVALID_RESPONSE);
     }
     // Verify response JSON
     $response = json_decode($jsonStr, true);
     if (empty($response)) {
         throw new RublonException('Invalid response: ' . $jsonStr, RublonException::CODE_INVALID_RESPONSE);
     }
     if (!empty($response[self::FIELD_STATUS]) and $response[self::FIELD_STATUS] == self::STATUS_ERROR) {
         $msg = isset($response[self::FIELD_MSG]) ? $response[self::FIELD_STATUS] : 'Error response: ' . $jsonStr;
         throw new RublonException($msg, RublonException::CODE_INVALID_RESPONSE);
     }
     if (empty($response[self::FIELD_DATA])) {
         throw new RublonException('Missing data field', RublonException::CODE_INVALID_RESPONSE);
     }
     if (empty($response[self::FIELD_SIGN])) {
         throw new RublonException('Missing sign field', RublonException::CODE_INVALID_RESPONSE);
     }
     if (!RublonSignatureWrapper::verifyData($response[self::FIELD_DATA], $secretKey, $response[self::FIELD_SIGN])) {
         throw new RublonException('Invalid signature', RublonException::CODE_INVALID_RESPONSE);
     }
     // Verify data field
     $data = json_decode($response[self::FIELD_DATA], true);
     if (empty($data) or !is_array($data)) {
         throw new RublonException('Invalid response', RublonException::CODE_INVALID_RESPONSE);
     }
     if (!isset($data[self::FIELD_HEAD]) or !is_array($data[self::FIELD_HEAD]) or empty($data[self::FIELD_HEAD])) {
         throw new RublonException('Invalid response data (invalid header)', RublonException::CODE_INVALID_RESPONSE);
     }
     // Verify head field
     $head = $data[self::FIELD_HEAD];
     if (empty($config[self::CONFIG_SKIP_TIME]) and !(isset($head[self::FIELD_HEAD_TIME]) and abs(time() - $head[self::FIELD_HEAD_TIME]) <= self::MESSAGE_LIFETIME)) {
         throw new RublonException('Invalid message time', RublonException::CODE_TIMESTAMP_ERROR);
     }
     if (!isset($data[self::FIELD_BODY]) or !is_string($data[self::FIELD_BODY])) {
         throw new RublonException('Invalid response data (no body)', RublonException::CODE_INVALID_RESPONSE);
     }
     // Verify body field
     $body = json_decode($data[self::FIELD_BODY], true);
     if (is_array($body) and !empty($body)) {
         return $body;
     } else {
         return $data[self::FIELD_BODY];
     }
 }
 /**
  * Parse signed message.
  *
  * @throws Exception
  * @param mixed $jsonStr
  * @param string $secretKey
  * @param array $config
  * @return mixed
  */
 static function parseMessage($jsonStr, $secretKey, $config = array())
 {
     if (empty($secretKey)) {
         throw new RublonException('Invalid API response', RublonException::CODE_INVALID_RESPONSE_EMPTY_SECRET_KEY);
     }
     if (empty($jsonStr)) {
         throw new RublonException('Empty API response', RublonException::CODE_INVALID_RESPONSE_EMPTY_JSON_STRING);
     }
     // Verify response JSON
     $response = json_decode($jsonStr, true);
     if (empty($response)) {
         throw new RublonException('Cannot parse empty API response: ' . $jsonStr, RublonException::CODE_EMPTY_JSON_RESPONSE);
     }
     if (!empty($response[self::FIELD_STATUS]) and $response[self::FIELD_STATUS] == self::STATUS_ERROR) {
         $msg = isset($response[self::FIELD_MSG]) ? $response[self::FIELD_MSG] : 'Cannot parse incorrect API response';
         throw new RublonException($msg, RublonException::CODE_API_RESPONSE_STATUS_ERROR);
     }
     if (empty($response[self::FIELD_DATA])) {
         throw new RublonException('Invalid API response', RublonException::CODE_INVALID_RESPONSE_MISSING_JSON_DATA_FIELD);
     }
     if (empty($response[self::FIELD_SIGN])) {
         throw new RublonException('Invalid API response', RublonException::CODE_INVALID_RESPONSE_MISSING_JSON_SIGN_FIELD);
     }
     if (!RublonSignatureWrapper::verifyData($response[self::FIELD_DATA], $secretKey, $response[self::FIELD_SIGN])) {
         throw new RublonException('Invalid signature', RublonException::CODE_INVALID_RESPONSE_INVALID_SIGNATURE);
     }
     // Verify data field
     $data = json_decode($response[self::FIELD_DATA], true);
     if (empty($data) or !is_array($data)) {
         throw new RublonException('Invalid API response', RublonException::CODE_INVALID_RESPONSE_INVALID_JSON_DATA_FIELD);
     }
     if (!isset($data[self::FIELD_HEAD]) or !is_array($data[self::FIELD_HEAD]) or empty($data[self::FIELD_HEAD])) {
         throw new RublonException('Invalid API response', RublonException::CODE_INVALID_RESPONSE_INVALID_JSON_HEAD_FIELD);
     }
     // Verify head field
     $head = $data[self::FIELD_HEAD];
     if (empty($config[self::CONFIG_SKIP_TIME]) and !(isset($head[self::FIELD_HEAD_TIME]) and abs(time() - $head[self::FIELD_HEAD_TIME]) <= self::MESSAGE_LIFETIME)) {
         throw new RublonException('Invalid message time', RublonException::CODE_TIMESTAMP_ERROR);
     }
     if (!isset($data[self::FIELD_BODY]) or !is_string($data[self::FIELD_BODY])) {
         throw new RublonException('Invalid API response', RublonException::CODE_INVALID_RESPONSE_MISSING_JSON_BODY_FIELD);
     }
     // Verify body field
     $body = json_decode($data[self::FIELD_BODY], true);
     if (is_array($body) and !empty($body)) {
         return $body;
     } else {
         return $data[self::FIELD_BODY];
     }
 }