wrote this file. * As long as you retain this notice you can do whatever you want with * this stuff. If we meet some day, and you think this stuff is worth it, * you can buy me a beer in return. * * @author Sven Strittmatter * @copyright Copyright (c) 2010, Sven Strittmatter. * @version 0.2.2 * @license http://www.weltraumschaf.de/the-beer-ware-license.txt */ /** * @see Api_Log */ require_once 'Api/Log.php'; /** * This class abstracts a KWICK! API request. * * It utilizes the HttpRequest class from pecl_http. * * It does for you the signature generating stuff. */ class Api_Kwick_Request { /** * URI suffix for version 2.0. * * @var string */ const VERSION_20 = '2.0'; /** * Deafult method name. * IS called if method or service was ommited. * * @var string */ const DEFAULT_METHOD = 'getAPIVersion'; /** * Deafult service name. * IS called if method or service was ommited. * * @var string */ const DEFAULT_SERVICE = 'application'; /** * The base URI for the API requests. * * @see configs/app.sample.php * @var string */ private $baseUri; /** * A md5 hash you got after registering your app. * * @var string */ private $apiKey; /** * A sha1 hash. * * You have to deal with to secrets, which is not so obvious in the dcumentation. * First you have a so called app secret which you got after resgistering your app. * After the authentication process (which each user of your app need to perform) * you got a session hash and a so called user secret. All authenticated * API calls needs the second user secret. The app secret is only neccessary * to perform authentication. * * @var string */ private $secret; /** * The API version. * * Is appended to the base URI. There is only version 2.0 yet. * @var */ private $version; /** * The called method. * * @var string */ private $method; /** * The called service. * * @var string */ private $service; /** * Assoc array with the API calls parameters. * * The key is the parameter name: * * 'foo', * 'name2' => 'bar', * //... * 'namen' => '...' * ); * * @var array */ private $parameters; private $files; public function __construct(Api_Kwick_Config $config) { $this->setBaseUri($config->get('baseUri')); $this->setApiKey($config->get('apiKey')); $this->setSecret($config->get('secret')); $this->version = $config->get('version', self::VERSION_20); $this->service = self::DEFAULT_SERVICE; $this->method = self::DEFAULT_METHOD; $this->parameters = array(); $this->files = array(); } public function setBaseUri($uri) { $this->baseUri = (string) $uri; } public function getBaseUri() { return $this->baseUri; } public function setApiKey($key) { $this->apiKey = (string) $key; } public function getApiKey() { return $this->apiKey; } public function setFiles(array $files) { $this->files = $files; } public function setSecret($secret) { $this->secret = (string) $secret; } public function getSecret() { return $this->secret; } public function setParameter($name, $value) { if (isset($this->parameters[$name])) { Api_Log::log("Parameter '$name' already set."); if ($this->parameters[$name] !== $value) { Api_Log::log("Change parameter '$name' from '{$this->parameters[$name]}' to '{$value}'."); } else { return; } } $trace = debug_backtrace(); $frame = $trace[1]; Api_Log::log("Set parameter: '$name' with: '$value' in {$frame['class']}::{$frame['function']}." ); $this->parameters[$name] = $value; } public function setMethod($method) { Api_Log::log('Set method to: ' . $method); $this->method = (string) $method; } public function setService($service) { Api_Log::log('Set service to: ' . $service); $this->service = (string) $service; } public function send(HttpRequest $httpRequest = null) { if (null === $httpRequest) { if (!class_exists('HttpRequest', false)) { throw new RuntimeException('Can not find class HttpRequest! Install pecl http.'); } $httpRequest = new HttpRequest(); } $url = $this->generateUri(); if (!empty($this->files)) { foreach ($this->files as $fileName => $fileUpload) { $httpRequest->addPostFile($fileName, $fileUpload['tmp_name']); } } Api_Log::log('Send request with url: ' . $url); $httpRequest->setUrl($url); $httpRequest->setMethod(HttpRequest::METH_POST); $start = microtime(true); $httpRequest->send(); $time = microtime(true) - $start; Api_Log::log('Duration of api request: ' . round($time, 3) . 's'); if ($httpRequest->getResponseCode() < 500) { switch ($httpRequest->getResponseCode()) { case 401: $message = 'Authroization required on URI: ' . $url; throw new RuntimeException($message, 401); case 404: $message = 'Not found URI: ' . $url; throw new RuntimeException($message, 404); default: return $httpRequest->getResponseBody(); } } $message = 'Got a server error response on URI: ' . $url; throw new RuntimeException($message, $httpRequest->getResponseCode()); } /** * @deprecated Please use generateUri() instead. * @return string */ public function generateUrl() { return $this->generateUri(); } /** * * @return string */ public function generateUri() { $url = $this->baseUri . '?'; $url .= 'api_key=' . $this->apiKey . '&'; $url .= 'v=' . $this->version . '&'; $url .= 'method=' . $this->getQualifiedMethod() . '&'; $url .= 'sig=' . $this->generateSignature(); if (!empty($this->parameters)) { foreach ($this->parameters as $name => $value) { $url .= '&' . $name . '=' . urlencode($value); } } return $url; } public function getQualifiedMethod() { return $this->service . '.' . $this->method; } public function generateParamString() { $parameters = array_merge($this->parameters, array( 'api_key' => $this->apiKey, 'v' => $this->version, 'method' => $this->getQualifiedMethod() )); ksort($parameters); $parameterString = ''; foreach ($parameters as $name => $value) { $parameterString .= $name . '=' . $value; } return $parameterString; } public function generateSignature() { $plain = $this->generateParamString() . $this->secret; Api_Log::log('Hashing plain signature: ' . $plain); return md5($plain); } }