We're just upgrading to form v3.0 and whilst doing so, refactoring our code.
Whilst doing so, we noticed that when using http_build_query which takes an associative array and converts it into an RFC1738 valid URL, that SagePay fails with the following error:
The SuccessURL format is invalid
The form submitting to the SagePay endpoint has an enctype of application/x-www-form-urlencoded.
However... If we manually build the string to encrypt by doing:
$tmp = '';
foreach ($crypt_store as $key => $value) {
$tmp .= sprintf('&%s=%s', $key, $value);
}
It works...
Now as I understand RFC1738, if an url exists within an url, it should be encoded, i.e.
RFC1738:
&VendorTxCode=Test&SuccessUrl=http%3A%2F%2Fwww.stackoverflow.com%3Fa%3Da%26b%3Db&FailureUrl...
SagePay:
&VendorTxCode=Test&SuccessUrl=http://www.stackoverflow.com?a=a&b=b&FailureUrl...
Surely if SagePay are following RFC1738, encoding the URL should work? Or is it because the string is encrypted which means it doesn't really matter?
Any thoughts?
Thanks
Gavin
You are correct. Because the Success / Failure URLs are encrypted within the Crypt field, there is no need to encode them.
Related
I am working on a simple SOAP request from a server in PHP, using the standard SOAP library calls. I do not have the required username and password for authorization; however, I do have the base64-encoded authorization string (from a database) that encoding the username and password would provide. I don't seem to be able to find an example that uses the already-encoded authorization string. Is there a) a technique I can use that allows and transmits the pre-encoded string, and/or b) a function that allows me to parse out the username and password from the encoded string so I can pass those as params?
TIA for any help you can offer!
I figured out the answer:
The base-64 encoded string is simply the login and password encoded. I just decoded the string using base64_decode and split the string on the semicolon (:) symbol. Here's what the code looks like -
$loginAry = split(":", base64_decode(my_encoded_string_here));
$login = $loginAry[0];
$pwd = $loginAry[1];
and used the decoded values to log into the application. Simple as that.
So I am using a REST API, where the API issues a POST request to my server in JSON format. Following is the information it sends:
info: {
id: "9890dsds8",
number: 5,
amount: 33
},
sig: "8jhjbhb78979899h"
sig is a SHA1 signature of the info, this should be used to validate the post. For example, we can validate the info in Ruby with (as given in their example):
require 'json'
require 'cgi'
require 'digest/sha1'
key = "some_key"
params = CGI::parse(post_body)
digest = Digest::SHA1.hexdigest(params["info"]+key)
if digest == params["sig"]
# Valid signature
info = JSON.parse(params["info"])
# Respond with status code 200 and some unique_id
else
# Invalid signature. You should response with a non-200 response code.
end
The unique_id must be a string of UTF8 characters 50 characters in length or less and should be the only contents of the body of your response.
Though I am quite able to understand what's happening, I am not completely able to figure out everything. Mostly, may be because its in Ruby.
Can someone please help me on how to do this in PHP? I am not able to handle this JSON POST request in PHP. A PHP converted version of the snippet would be extremely appreciated. I am also not sure, how to deal with SHA1 aspects in PHP, any special knowledge required?
Thanks a lot!!
I assume that the API will populate the "response" variable in your POST array.
Then:
//Get the JSON string
$json_string = $_POST['response'];
//Decode JSON string to array
$decoded = json_decode($json_string);
//Calculate SHA1 (I am not sure how ruby is concatenating a string with an array, so I will just convert the array to string using implode).
$key = 'somekey';
$hash = sha1(implode("",$decoded['info']) . $key);
if($hash == $decoded['sig']){
//OK!
}else{
//Not OK!
}
I have a SOAP service I am calling with PHP 5.3.1's builtin SoapClient. The first operation I must perform on the service is a custom authentication operation, and one of the required parameters I must pass is a 3DES encrypted string which I am creating using PHP's mcrypt, like so:
$encryptionKey = '1234myKey1234';
$currentFormattedDate = date ("Y/m/d H:i");
$encryptedString = mcrypt_encrypt('tripledes', $encryptionKey, $currentFormattedDate, 'ecb');
If I try to just pass $encryptedString as I get it from mcrypt_encrypt() I get a fatal error on my side and no call is made:
Fatal error: SOAP-ERROR: Encoding: string 'd\xe0...' is not a valid utf-8 string in /path/to/file
However if I utf8_encode() the string as such:
$encryptedString = utf8_encode($encryptedString)
Then the call is made but their webservice responds with the following error:
The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:argStatusDate. The InnerException message was 'There was an error deserializing the object of type System.String. The byte 0x19 is not valid at this location. Line 2, position 318.'.
This is the closest I can get to success with this process after having tried so many things that I'm back to square one. I have verified I can just pass a bogus string which results in the expected response of not being able to authenticate.
I don't think this should make any difference since I believe the SOAP call is ultimately made as utf8, but I have tried setting 'encoding' => 'ISO-8859-1' when constructing my SoapClient in PHP and I get the same error. The call is made but the server responds with the deserialization error.
Does anyone know a better way for me to treat this encrypted string that will please both my PHP client and their .Net webservice?
Maybe the problem is on their end?
FWIW, I can also request that we change the encryption method to "Rijndael AES Block Cypher" per their documentation. Not sure if that would result in an easier to handle string.
You probably need to encode the data in a base 64 encoded CDATA segment inside the opening and closing tags. You might want to ask the creater of the service for a sample, or - if it is a webservice - try to download the definition or even create a client through discovery. Note that the last link was found using Google search, I've been out of PHP for a while.
[EDIT] changing the cipher won't help for this, although anything is better than ECB encoding XML
I need to validate a signature for a callback from ankoder.com who provide the following description:
It is the URL-escaped string of Base64-encoded HMAC-SHA1 digest of your private key and the URL-unescaped message.
$passkey = urlencode(base64_encode(hash_hmac('sha1', urldecode($str), $private_key, true)));
They provide the following Ruby example
encoded_signature = CGI.escape Base64.encode64(HMAC::SHA1::digest(private_key, CGI.unescape(message))).strip
I run this on sample data I have returned from a callback but am not getting the same signature. How do I replicate the Ruby code in PHP?
Edit
The issue was trailing whitespace being sent through.
Your PHP code matches the Ruby code. The problem must be somewhere else.
Check if the key is correct and the message is parsed correctly (urldecode, then json_decode).
I have an HTML form POSTing to a PHP page.
I can read in the data using the $_POST variable on the PHP.
However, all the data seems to be escaped.
So, for example
a comma (,) = %2C
a colon (:) = %3a
a slash (/) = %2
so things like a simple URL of such as http://example.com get POSTed as http%3A%2F%2Fexample.com
Any ideas as to what is happening?
Actually you want urldecode. %xx is an URL encoding, not a html encoding. The real question is why are you getting these codes. PHP usually decodes the URL for you as it parses the request into the $_GET and $_REQUEST variables. POSTed forms should not be urlencoded. Can you show us some of the code generating the form? Maybe your form is being encoded on the way out for some reason.
See the warning on this page: http://us2.php.net/manual/en/function.urldecode.php
Here is a simple PHP loop to decode all POST vars
foreach($_POST as $key=>$value) {
$_POST[$key] = urldecode($value);
}
You can then access them as per normal, but properly decoded. I, however, would use a different array to store them, as I don't like to pollute the super globals (I believe they should always have the exact data in them as by PHP).
This shouldn't be happening, and though you can fix it by manually urldecode()ing, you will probably be hiding a basic bug elsewhere that might come round to bite you later.
Although when you POST a form using the default content-type ‘application/x-www-form-encoded’, the values inside it are URL-encoded (%xx), PHP undoes that for you when it makes values available in the $_POST[] array.
If you are still getting unwanted %xx sequences afterwards, there must be another layer of manual URL-encoding going on that shouldn't be there. You need to find where that is. If it's a hidden field, maybe the page that generates it is accidentally encoding it using urlencode() instead of htmlspecialchars(), or something? Putting some example code online might help us find out.