Skip to content

Commit a26a6e0

Browse files
committed
Functions for creating auth request and getting access token
1 parent a04ac59 commit a26a6e0

File tree

1 file changed

+134
-8
lines changed

1 file changed

+134
-8
lines changed

lib/ShopifyClient.php

Lines changed: 134 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -141,18 +141,14 @@ class ShopifyClient
141141
*/
142142
public function __construct($config)
143143
{
144-
//Remove https:// and trailing slash (if provided)
145-
$config['ShopUrl'] = preg_replace('#^https?://|/$#', '',$config['ShopUrl']);
146144

147-
if (isset($config['ApiKey']) && isset($config['Password'])) {
148-
$apiKey = $config['ApiKey'];
149-
$password = $config['Password'];
150145

151-
$config['ApiUrl'] = "https://$apiKey:$password@" . $config['ShopUrl'] . '/admin/';
146+
if (isset($config['ApiKey']) && isset($config['Password'])) {
147+
$config['ApiUrl'] = ShopifyClient::getAdminUrl($config['ShopUrl'], $config['ApiKey'], $config['Password']);
152148
} elseif (!isset($config['AccessToken'])) {
153149
throw new SdkException("Either AccessToken or ApiKey+Password Combination must be provided!");
154150
} else {
155-
$config['ApiUrl'] = 'https://' . $config['ShopUrl'] . '/admin/';
151+
$config['ApiUrl'] = ShopifyClient::getAdminUrl($config['ShopUrl']);
156152
}
157153

158154
$this->config = $config;
@@ -180,7 +176,7 @@ public function __get($resourceName)
180176
* @param string $resourceName
181177
* @param array $arguments
182178
*
183-
* @throws SdkException if the $name is not a valid resource.
179+
* @throws SdkException if the $name is not a valid ShopifyAPI resource.
184180
*
185181
* @return ShopifyAPI
186182
*/
@@ -205,4 +201,134 @@ public function __call($resourceName, $arguments)
205201

206202
return $resource;
207203
}
204+
205+
/**
206+
* Return the admin url, based on a given shop url
207+
*
208+
* @param string $shopUrl
209+
* @param string $apiKey
210+
* @param string $apiPassword
211+
* @return string
212+
*/
213+
public static function getAdminUrl($shopUrl, $apiKey = null, $apiPassword = null)
214+
{
215+
//Remove https:// and trailing slash (if provided)
216+
$shopUrl = preg_replace('#^https?://|/$#', '', $shopUrl);
217+
218+
if($apiKey && $apiPassword) {
219+
$adminUrl = "https://$apiKey:$apiPassword@$shopUrl/admin/";
220+
} else {
221+
$adminUrl = "https://$shopUrl/admin/";
222+
}
223+
return $adminUrl;
224+
}
225+
226+
/**
227+
* Verify if the request is made from shopify using hmac hash value
228+
*
229+
* @throws SdkException if hmac is not found in the url parameters
230+
*
231+
* @param string $sharedSecret Shared Secret of the Shopify App
232+
*
233+
* @return bool
234+
*/
235+
public static function verifyShopifyRequest($sharedSecret)
236+
{
237+
$data = $_GET;
238+
//Get the hmac and remove it from array
239+
if (isset($data['hmac'])) {
240+
$hmac = $data['hmac'];
241+
unset($data['hmac']);
242+
} else {
243+
throw new SdkException("HMAC value not found in url parameters.");
244+
}
245+
//signature validation is deprecated
246+
if (isset($data['signature'])) {
247+
unset($data['signature']);
248+
}
249+
//Create data string for the remaining url parameters
250+
$dataString = http_build_query($data);
251+
252+
$realHmac = hash_hmac('sha256', $dataString, $sharedSecret);
253+
254+
//hash the values before comparing (to prevent time attack)
255+
if(md5($realHmac) === md5($hmac)) {
256+
return true;
257+
} else {
258+
return false;
259+
}
260+
}
261+
262+
/**
263+
* Redirect the user to the authorization page to allow the app access to the shop
264+
*
265+
* @see https://help.shopify.com/api/guides/authentication/oauth#scopes For allowed scopes
266+
*
267+
* @param array $config
268+
* @param string|string[] $scopes Scopes required by app
269+
* @param string $redirectUrl
270+
*
271+
* @return void
272+
*/
273+
public static function createAuthRequest($config, $scopes, $redirectUrl = null)
274+
{
275+
if (!$redirectUrl) {
276+
//If redirect url is the same as this url, then need to check for access token when redirected back from shopify
277+
if(isset($_GET['code'])) {
278+
return self::getAccessToken($config);
279+
} else {
280+
$redirectUrl = self::getCurrentUrl();
281+
}
282+
}
283+
284+
if (is_array($scopes)) {
285+
$scopes = join(',', $scopes);
286+
}
287+
$authUrl = self::getAdminUrl($config['ShopUrl']) . 'oauth/authorize?client_id=' . $config['ApiKey'] . '&redirect_uri=' . $redirectUrl . "&scope=$scopes";
288+
289+
header("Location: $authUrl");
290+
}
291+
292+
/**
293+
* Get Access token for the API
294+
* Call this when being redirected from shopify page ( to the $redirectUrl) after authentication
295+
*
296+
* @param array $config
297+
*
298+
* @return string
299+
*/
300+
public static function getAccessToken($config)
301+
{
302+
if(self::verifyShopifyRequest($config['SharedSecret'])) {
303+
$data = array(
304+
'client_id' => $config['ApiKey'],
305+
'client_secret' => $config['SharedSecret'],
306+
'code' => $_GET['code'],
307+
);
308+
309+
$response = HttpRequestJson::post(self::getAdminUrl($config['ShopUrl']) . 'oauth/access_token', $data);
310+
311+
return isset($response['access_token']) ? $response['access_token'] : null;
312+
}
313+
}
314+
315+
/**
316+
* Get the url of the current page
317+
*
318+
* @return string
319+
*/
320+
public static function getCurrentUrl()
321+
{
322+
if (isset($_SERVER['HTTPS']) &&
323+
($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) ||
324+
isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
325+
$_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
326+
$protocol = 'https';
327+
}
328+
else {
329+
$protocol = 'http';
330+
}
331+
332+
return "$protocol://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
333+
}
208334
}

0 commit comments

Comments
 (0)