When I am trying to integrate the PayU integration. Whatever changes I do I am getting invalid hash. I think I am doing something minor mistake.
For generating the hash I have written in PHP though currently, all data is static I have matched all are same only.
In the following php example I am using payment_related_details_for_mobile_sdk_hash key in android
Here is my code:
paymentIntegration("741852963", "1.0", "SmartAuto", "Piyush", "piyush.sahay#mail.com", "330122983a2492fe6ff18ad2fcccc6a78ed499f988a6b06b226ff4f27b9b390356f18c297282105b2dbb70166bfd0c2332dfa4e55a784543658bd67330f98b39", "XXXXX:XXXXX#XXXXX.com");
private void paymentIntegration(String txnId, String amount, String productName, String userName, String userEmail, String hash1, String userCredentials) {
HashMap<String, Object> additionalParams = new HashMap<>();
additionalParams.put(PayUCheckoutProConstants.CP_UDF1, "udf1");
additionalParams.put(PayUCheckoutProConstants.CP_UDF2, "udf2");
additionalParams.put(PayUCheckoutProConstants.CP_UDF3, "udf3");
additionalParams.put(PayUCheckoutProConstants.CP_UDF4, "udf4");
additionalParams.put(PayUCheckoutProConstants.CP_UDF5, "udf5");
PayUPaymentParams.Builder builder = new PayUPaymentParams.Builder();
builder.setAmount(amount)
.setIsProduction(true)
.setProductInfo(productName)
.setKey(MERCHANT_KEY)
.setPhone("XXXXXXXX")
.setTransactionId(txnId)
.setFirstName(userName)
.setEmail(userEmail)
.setSurl("https://payu.herokuapp.com/success")
.setFurl("https://payu.herokuapp.com/failure")
.setUserCredential(userCredentials)
.setAdditionalParams(additionalParams);
PayUPaymentParams payUPaymentParams = builder.build();
PayUCheckoutPro.open(
this,
payUPaymentParams,
new PayUCheckoutProListener() {
#Override
public void onPaymentSuccess(Object response) {
//Cast response object to HashMap
HashMap<String,Object> result = (HashMap<String, Object>) response;
String payuResponse = (String)result.get(PayUCheckoutProConstants.CP_PAYU_RESPONSE);
String merchantResponse = (String) result.get(PayUCheckoutProConstants.CP_MERCHANT_RESPONSE);
}
#Override
public void onPaymentFailure(Object response) {
//Cast response object to HashMap
HashMap<String,Object> result = (HashMap<String, Object>) response;
String payuResponse = (String)result.get(PayUCheckoutProConstants.CP_PAYU_RESPONSE);
String merchantResponse = (String) result.get(PayUCheckoutProConstants.CP_MERCHANT_RESPONSE);
}
#Override
public void onPaymentCancel(boolean isTxnInitiated) {
}
#Override
public void onError(ErrorResponse errorResponse) {
String errorMessage = errorResponse.getErrorMessage();
Toast.makeText(getApplicationContext(), errorMessage, Toast.LENGTH_LONG).show();
}
#Override
public void setWebViewProperties(#Nullable WebView webView, #Nullable Object o) {
//For setting webview properties, if any. Check Customized Integration section for more details on this
}
#Override
public void generateHash(HashMap<String, String> valueMap, PayUHashGenerationListener hashGenerationListener) {
String hashName = valueMap.get(PayUCheckoutProConstants.CP_HASH_NAME);
String hashData = valueMap.get(PayUCheckoutProConstants.CP_HASH_STRING);
if (!TextUtils.isEmpty(hashName) && !TextUtils.isEmpty(hashData)) {
//Do not generate hash from local, it needs to be calculated from server side only. Here, hashString contains hash created from your server side.
String hash = hash1;
HashMap<String, String> dataMap = new HashMap<>();
dataMap.put(hashName, hash);
hashGenerationListener.onHashGenerated(dataMap);
}
}
}
);
}
Here is my PHP Code for a hash generation:
$output=getHashes("741852963", "1.0", "SmartAuto", "Piyush", "piyush.sahay#gmail.com", "XXXXX:XXXXX#XXXXX.com","udf1","udf2","udf3","udf4","udf5","","" );
function getHashes($txnid, $amount, $productinfo, $firstname, $email, $user_credentials, $udf1, $udf2, $udf3, $udf4, $udf5,$offerKey,$cardBin)
{
// $firstname, $email can be "", i.e empty string if needed. Same should be sent to PayU server (in request params) also.
$key = 'XXXXX';
$salt = 'XXXXXX';
$payhash_str = $key . '|' . checkNull($txnid) . '|' .checkNull($amount) . '|' .checkNull($productinfo) . '|' . checkNull($firstname) . '|' . checkNull($email) . '|' . checkNull($udf1) . '|' . checkNull($udf2) . '|' . checkNull($udf3) . '|' . checkNull($udf4) . '|' . checkNull($udf5) . '||||||' . $salt;
$paymentHash = strtolower(hash('sha512', $payhash_str));
$arr['payment_hash'] = $paymentHash;
$cmnNameMerchantCodes = 'get_merchant_ibibo_codes';
$merchantCodesHash_str = $key . '|' . $cmnNameMerchantCodes . '|default|' . $salt ;
$merchantCodesHash = strtolower(hash('sha512', $merchantCodesHash_str));
$arr['get_merchant_ibibo_codes_hash'] = $merchantCodesHash;
$cmnMobileSdk = 'vas_for_mobile_sdk';
$mobileSdk_str = $key . '|' . $cmnMobileSdk . '|default|' . $salt;
$mobileSdk = strtolower(hash('sha512', $mobileSdk_str));
$arr['vas_for_mobile_sdk_hash'] = $mobileSdk;
$cmnPaymentRelatedDetailsForMobileSdk1 = 'payment_related_details_for_mobile_sdk';
$detailsForMobileSdk_str1 = $key . '|' . $cmnPaymentRelatedDetailsForMobileSdk1 . '|default|' . $salt ;
$detailsForMobileSdk1 = strtolower(hash('sha512', $detailsForMobileSdk_str1));
$arr['payment_related_details_for_mobile_sdk_hash'] = $detailsForMobileSdk1;
//used for verifying payment(optional)
$cmnVerifyPayment = 'verify_payment';
$verifyPayment_str = $key . '|' . $cmnVerifyPayment . '|'.$txnid .'|' . $salt;
$verifyPayment = strtolower(hash('sha512', $verifyPayment_str));
$arr['verify_payment_hash'] = $verifyPayment;
if($user_credentials != NULL && $user_credentials != '')
{
$cmnNameDeleteCard = 'delete_user_card';
$deleteHash_str = $key . '|' . $cmnNameDeleteCard . '|' . $user_credentials . '|' . $salt ;
$deleteHash = strtolower(hash('sha512', $deleteHash_str));
$arr['delete_user_card_hash'] = $deleteHash;
$cmnNameGetUserCard = 'get_user_cards';
$getUserCardHash_str = $key . '|' . $cmnNameGetUserCard . '|' . $user_credentials . '|' . $salt ;
$getUserCardHash = strtolower(hash('sha512', $getUserCardHash_str));
$arr['get_user_cards_hash'] = $getUserCardHash;
$cmnNameEditUserCard = 'edit_user_card';
$editUserCardHash_str = $key . '|' . $cmnNameEditUserCard . '|' . $user_credentials . '|' . $salt ;
$editUserCardHash = strtolower(hash('sha512', $editUserCardHash_str));
$arr['edit_user_card_hash'] = $editUserCardHash;
$cmnNameSaveUserCard = 'save_user_card';
$saveUserCardHash_str = $key . '|' . $cmnNameSaveUserCard . '|' . $user_credentials . '|' . $salt ;
$saveUserCardHash = strtolower(hash('sha512', $saveUserCardHash_str));
$arr['save_user_card_hash'] = $saveUserCardHash;
$cmnPaymentRelatedDetailsForMobileSdk = 'payment_related_details_for_mobile_sdk';
$detailsForMobileSdk_str = $key . '|' . $cmnPaymentRelatedDetailsForMobileSdk . '|' . $user_credentials . '|' . $salt ;
$detailsForMobileSdk = strtolower(hash('sha512', $detailsForMobileSdk_str));
$arr['payment_related_details_for_mobile_sdk_hash'] = $detailsForMobileSdk;
}
// if($udf3!=NULL && !empty($udf3)){
$cmnSend_Sms='send_sms';
$sendsms_str=$key . '|' . $cmnSend_Sms . '|' . $udf3 . '|' . $salt;
$send_sms = strtolower(hash('sha512',$sendsms_str));
$arr['send_sms_hash']=$send_sms;
// }
if ($offerKey!=NULL && !empty($offerKey)) {
$cmnCheckOfferStatus = 'check_offer_status';
$checkOfferStatus_str = $key . '|' . $cmnCheckOfferStatus . '|' . $offerKey . '|' . $salt ;
$checkOfferStatus = strtolower(hash('sha512', $checkOfferStatus_str));
$arr['check_offer_status_hash']=$checkOfferStatus;
}
if ($cardBin!=NULL && !empty($cardBin)) {
$cmnCheckIsDomestic = 'check_isDomestic';
$checkIsDomestic_str = $key . '|' . $cmnCheckIsDomestic . '|' . $cardBin . '|' . $salt ;
$checkIsDomestic = strtolower(hash('sha512', $checkIsDomestic_str));
$arr['check_isDomestic_hash']=$checkIsDomestic;
}
return $arr;
}
function checkNull($value) {
if ($value == null) {
return '';
} else {
return $value;
}
}
echo json_encode($output);
Related
I'm trying to use the $rank variable outside the function and class.
class UrlInfo {
protected static $ActionName = 'UrlInfo';
protected static $ResponseGroupName = 'Rank,LinksInCount';
protected static $ServiceHost = 'awis.amazonaws.com';
protected static $ServiceEndpoint = 'awis.us-west-1.amazonaws.com';
protected static $NumReturn = 10;
protected static $StartNum = 1;
protected static $SigVersion = '2';
protected static $HashAlgorithm = '******';
protected static $ServiceURI = "/api";
protected static $ServiceRegion = "us-west-1";
protected static $ServiceName = "awis";
public function __construct($accessKeyId, $secretAccessKey, $site) {
$this->accessKeyId = $accessKeyId;
$this->secretAccessKey = $secretAccessKey;
$this->site = $site;
$now = time();
$this->amzDate = gmdate("Ymd\THis\Z", $now);
$this->dateStamp = gmdate("Ymd", $now);
}
/**
* Get site info from AWIS.
*/
public function getUrlInfo() {
$canonicalQuery = $this->buildQueryParams();
$canonicalHeaders = $this->buildHeaders(true);
$signedHeaders = $this->buildHeaders(false);
$payloadHash = hash('sha256', "");
$canonicalRequest = "GET" . "\n" . self::$ServiceURI . "\n" . $canonicalQuery . "\n" . $canonicalHeaders . "\n" . $signedHeaders . "\n" . $payloadHash;
$algorithm = "AWS4-HMAC-SHA256";
$credentialScope = $this->dateStamp . "/" . self::$ServiceRegion . "/" . self::$ServiceName . "/" . "aws4_request";
$stringToSign = $algorithm . "\n" . $this->amzDate . "\n" . $credentialScope . "\n" . hash('sha256', $canonicalRequest);
$signingKey = $this->getSignatureKey();
$signature = hash_hmac('sha256', $stringToSign, $signingKey);
$authorizationHeader = $algorithm . ' ' . 'Credential=' . $this->accessKeyId . '/' . $credentialScope . ', ' . 'SignedHeaders=' . $signedHeaders . ', ' . 'Signature=' . $signature;
$url = 'https://' . self::$ServiceHost . self::$ServiceURI . '?' . $canonicalQuery;
$ret = self::makeRequest($url, $authorizationHeader);
// echo "\nResults for " . $this->site .":\n\n";
// echo $ret;
self::parseResponse($ret);
}
protected function sign($key, $msg) {
return hash_hmac('sha256', $msg, $key, true);
}
protected function getSignatureKey() {
$kSecret = 'AWS4' . $this->secretAccessKey;
$kDate = $this->sign($kSecret, $this->dateStamp);
$kRegion = $this->sign($kDate, self::$ServiceRegion);
$kService = $this->sign($kRegion, self::$ServiceName);
$kSigning = $this->sign($kService, 'aws4_request');
return $kSigning;
}
/**
* Builds headers for the request to AWIS.
* #return String headers for the request
*/
protected function buildHeaders($list) {
$params = array(
'host' => self::$ServiceEndpoint,
'x-amz-date' => $this->amzDate
);
ksort($params);
$keyvalue = array();
foreach($params as $k => $v) {
if ($list)
$keyvalue[] = $k . ':' . $v;
else {
$keyvalue[] = $k;
}
}
return ($list) ? implode("\n",$keyvalue) . "\n" : implode(';',$keyvalue) ;
}
/**
* Builds query parameters for the request to AWIS.
* Parameter names will be in alphabetical order and
* parameter values will be urlencoded per RFC 3986.
* #return String query parameters for the request
*/
protected function buildQueryParams() {
$params = array(
'Action' => self::$ActionName,
'Count' => self::$NumReturn,
'ResponseGroup' => self::$ResponseGroupName,
'Start' => self::$StartNum,
'Url' => $this->site
);
ksort($params);
$keyvalue = array();
foreach($params as $k => $v) {
$keyvalue[] = $k . '=' . rawurlencode($v);
}
return implode('&',$keyvalue);
}
/**
* Makes request to AWIS
* #param String $url URL to make request to
* #param String authorizationHeader Authorization string
* #return String Result of request
*/
protected function makeRequest($url, $authorizationHeader) {
// echo "\nMaking request to:\n$url\n";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_TIMEOUT, 4);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Accept: application/xml',
'Content-Type: application/xml',
'X-Amz-Date: ' . $this->amzDate,
'Authorization: ' . $authorizationHeader
));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* Parses XML response from AWIS and displays selected data
* #param String $response xml response from AWIS
*/
public static function parseResponse($response) {
$xml = new SimpleXMLElement($response,LIBXML_ERR_ERROR,false,'http://awis.amazonaws.com/doc/2005-07-11');
if($xml->count() && $xml->Response->UrlInfoResult->Alexa->count()) {
$info = $xml->Response->UrlInfoResult->Alexa;
$links = $info->ContentData->LinksInCount;
$rank = $info->TrafficData->Rank;
echo "<br>Links in Count: " .$links;
echo "<br>Rank: " .$rank;
);
}
}
}
}
Does anyone have an idea?
Thanks!
I want to add the $rank to an array;
$arrayinfo = array(
"domain" => $ip,
"ip" => $ipphp,
"Rank" => $rank,);
What if you declare $rank as a static variable like the $name of following example
<?php
class Test{
static $name;
static function setName($name){
self::$name=$name;
}
}
Test::setName("Test Name");
Test::setName("Test1 Name");
echo Test::$name; //Test1 Name
I am working on aws signature version 4. Now my concern is that I receive signature from api request at Amazon api gateway and gateway auhorize and authenticate the request and forward to php microservice. Now I want to detect user from signature that is in request headers. How I can resolve this issue.
Below is my working code through I generate aws signature
public function generateAWSToken($uid) {
try {
$method = 'GET';
$uri = '/dev';
$json = file_get_contents('php://input');
$obj = json_decode($json);
if (isset($obj->method)) {
$m = explode("|", $obj->method);
$method = $m[0];
$uri .= $m[1];
}
$secretKey = env('AWS_SECRET_ACCESS_KEY');
$access_key = env('AKIAJR2JSY655JXI5LIA');
$token = env('AWS_SECRET_ACCESS_KEY');
$region = env('AWS_DEFAULT_REGIO');
$service = 'execute-api';
$options = array();
$headers = array();
$host = "YOUR-API-HOST.execute-api.ap-southeast-1.amazonaws.com";
//Or you can define your host here.. I am using API gateway.
$alg = 'sha256';
$date = new \DateTime('UTC');
$dd = $date->format('Ymd\THis\Z');
$amzdate2 = new \DateTime('UTC');
$amzdate2 = $amzdate2->format('Ymd');
$amzdate = $dd;
$algorithm = 'AWS4-HMAC-SHA256';
// $parameters = (array) $obj->data;
if (isset($obj->data) && ($obj->data == null || empty($obj->data))) {
$obj->data = "";
} else {
$param = "";
// $param = json_encode($obj->data);
// if ($param == "{}") {
// $param = "";
// }
$requestPayload = strtolower($param);
$hashedPayload = hash($alg, $uid);
$canonical_uri = $uri;
$canonical_querystring = '';
$canonical_headers = "content-type:" . "application/json" . "\n" . "host:" . $host . "\n" . "x-amz-date:" . $amzdate . "\n" . "x-amz-security-token:" . $token . "\n";
$signed_headers = 'content-type;host;x-amz-date;x-amz-security-token';
$canonical_request = "" . $method . "\n" . $canonical_uri . "\n" . $canonical_querystring . "\n" . $canonical_headers . "\n" . $signed_headers . "\n" . $hashedPayload;
$credential_scope = $amzdate2 . '/' . $region . '/' . $service . '/' . 'aws4_request';
$string_to_sign = "" . $algorithm . "\n" . $amzdate . "\n" . $credential_scope . "\n" . hash('sha256', $canonical_request) . "";
//string_to_sign is the answer..hash('sha256', $canonical_request)//
$kSecret = 'AWS4' . $secretKey;
$kDate = hash_hmac($alg, $amzdate2, $kSecret, true);
$kRegion = hash_hmac($alg, $region, $kDate, true);
$kService = hash_hmac($alg, $service, $kRegion, true);
$kSigning = hash_hmac($alg, 'aws4_request', $kService, true);
$signature = hash_hmac($alg, $string_to_sign, $kSigning);
$authorization_header = $algorithm . ' ' . 'Credential=' . $access_key . '/' . $credential_scope . ', ' . 'SignedHeaders=' . $signed_headers . ', ' . 'Signature=' . $signature;
$headers = [
'content-type' => 'application/json',
'x-amz-security-token' => $token,
'x-amz-date' => $amzdate,
'Authorization' => $authorization_header];
return $signature;
}
} catch (\Exception $ex) {
return false;
}
}
Suggest any usefull link and method.
How are you generating the AKS+AKI+token? If you are using Cognito pools & identity federation, this should be helpful. This helped me
how to user identity id to link to cognito user pool
PS: this might be a copy-paste error but surely the token is not $token = env('AWS_SECRET_ACCESS_KEY');
I recenlythave tried to convert the preg_replace() line to preg_replace_callback, but with no success. I did try the methods on Stackoverflow, but they seem to be different.
Hope I could get some help with it.
function ame_process_bbcode(&$parser, &$param1, $param2 = '')
{
if (class_exists('vB_BbCodeParser_Wysiwyg') AND is_a($parser, 'vB_BbCodeParser_Wysiwyg'))
{
return $text;
}
else
{
global $vbulletin;
($hook = vBulletinHook::fetch_hook('automediaembed_parse_bbcode_start')) ? eval($hook) : false;
$ameinfo = fetch_full_ameinfo();
$text = preg_replace($ameinfo['find'], $ameinfo['replace'], ($param2 ? $param2 : $param1), 1);
($hook = vBulletinHook::fetch_hook('automediaembed_parse_bbcode_end')) ? eval($hook) : false;
return $text;
}
}
Updates: Thanks to #Barmar, I know now that the issue is related to the fetch_full_ameinfo function.. I will add function below. Maybe it will help others in the long run. I will also include the fix whenever I am done. Thanks to #Barmar for the help.
function &fetch_full_ameinfo($findonly = false, $refresh = false)
{
global $db, $vbulletin, $vbphrase, $stylevar;
static $ameinfo = array();
static $inied, $lastfind;
if ($refresh)
{
$inied = false;
}
if ($lastfind && !$findonly)
{
$inied = false;
$ameinfo = array();
}
if (!$inied)
{
if (!$refresh AND $vbulletin->options['automediaembed_cache'])
{
$path = $vbulletin->options['automediaembed_cache_path'];
if (file_exists($path . "findonly.php"));
{
if ($findonly)
{
include($path . "findonly.php");
}
else
{
include($path . "ameinfo.php");
}
$inied = true;
$lastfind = $findonly;
return $ameinfo;
}
}
if ($vbulletin->options['automediaembed_resolve'])
{
$embed = ",IF(extraction=1 AND embedregexp!= '', embedregexp, '') as embedregexp, IF(extraction=1 AND validation!= '', validation, '') as validation";
$embedwhere = " AND ((extraction = 0 AND embedregexp = '') OR (extraction = 1)) ";
}
else
{
$embedwhere = " AND embedregexp = ''";
}
$sql = "SELECT findcode" . (!$findonly ? ", replacecode,title,container,ameid" : ",extraction$embed") . " FROM " . TABLE_PREFIX . "automediaembed WHERE status=1 $embedwhere
ORDER BY displayorder, title ASC";
$results = $db->query_read_slave($sql);
while ($result = $db->fetch_array($results))
{
if ($result['findcode'])
{
if (!$findonly)
{
$ameinfo['find'][] = "~($result[findcode])~ie";
$ameinfo['replace'][] = 'ame_match_bbcode($param1, $param2, \'' . $result['ameid'] . '\', \'' . ame_slasher($result['title']) . '\', ' . $result['container'] . ', \'' . ame_slasher($result['replacecode']) . '\', \'\\1\', \'\\2\', \'\\3\', \'\\4\', \'\\5\', \'\\6\')';
}
else
{
$ameinfo['find'][] = "~(\[url\]$result[findcode]\[/url\])~ie";
$ameinfo['find'][] = "~(\[url=\"?$result[findcode]\"?\](.*?)\[/url\])~ie";
$ameinfo['replace'][] = 'ame_match("\1", "", ' . intval($result['extraction']) .', "' . ($result['embedregexp'] ? "~" . ame_slasher($result['embedregexp']) . "~sim" : "") . '", "' . ($result['validation'] ? "~" . ame_slasher($result['validation']) . "~sim" : "") . '",$ameinfo)';
$ameinfo['replace'][] = 'ame_match("\1", "\2", ' . intval($result['extraction']) .', "' . ($result['embedregexp'] ? "~" . ame_slasher($result['embedregexp']) . "~sim" : "") . '", "' . ($result['validation'] ? "~" . ame_slasher($result['validation']) . "~sim" : "") . '", $ameinfo)';
}
}
}
$inied = true;
}
$lastfind = $findonly;
return $ameinfo;
}
You can't put the replacement function in fetch_full_ameinfo(), because it needs to refer to the $param1 and $param2 variables, which are local to this function.
This means it needs to use eval() in the current function (this is essentially what preg_replace() does internally when it processes the /e flag).
You need to change the replacement string that fetch_full_ameinfo() creates so that it uses a variable instead of \1, \2, etc. to refer to the capture groups, because the callback function receives the captured matches as an array. So replace the block beginning with if (!$findonly) with this:
if (!$findonly)
{
$ameinfo['find'][] = "~($result[findcode])~i";
$ameinfo['replace'][] = 'ame_match_bbcode($param1, $param2, \'' . $result['ameid'] . '\', \'' . ame_slasher($result['title']) . '\', ' . $result['container'] . ', \'' . ame_slasher($result['replacecode']) . '\', \'$match[1]\', \'$match[2]\', \'$match[3]\', \'$match[4]\', \'$match[5]\', \'$match[6]\')';
}
else
{
$ameinfo['find'][] = "~(\[url\]$result[findcode]\[/url\])~i";
$ameinfo['find'][] = "~(\[url=\"?$result[findcode]\"?\](.*?)\[/url\])~i";
$ameinfo['replace'][] = 'ame_match("$match[1]", "", ' . intval($result['extraction']) .', "' . ($result['embedregexp'] ? "~" . ame_slasher($result['embedregexp']) . "~sim" : "") . '", "' . ($result['validation'] ? "~" . ame_slasher($result['validation']) . "~sim" : "") . '",$ameinfo)';
$ameinfo['replace'][] = 'ame_match("$match[1]", "$match[2]", ' . intval($result['extraction']) .', "' . ($result['embedregexp'] ? "~" . ame_slasher($result['embedregexp']) . "~sim" : "") . '", "' . ($result['validation'] ? "~" . ame_slasher($result['validation']) . "~sim" : "") . '", $ameinfo)';
}
Then change your code to:
$text = preg_replace_callback($ameinfo['find'], function($match) use (&$param1, &$param2, &$ameinfo) {
return eval($ameinfo['replace']);
}, ($param2 ? $param2 : $param1), 1);
i trying to create SAS link to blob resource using PHP. Unfortunately currently in azure SDK there is no method for creating SAS signature.
I wrote a code for generating SAS but when i'm trying to get a resource by the link generated by this method i'm getting this message: Signature fields not well formed.
public function getSharedAccessSignatureURL($container, $blob)
{
$signedStart = date('c', strtotime('-1 day'));
$signedExpiry = date('c', strtotime('+1 day'));
$signedResource = 'b';
$signedPermission = 'r';
$signedIdentifier = '';
$responseContent = "file; attachment";
$responseType = "binary";
$canonicalizedResource = '/'.$this->account['accountName'].'/'.$container.'/'.$blob;
$signedVersion = '2014-02-14';
$stringToSign =
$signedPermission."\n".
$signedStart."\n".
$signedExpiry."\n".
$canonicalizedResource."\n".
$signedIdentifier."\n".
$signedVersion;
$signature = base64_encode(
hash_hmac(
'sha256',
urldecode(utf8_encode($stringToSign)),
$this->account['primaryKey'],
true
)
);
$arrayToUrl = [
'sv='.urlencode($signedVersion),
'st='.urlencode($signedStart),
'se='.urlencode($signedExpiry),
'sr='.urlencode($signedResource),
'sp='.urlencode($signedPermission),
'rscd='.urlencode($responseContent),
'rsct='.urlencode($responseType),
'sig='.urlencode($signature)
];
$url = 'https://'.$this->account['accountName'].'.blob.core.windows.net'.'/'
.$container.'/'
.$blob.'?'.implode('&', $arrayToUrl);
return $url;
}
Any suggest what i am doing wrong? I am commpletle newbie at Microsoft Azure
I believe there's an issue with your $stringToSign variable. Based on the documentation here: http://msdn.microsoft.com/en-US/library/azure/dn140255.aspx, your string to sign should be constructed like the following:
StringToSign = signedpermissions + "\n"
signedstart + "\n"
signedexpiry + "\n"
canonicalizedresource + "\n"
signedidentifier + "\n"
signedversion + "\n"
rscc + "\n"
rscd + "\n"
rsce + "\n"
rscl + "\n"
rsct
considering you're including rscd and rsct in your SAS querystring. Please try the following and see if that makes the difference:
$stringToSign =
$signedPermission."\n".
$signedStart."\n".
$signedExpiry."\n".
$canonicalizedResource."\n".
$signedIdentifier."\n".
$signedVersion."\n".
"\n".
$responseContent."\n".
"\n".
"\n".
$responseType;
UPDATE
Please try the code below. Replace the account name/key, container name and blob name with appropriate values:
<?php
$signedStart = gmdate('Y-m-d\TH:i:s\Z', strtotime('-1 day'));
echo $signedStart."\n";
$signedExpiry = gmdate('Y-m-d\TH:i:s\Z', strtotime('+1 day'));
echo $signedExpiry."\n";
$signedResource = 'b';
$signedPermission = 'r';
$signedIdentifier = '';
$accountName = "[account name]";
$accountKey = "[account key]";
$container = "[container name]";
$blob = "[blob name]";
$canonicalizedResource = '/'.$accountName.'/'.$container.'/'.$blob;
$signedVersion = '2014-02-14';
echo $canonicalizedResource."\n";
$rscc = '';
$rscd = 'file; attachment';//Content disposition
$rsce = '';
$rscl = '';
$rsct = 'binary';//Content type
$stringToSign =
$signedPermission."\n".
$signedStart."\n".
$signedExpiry."\n".
$canonicalizedResource."\n".
$signedIdentifier."\n".
$signedVersion."\n".
$rscc."\n".
$rscd."\n".
$rsce."\n".
$rscl."\n".
$rsct;
echo $stringToSign."\n";
$signature = base64_encode(
hash_hmac(
'sha256',
$stringToSign,
base64_decode($accountKey),
true
)
);
echo $signature."\n";
$arrayToUrl = [
'sv='.urlencode($signedVersion),
'st='.urlencode($signedStart),
'se='.urlencode($signedExpiry),
'sr='.urlencode($signedResource),
'sp='.urlencode($signedPermission),
'rscd='.urlencode($rscd),
'rsct='.urlencode($rsct),
'sig='.urlencode($signature)
];
$url = 'https://'.$accountName.'.blob.core.windows.net'.'/'
.$container.'/'
.$blob.'?'.implode('&', $arrayToUrl);
echo $url."\n";
?>
Essentially there were two issues (apart from incorrect $stringToSign variable):
Start/End date time were not properly formatted.
We would need to base64_decode the account key for calculating signature.
I run into exactly the same problem. But now you can use MicrosoftAzure\Storage\Common\SharedAccessSignatureHelper which can handle a lot of problems for you. I has been added to the common libary 2 years ago in this PR (https://github.com/Azure/azure-storage-php/pull/73/files).
And it should be solved very simple like this:
$sasHelper = new SharedAccessSignatureHelper(
'nameofyouraccount',
'H...your-token...=='
);
$sas = $sasHelper->generateAccountSharedAccessSignatureToken(
'2018-11-09',
'rwl',
'b',
'sco',
(new \DateTime())->modify('+10 minute'),
(new \DateTime())->modify('-5 minute'),
'',
'https'
);
$connectionString = "BlobEndpoint=https://nameofyouraccount.blob.core.windows.net/;SharedAccessSignature={$sas}";
And you got your connection string!
modified and turned in to a function from #Gaurav Mantri
function generateSasToken($bucket,$key, $accountName, $accountKey){
$signedStart = gmdate('Y-m-d\TH:i:s\Z', time());
$signedExpiry = gmdate('Y-m-d\TH:i:s\Z', time()+3600);
$signedResource = 'b';
$signedPermission = 'r';
$signedIdentifier = '';
$canonicalizedResource = '/' . $accountName . '/' . $bucket . '/' . $key;
$signedVersion = '2014-02-14';
$rscc = '';
$rscd = 'file; attachment';//Content disposition
$rsce = '';
$rscl = '';
$rsct = 'binary';//Content type
$stringToSign =
$signedPermission . "\n" .
$signedStart . "\n" .
$signedExpiry . "\n" .
$canonicalizedResource . "\n" .
$signedIdentifier . "\n" .
$signedVersion . "\n" .
$rscc . "\n" .
$rscd . "\n" .
$rsce . "\n" .
$rscl . "\n" .
$rsct;
$signature = base64_encode(
hash_hmac(
'sha256',
$stringToSign,
base64_decode($accountKey),
true
)
);
$arrayToUrl = [
'sv=' . urlencode($signedVersion),
'st=' . urlencode($signedStart),
'se=' . urlencode($signedExpiry),
'sr=' . urlencode($signedResource),
'sp=' . urlencode($signedPermission),
'rscd=' . urlencode($rscd),
'rsct=' . urlencode($rsct),
'sig=' . urlencode($signature)
];
$url = 'https://' . $accountName . '.blob.core.windows.net' . '/'
. $bucket . '/'
. $key . '?' . implode('&', $arrayToUrl);
return $url;
}
I currently have this code. It fetches the json data file for each hour and the whole day's file from an api. It then caches the results for faster fetching. It currently takes ~10s to fetch all the files and use them (no caching), it takes ~1 to execute with a cache but it takes ~80s with the method below (with caching) when the cache is stale. There is other code obviously being run on this but this is the slow bit. $this->hours has 24 elements.
Is there a faster way to get the files & cache them?
/**
* Get the weather data from forecast.io
* #return array The overall weather data
*/
public function getData($kernelDir)
{
$apiSite = 'https://api.forecast.io/forecast/';
$url = $apiSite . $this->apiKey . '/' . $this->latitude . ',' . $this->longitude;
if (!file_exists($kernelDir . '/cache/api/' . $this->latitude . '.' . $this->longitude))
{
$weatherFile = #file_get_contents($url);
$fp = fopen($kernelDir . '/cache/api/' . $this->latitude . '.' . $this->longitude, 'w+');
fwrite($fp, $weatherFile);
fclose($fp);
}
else {
$weatherFile = #file_get_contents($kernelDir . '/cache/api/' . $this->latitude . '.' . $this->longitude);
}
$this->weatherData['day'] = #json_decode($weatherFile, true);
$this->getHours();
foreach ($this->hours as $normal => $unixTimestamp)
{
$url = $apiSite . $this->apiKey . '/' . $this->latitude . ',' . $this->longitude . ',' . $unixTimestamp;
if (!file_exists($kernelDir . '/cache/api/' . $this->latitude . '.' . $this->longitude . '.' . $unixTimestamp))
{
$weatherFile = #file_get_contents($url);
$fp = fopen($kernelDir . '/cache/api/' . $this->latitude . '.' . $this->longitude . '.' . $unixTimestamp, 'w+');
fwrite($fp, $weatherFile);
fclose($fp);
}
else {
$weatherFile = #file_get_contents($kernelDir . '/cache/api/' . $this->latitude . ',' . $this->longitude . ',' . $unixTimestamp);
}
$this->weatherData['time'][$normal] = #json_decode($weatherFile, true);
}
return $this->weatherData;
}