Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ Simple [Shopify API](http://api.shopify.com/) client in PHP

## Usage and Quickstart Skeleton Project

See [phpish/shopify_app-skeleton](https://github.com/phpish/shopify_app-skeleton) and [phpish/shopify_private_app-skeleton](https://github.com/phpish/shopify_private_app-skeleton)
See [phpish/shopify_app-skeleton](https://github.com/phpish/shopify_app-skeleton) and [phpish/shopify_private_app-skeleton](https://github.com/phpish/shopify_private_app-skeleton)

## FIXED

I had to fix it so it works with the latest HMAC protocols. Unable to reach creator for pull request.
88 changes: 35 additions & 53 deletions shopify.php
Original file line number Diff line number Diff line change
@@ -1,41 +1,29 @@
<?php

namespace phpish\shopify;
use phpish\http;


function install_url($shop, $api_key)
{
return "http://$shop/admin/api/auth?api_key=$api_key";
}


function is_valid_request($query_params, $shared_secret)
{
if (!isset($query_params['timestamp'])) return false;

$seconds_in_a_day = 24 * 60 * 60;
$older_than_a_day = $query_params['timestamp'] < (time() - $seconds_in_a_day);
if ($older_than_a_day) return false;

$signature = $query_params['signature'];
unset($query_params['signature']);

foreach ($query_params as $key=>$val) $params[] = "$key=$val";
sort($params);

return (md5($shared_secret.implode('', $params)) === $signature);
function is_valid_request($query_params, $shared_secret) {
if(!is_array($query_params)) return false;
if(array_key_exists('shop',$query_params) && array_key_exists('timestamp',$query_params) && array_key_exists('hmac',$query_params)) {
$hmac = $query_params['hmac'];
unset($query_params['signature']);
unset($query_params['hmac']);
ksort($query_params);
return $hmac == hash_hmac('sha256', http_build_query($query_params), $shared_secret);
}
return false;
}


function authorization_url($shop, $api_key, $scopes=array(), $redirect_uri='')
{
$scopes = empty($scopes) ? '' : '&scope='.implode(',', $scopes);
$redirect_uri = empty($redirect_uri) ? '' : '&redirect_uri='.urlencode($redirect_uri);
return "https://$shop/admin/oauth/authorize?client_id=$api_key$scopes$redirect_uri";
}


function access_token($shop, $api_key, $shared_secret, $code)
{
try
Expand All @@ -44,27 +32,35 @@ function access_token($shop, $api_key, $shared_secret, $code)
}
catch (http\CurlException $e) { throw new CurlException($e->getMessage(), $e->getCode(), $e->getRequest()); }
catch (http\ResponseException $e) { throw new ApiException($e->getMessage(), $e->getCode(), $e->getRequest(), $e->getResponse()); }

return $response['access_token'];
}


function client($shop, $api_key, $oauth_token, $private_app=false)
{
$base_uri = $private_app ? _private_app_base_url($shop, $api_key, $oauth_token) : "https://$shop/";

return function ($method_uri, $query='', $payload='', &$response_headers=array(), $request_headers=array(), $curl_opts=array()) use ($base_uri, $oauth_token, $private_app)
{
if (!$private_app) $request_headers['X-Shopify-Access-Token'] = $oauth_token;
$request_headers['content-type'] = 'application/json; charset=utf-8';
$http_client = http\client($base_uri, $request_headers);

$http_client = http\client($base_uri, $request_headers, array(
CURLOPT_HEADER => true,
CURLOPT_RETURNTRANSFER => true,
# http://www.php.net/manual/en/function.curl-setopt.php#71313
# CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 3,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_USERAGENT => 'phpish/http',
CURLOPT_CONNECTTIMEOUT => 25,
CURLOPT_TIMEOUT => 25,
CURLOPT_SSLVERSION => 1
));
try
{
$response = $http_client($method_uri, $query, $payload, $response_headers, $request_headers, $curl_opts);
}
catch (http\CurlException $e) { throw new CurlException($e->getMessage(), $e->getCode(), $e->getRequest()); }
catch (http\ResponseException $e) { throw new ApiException($e->getMessage(), $e->getCode(), $e->getRequest(), $e->getResponse()); }
catch (http\Exception $e) { throw new Exception($e->getMessage(), $e->getCode(), $e->getRequest()); }
if (isset($response['errors']))
{
list($method, $uri) = explode(' ', $method_uri, 2);
Expand All @@ -74,43 +70,30 @@ function client($shop, $api_key, $oauth_token, $private_app=false)
$response = array('headers'=>$response_headers, 'body'=>$response);
throw new ApiException($response_headers['http_status_message'].": $uri", $response_headers['http_status_code'], $request, $response);
}

return (is_array($response) and !empty($response)) ? array_shift($response) : $response;

};
}

function _private_app_base_url($shop, $api_key, $password)
{
return "https://$api_key:$password@$shop/";
}


function _private_app_base_url($shop, $api_key, $password)
{
return "https://$api_key:$password@$shop/";
}
function calls_made($response_headers)
{
return _shop_api_call_limit_param(0, $response_headers);
}


function call_limit($response_headers)
{
return _shop_api_call_limit_param(1, $response_headers);
}


function calls_left($response_headers)
function calls_left($response_headers)
{
return call_limit($response_headers) - calls_made($response_headers);
}


function _shop_api_call_limit_param($index, $response_headers)
{
$params = explode('/', $response_headers['http_x_shopify_shop_api_call_limit']);
return (int) $params[$index];
}


function _shop_api_call_limit_param($index, $response_headers)
{
$params = explode('/', $response_headers['http_x_shopify_shop_api_call_limit']);
return (int) $params[$index];
}
class Exception extends http\Exception { }
class CurlException extends Exception { }
class ApiException extends Exception
Expand All @@ -124,5 +107,4 @@ function __construct($message, $code, $request, $response=array(), Exception $pr
parent::__construct($this->message, $code, $request, $response, $previous);
}
}

?>
?>