Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

First commit

  • Loading branch information...
commit 8957ebfdbba78d5c816438b6659327bf0ff42f04 0 parents
@dancannon authored
1  .gitignore
@@ -0,0 +1 @@
+.idea
19 LICENSE
@@ -0,0 +1,19 @@
+Copyright (C) 2011 by Daniel Cannon
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
1  README
@@ -0,0 +1 @@
+This file was created by JetBrains PhpStorm 2.1.1 for binding GitHub repository
0  README.md
No changes.
14 lib/WowApi/Api/Api.php
@@ -0,0 +1,14 @@
+<?php
+namespace WowApi\Api;
+
+use WowApi\Request\RequestInterface;
+
+abstract class Api implements ApiInterface
+{
+ protected $request;
+
+ public function __construct(RequestInterface $request)
+ {
+ $this->request = $request;
+ }
+}
9 lib/WowApi/Api/ApiInterface.php
@@ -0,0 +1,9 @@
+<?php
+namespace WowApi\Api;
+
+use \WowApi\Request\RequestInterface;
+
+interface ApiInterface
+{
+ function __construct(RequestInterface $request);
+}
14 lib/WowApi/Api/Character.php
@@ -0,0 +1,14 @@
+<?php
+namespace WowApi\Api;
+
+use WowApi\Utilities;
+
+class Character extends Api
+{
+ public function getCharacter($server, $character, array $fields=array())
+ {
+ $server = Utilities::urlencode($server);
+ $character = Utilities::urlencode($character);
+ $this->request->get("character/$server/$character", array('fields' => implode(',', $fields)));
+ }
+}
10 lib/WowApi/Api/Classes.php
@@ -0,0 +1,10 @@
+<?php
+namespace WowApi\Api;
+
+class Classes extends Api
+{
+ public function getClasses()
+ {
+ return $this->request->get('data/character/classes');
+ }
+}
14 lib/WowApi/Api/Guild.php
@@ -0,0 +1,14 @@
+<?php
+namespace WowApi\Api;
+
+use WowApi\Utilities;
+
+class Guild extends Api
+{
+ public function getGuild($server, $guild, array $fields=array())
+ {
+ $server = Utilities::urlencode($server);
+ $guild = Utilities::urlencode($guild);
+ $this->request->get("/guild/$server/$guild", array('fields' => implode(',', $fields)));
+ }
+}
10 lib/WowApi/Api/GuildPerks.php
@@ -0,0 +1,10 @@
+<?php
+namespace WowApi\Api;
+
+class GuildPerks extends Api
+{
+ public function getPerks()
+ {
+ return $this->request->get('data/guild/perks');
+ }
+}
10 lib/WowApi/Api/GuildRewards.php
@@ -0,0 +1,10 @@
+<?php
+namespace WowApi\Api;
+
+class GuildRewards extends Api
+{
+ public function getRewards()
+ {
+ return $this->request->get('data/guild/rewards');
+ }
+}
13 lib/WowApi/Api/Items.php
@@ -0,0 +1,13 @@
+<?php
+namespace WowApi\Api;
+
+use WowApi\Utilities;
+
+class Items extends Api
+{
+ public function getItem($itemId)
+ {
+ $itemId = Utilities::urlencode($itemId);
+ return $this->request->get("data/item/$itemId");
+ }
+}
10 lib/WowApi/Api/Races.php
@@ -0,0 +1,10 @@
+<?php
+namespace WowApi\Api;
+
+class Races extends Api
+{
+ public function getRaces()
+ {
+ return $this->request->get('data/character/races');
+ }
+}
26 lib/WowApi/Api/Realm.php
@@ -0,0 +1,26 @@
+<?php
+namespace WowApi\Api;
+
+use WowApi\Exception\ApiException;
+
+class Realm extends Api
+{
+ public function getRealm($realm) {
+ return $this->getRealms(array($realm));
+ }
+
+
+ /**
+ * Get status results for specified realm(s).
+ *
+ * @param array $realms String or array of realm(s)
+ * @return mixed
+ */
+ public function getRealms(array $realms = array()) {
+ if (empty($realms)) {
+ return $this->request->get('realm/status');
+ } else {
+ return $this->request->get('realm/status', array('realms' => implode(',', $realms)));
+ }
+ }
+}
13 lib/WowApi/Cache/ApcCache.php
@@ -0,0 +1,13 @@
+<?php
+namespace WowApi\Cache;
+
+class ApcCache extends Cache
+{
+ public function write($key, $data) {
+ apc_store($key, $data);
+ }
+
+ public function read($key) {
+ return apc_fetch($key);
+ }
+}
24 lib/WowApi/Cache/Cache.php
@@ -0,0 +1,24 @@
+<?php
+namespace WowApi\Cache;
+
+abstract class Cache implements CacheInterface
+{
+ public function getCachedResponse($path, $parameters)
+ {
+ $return = array();
+ $return['last-modified'] = $this->read("wowapi:last-modified" . $this->getHash($path, $parameters));
+ $return['response'] = $this->read("wowapi:response" . $this->getHash($path, $parameters));
+ return $return;
+ }
+
+ public function setCachedResponse($path, $parameters, $response, $date)
+ {
+ $this->write("wowapi:last-modified" . $this->getHash($path, $parameters), $date);
+ $this->write("wowapi:response" . $this->getHash($path, $parameters), $response);
+ }
+
+ protected function getHash($path, $parameters)
+ {
+ return md5($path . serialize($parameters));
+ }
+}
10 lib/WowApi/Cache/CacheInterface.php
@@ -0,0 +1,10 @@
+<?php
+namespace WowApi\Cache;
+
+interface CacheInterface
+{
+ function write($key, $data);
+ function read($key);
+ function getCachedResponse($path, $parameters);
+ function setCachedResponse($path, $parameters, $response, $date);
+}
203 lib/WowApi/Client.php
@@ -0,0 +1,203 @@
+<?php
+namespace WowApi;
+
+use WowApi\Request\Curl;
+use WowApi\Cache\CacheInterface;
+use WowApi\Request\Request;
+use WowApi\Request\RequestInterface;
+use WowApi\Api\ApiInterface;
+use WowApi\Api\Character;
+use WowApi\Api\Classes;
+use WowApi\Api\Items;
+use WowApi\Api\Guild;
+use WowApi\Api\GuildPerks;
+use WowApi\Api\GuildRewards;
+use WowApi\Api\Races;
+use WowApi\Api\Realm;
+
+
+if (!function_exists('curl_init')) {
+ throw new \Exception('This API client needs the cURL PHP extension.');
+}
+if (!function_exists('json_decode')) {
+ throw new \Exception('This API client needs the JSON PHP extension.');
+}
+
+class Client
+{
+ protected $request = null;
+
+ protected $apis;
+
+ protected $region;
+
+ protected $regions = array(
+ 'us' => 'us.battle.net',
+ 'eu' => 'eu.battle.net',
+ 'kr' => 'kr.battle.net',
+ 'tw' => 'tw.battle.net',
+ 'cn' => 'battlenet.com.cn',
+ );
+
+ public function __construct($options = array())
+ {
+ $this->request = new Curl($options);
+ }
+
+ public function authenticate($publicKey, $privateKey)
+ {
+ $this->getRequest()->setOption('publicKey', $publicKey);
+ $this->getRequest()->setOption('privateKey', $privateKey);
+ }
+
+ public function setRegion($region)
+ {
+ if(array_key_exists($region, $this->regions)) {
+ $this->region = $region;
+ $this->getRequest()->setOption('region', $region);
+ $this->getRequest()->setOption('baseUrl', $this->regions[$region]);
+ } else {
+ throw new \InvalidArgumentException("That region is not valid");
+ }
+ }
+
+ public function setCache(CacheInterface $cache)
+ {
+ $this->getRequest()->setCache($cache);
+ }
+
+ public function setOption($name, $value)
+ {
+ $this->getRequest()->setOption($name, $value);
+ }
+
+ public function api($path, array $parameters = array(), $httpMethod = 'GET', array $options = array())
+ {
+ $this->getRequest()->send($path, $parameters, $httpMethod, $options);
+ }
+
+ public function getRequest() {
+ return $this->request;
+ }
+
+ public function setRequest($request) {
+ $this->request = $request;
+ }
+
+ public function getApi($name)
+ {
+ return $this->apis[$name];
+ }
+
+ public function setApi($name, ApiInterface $instance)
+ {
+ $this->apis[$name] = $instance;
+ }
+
+ /** API's **/
+
+ /**
+ * Return the character API
+ * @return \WowApi\Api\Character
+ */
+ public function getCharacterApi()
+ {
+ if (!isset($this->apis['character'])) {
+ $this->setApi('character', new Character($this->getRequest()));
+ }
+
+ return $this->apis['character'];
+ }
+
+ /**
+ * Return the classes API
+ * @return \WowApi\Api\Classes
+ */
+ public function getClassesApi()
+ {
+ if (!isset($this->apis['classes'])) {
+ $this->setApi('classes', new Classes($this->getRequest()));
+ }
+
+ return $this->apis['classes'];
+ }
+
+ /**
+ * Return the guild API
+ * @return \WowApi\Api\Guild
+ */
+ public function getGuildApi()
+ {
+ if (!isset($this->apis['guild'])) {
+ $this->setApi('guild', new Guild($this->getRequest()));
+ }
+
+ return $this->apis['guild'];
+ }
+
+ /**
+ * Return the guildPerks API
+ * @return \WowApi\Api\GuildPerks
+ */
+ public function getGuildPerksApi()
+ {
+ if (!isset($this->apis['guildPerks'])) {
+ $this->setApi('guildPerks', new GuildPerks($this->getRequest()));
+ }
+
+ return $this->apis['guildPerks'];
+ }
+
+ /**
+ * Return the guildRewards API
+ * @return \WowApi\Api\GuildRewards
+ */
+ public function getGuildRewardsApi()
+ {
+ if (!isset($this->apis['guildRewards'])) {
+ $this->setApi('guildRewards', new GuildRewards($this->getRequest()));
+ }
+
+ return $this->apis['guildRewards'];
+ }
+
+ /**
+ * Return the races API
+ * @return \WowApi\Api\Races
+ */
+ public function getRacesApi()
+ {
+ if (!isset($this->apis['races'])) {
+ $this->setApi('races', new Races($this->getRequest()));
+ }
+
+ return $this->apis['races'];
+ }
+
+ /**
+ * Return the realm API
+ * @return \WowApi\Api\Realm
+ */
+ public function getRealmApi()
+ {
+ if (!isset($this->apis['realm'])) {
+ $this->setApi('realm', new Realm($this->getRequest()));;
+ }
+
+ return $this->apis['realm'];
+ }
+
+ /**
+ * Return the item API
+ * @return \WowApi\Api\Items
+ */
+ public function getItemsApi()
+ {
+ if (!isset($this->apis['items'])) {
+ $this->setApi('items', new Items($this->getRequest()));;
+ }
+
+ return $this->apis['items'];
+ }
+
+}
7 lib/WowApi/Exception/ApiException.php
@@ -0,0 +1,7 @@
+<?php
+namespace WowApi\Exception;
+
+class ApiException extends \Exception
+{
+
+}
7 lib/WowApi/Exception/RequestException.php
@@ -0,0 +1,7 @@
+<?php
+namespace WowApi\Exception;
+
+class RequestException extends \Exception
+{
+
+}
88 lib/WowApi/Request/Curl.php
@@ -0,0 +1,88 @@
+<?php
+namespace WowApi\Request;
+
+use WowApi\Exception\RequestException;
+use WowApi\Utilities;
+
+class Curl extends Request
+{
+ /**
+ * Send a request to the server, receive a response
+ *
+ * @param string $url Request url
+ * @param array $parameters Parameters
+ * @param string $httpMethod HTTP method to use
+ * @param array $options Request options
+ *
+ * @return string HTTP response
+ */
+ public function makeRequest($url, array $parameters = array(), $httpMethod = 'GET', array $options = array())
+ {
+ //Set cURL options
+ $curlOptions = array(
+ CURLOPT_URL => $url,
+ CURLOPT_TIMEOUT => 10,
+ CURLOPT_ENCODING => "gzip",
+ CURLOPT_FOLLOWLOCATION => true,
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_SSL_VERIFYHOST => false,
+ CURLOPT_SSL_VERIFYPEER => false,
+ CURLOPT_VERBOSE => false,
+ );
+ if(isset($options['curlOptions'])) {
+ $curlOptions = array_merge($options['curlOptions'], $curlOptions);
+ }
+ $curlOptions[CURLOPT_HTTPHEADER] = $this->getRawHeaders();
+
+ // Prepare Data
+ if (!empty($parameters)) {
+ $queryString = '';
+ foreach($parameters as $name => $parameter) {
+ $queryString .= "$name=" . urlencode(str_replace(' ', '-', $parameter));
+ }
+ $queryString = Utilities::normalize($queryString);
+
+ switch($httpMethod) {
+ case 'GET':
+ $curlOptions[CURLOPT_URL] .= "?$queryString";
+ break;
+ case 'POST':
+ $curlOptions[CURLOPT_POST] = true;
+ $curlOptions[CURLOPT_POSTFIELDS] = Utilities::encode($parameters);
+ break;
+ case 'PUT':
+ $file_handle = fopen($parameters, 'r');
+ $curlOptions[CURLOPT_PUT] = true;
+ $curlOptions[CURLOPT_INFILE] = $file_handle;
+ break;
+ case 'DELETE':
+ $curlOptions[CURLOPT_CUSTOMREQUEST] = 'delete';
+ break;
+ }
+ }
+
+ $response = $this->doCurlCall($curlOptions);
+ if ($response['response'] === false) {
+ $e = new RequestException($response['errorMessage'], $response['errorNumber']);
+ throw $e;
+ }else{
+ return $response;
+ }
+ }
+
+ protected function doCurlCall(array $curlOptions)
+ {
+ $curl = curl_init();
+ var_dump($curlOptions);
+ curl_setopt_array($curl, $curlOptions);
+
+ $response = curl_exec($curl);
+ $headers = curl_getinfo($curl);
+ $errorNumber = curl_errno($curl);
+ $errorMessage = curl_error($curl);
+
+ curl_close($curl);
+
+ return compact('response', 'headers', 'errorNumber', 'errorMessage');
+ }
+}
180 lib/WowApi/Request/Request.php
@@ -0,0 +1,180 @@
+<?php
+namespace WowApi\Request;
+
+use WowApi\Exception\ApiException;
+use WowApi\Exception\RequestException;
+use WowApi\Cache\CacheInterface;
+use WowApi\Utilities;
+
+abstract class Request implements RequestInterface
+{
+ protected $headers = array(
+ 'Expect' => '',
+ 'Accept' => 'application/json',
+ 'Accept-Encoding' => 'gzip',
+ 'Content-Type' => 'application/json',
+ 'User-Agent' => 'PHP WowApi (http://github.com/dancannon/PHP-WowApi)',
+ );
+
+ protected $options = array(
+ 'protocol' => 'http',
+ 'baseUrl' => 'us.battle.net',
+ 'region' => 'us',
+ 'url' => ':protocol://:baseUrl:path',
+ 'path' => '/api/wow/:path',
+ 'publicKey' => null,
+ 'privateKey' => null,
+ );
+
+ protected $method = 'GET';
+
+ /**
+ * @var null|\WowApi\Cache\CacheInterface
+ */
+ protected $cache;
+
+ public function __construct(array $options = array())
+ {
+ $this->options = array_merge($this->options, $options);
+ }
+
+ public function setCache(CacheInterface $cache)
+ {
+ $this->cache = $cache;
+ }
+
+ public function get($path, array $parameters = array(), array $options = array())
+ {
+ return $this->send($path, $parameters, 'GET', $options);
+ }
+
+ public function post($path, array $parameters = array(), array $options = array())
+ {
+ return $this->send($path, $parameters, 'POST', $options);
+ }
+
+ public function put($path, array $parameters = array(), array $options = array())
+ {
+ return $this->send($path, $parameters, 'PUT', $options);
+ }
+
+ public function delete($path, array $parameters = array(), array $options = array())
+ {
+ return $this->send($path, $parameters, 'DELETE', $options);
+ }
+
+ public function send($path, array $parameters = array(), $httpMethod = 'GET', array $options = array())
+ {
+ $options = array_merge($this->options, $options);
+
+ // Create resource path
+ $path = strtr($options['path'], array(
+ ':path' => trim($path, '/'),
+ ));
+
+ // Attempt to set If-Modified-Since header
+ if($this->cache !== null) {
+ $cache = $this->cache->getCachedResponse($path, $parameters);
+ if (isset($cache) && isset($cache['last-modified'])) {
+ $this->setHeader('If-Modified-Since', gmdate("D, d M Y H:i:s", $cache['last-modified']) . " GMT");
+ }
+ }
+
+ // Attempt to authenticate application
+ if($this->options['publicKey'] !== null && $this->options['privateKey'] !== null) {
+ $stringToSign = "$httpMethod\n" . $this->getHttpDate(time()) . "\n$path\n";
+ $signature = base64_encode(hash_hmac('sha1', $stringToSign, utf8_encode($this->options['privateKey'])));
+
+ $this->setHeader("Authorization", "BNET " . $this->options['publicKey'] . "+$signature");
+ }
+
+ // create full url
+ $url = strtr($options['url'], array(
+ ':protocol' => $options['protocol'],
+ ':baseUrl' => $options['baseUrl'],
+ ':path' => $path
+ ));
+
+ // Get response
+ $response = $this->makeRequest($url, $parameters, $httpMethod, $options);
+ var_dump($response);
+ //Check for 304 Not Modified header
+ if(isset($cache) && $response['headers']['http_code'] === 304) {
+ return $cache;
+ } else {
+ //$response = Utilities::decode(json_decode($response['response']));
+ $response = json_decode($response['response']);
+ // Check for errors
+ if(!is_object($response)) {
+ throw new ApiException('The response was not valid');
+ } elseif(isset($response->status) && $response->status = 'nok') {
+ if(isset($response->reason)) {
+ throw new ApiException($response->reason);
+ } else {
+ throw new ApiException("Unknown error");
+ }
+ }
+ }
+ if($this->cache !== null) {
+ $this->cache->setCachedResponse($path, $parameters, $response, time());
+ }
+ return $response;
+ }
+
+ /**
+ * Create an RFC 1123 HTTP-Date from various date values
+ *
+ * @param string|int $date Date to convert
+ *
+ * @return string
+ */
+ public function getHttpDate($date)
+ {
+ if (!is_numeric($date)) {
+ $date = strtotime($date);
+ }
+
+ return gmdate('D, d M Y H:i:s', $date) . ' GMT';
+ }
+
+ public function getRawHeaders()
+ {
+ $headers = array();
+ foreach ($this->headers as $key => $value) {
+ $headers[] = $key . ': ' . $value;
+ }
+ return $headers;
+ }
+
+ public function getHeaders() {
+ return $this->headers;
+ }
+
+ public function getHeader($name) {
+ return $this->headers[$name];
+ }
+
+ public function setHeaders($headers) {
+ $this->headers = $headers;
+ }
+
+ public function setHeader($name, $value) {
+ $this->headers[$name] = $value;
+ }
+
+ public function getOption() {
+ return $this->options;
+ }
+
+ public function setOption($name, $value) {
+ $this->options[$name] = $value;
+ }
+
+ public function getOptions() {
+ return $this->options;
+ }
+
+ public function setOptions($options) {
+ $this->options = $options;
+ }
+}
12 lib/WowApi/Request/RequestInterface.php
@@ -0,0 +1,12 @@
+<?php
+namespace WowApi\Request;
+
+interface RequestInterface
+{
+ function get($path, array $parameters = array(), array $options = array());
+ function post($path, array $parameters = array(), array $options = array());
+ function put($path, array $parameters = array(), array $options = array());
+ function delete($path, array $parameters = array(), array $options = array());
+ function send($path, array $parameters = array(), $httpMethod = 'GET', array $options = array());
+ function makeRequest($url, array $parameters = array(), $httpMethod = 'GET', array $options = array());
+}
61 lib/WowApi/Utilities.php
@@ -0,0 +1,61 @@
+<?php
+namespace WowApi;
+
+class Utilities
+{
+ public static function normalize($string)
+ {
+ return \Normalizer::normalize($string, \Normalizer::FORM_KC);
+ }
+
+ public static function urlencode($input)
+ {
+ return urlencode(self::encode($input));
+ }
+
+ public static function encode($input)
+ {
+ if(is_object($input)) {
+ $output = new \stdClass();
+ foreach ($input as $key => $value) {
+ $output->$key = self::encode($value);
+ }
+ } elseif(is_array($input)) {
+ $output = array();
+ foreach ($input as $key => $value) {
+ $output[$key] = self::encode($value);
+ }
+ } else {
+ $output = utf8_encode(self::normalize($input));
+ }
+ return $output;
+ }
+
+ public static function decode($input)
+ {
+ if(is_object($input)) {
+ $output = new \stdClass();
+ foreach ($input as $key => $value) {
+ $output->$key = self::decode($value);
+ }
+ } elseif(is_array($input)) {
+ $output = array();
+ foreach ($input as $key => $value) {
+ $output[$key] = self::decode($value);
+ }
+ } else {
+ $output = utf8_decode($input);
+ }
+ return $output;
+ }
+
+ public static function getIconURL($region, $icon, $size='18')
+ {
+ return sprintf('http://%s.media.blizzard.com/wow/icons/%d/%s.jpg', $region, $size, $icon);
+ }
+
+ public static function getAvatarUrl($region, $avatar)
+ {
+ return sprintf('http://%s.media.blizzard.com/wow/icons/%d/%s.jpg', $region, $avatar);
+ }
+}
0  phpunit.xml.dist
No changes.
Please sign in to comment.
Something went wrong with that request. Please try again.