I have to submit an array via cURL in PHP, and one of the item in the array must be a signature generated with MD5 on a concatenation of array items and a public key:
// public key
$key = '4d7894219f3d28a6fbb8c415779dfffc';
// payload; each item was initialized
$vars = array(
'id'=>$id,
'name'=>$name,
'phone'=>$phone,
'email'=>$email,
'subject'=>$subject,
'notes'=>$notes,
'time'=>date('Y-m-d H:m:s'),
);
// Now create a HTTP query with the items of the array
$caesar = '';
foreach ($vars as $key2 => $value) {
$caesar = $caesar . $key2 . '=' . $value . '&';
}
unset($key2);
unset($value);
$caesar = substr($caesar, 0, -1);
// Concatenate the string from step 2 and $key (string then $key)
$caesar = $caesar . $key;
//MD5
$signature = md5($caesar);
Later I add the sig to the array and use cURL to transfer the array. But the server keeps returning "invalid signature". I don't see what is wrong. Please help me to identify the problem. Thanks.
Related
I have a multi-dimensional array with key value pairs. Some of the values of the keys are arrays, and some of the values in that array are arrays as well. It is only 3 branches deep (for now), but I am trying to recursively loop through the array, save the key for each level of the branch, and create a new array when it reaches a string that also mimics the structure of the original array. When it reaches a string, there should be a new object instantiation for each value.
The code below sort of does this, but only creates a flat array.
foreach ($data as $key => $value) {
if (!is_array($value)) {
$a_objects[$key] = new Component([$key], $value);
} else {
foreach ($value as $valueKey => $valueValue) {
if (!is_array($valueValue)) {
$a_objects[$key . "_" . $valueKey] = new Component([$key, $valueKey], $valueValue);
} else {
foreach ($valueValue as $k => $v) {
$a_objects[$key . "_" . $valueKey . "_" . $k] = new Component([$key, $valueKey, $k], $v);
}
}
}
}
Here is my own best attempt at this but it does not seem to save into the b_objects after some testing it does not seem to be saving the object instances.
$b_objects = [];
function create_r($data, $id)
{
foreach ($data as $key => $value) {
if (is_array($value) == true) {
array_push($id, $key);
create_r($value, $id);
} else {
array_push($id, $key);
$b_objects[$key] = new Component($id, $value);
$id = [];
}
}
}
$id = [];
create_r($data, $id);
echo "this is b_objects";
echo "<pre>";
print_r($b_objects);
echo "</pre>";
I verified that $id array contains the right "keys". I feel like this solution is pretty close but I have no idea how to use my $id array to mimic the structure of the $data.
I want to be able to say $b_objects[$level1key][$level2key][$level3key]...[$leveln-1key] = new Component...
Thanks!
I suggest you pass $b_objects by reference to your create_r() function. Otherwise each function call will instantiate a new $b_objects variable which is not used anywhere in the code afterwards.
Passing by reference allows the function to actually change the input array. Notice the & sign in the function declaration.
function create_r($data, $id, &$res)
{
foreach ($data as $key => $value) {
if (is_array($value) == true) {
array_push($id, $key);
create_r($value, $id, $res);
} else {
array_push($id, $key);
$res[$key] = new Component($id, $value);
$id = [];
}
}
}
$id = [];
$b_objects = [];
create_r($data, $id, $b_objects);
I'm trying to make a payment plugin for my webshop for Ogone ideal payments. I can make a payment, but when I return I cannot get the SHA-signs to match.
I have the following get request on return:
orderID=476&amount=90%2E82&PM=iDEAL&ACCEPTANCE=0000000000&STATUS=9&PAYID=43934127&NCERROR=0&BRAND=iDEAL&SHASIGN=5AB0A065BAA83C5D807249A66E661ACBB6709B8F
According to the documentation, I have to order the keys alphabetically and only hash those that are allowed.
These are the allowed keys:
['AAVADDRESS', 'AAVCHECK', 'AAVZIP', 'ACCEPTANCE', 'ALIAS', 'AMOUNT', 'BRAND', 'CARDNO', 'CCCTY', 'CN', 'COMPLUS', 'CURRENCY', 'CVCCHECK', 'DCC_COMMPERCENTAGE', 'DCC_CONVAMOUNT', 'DCC_CONVCCY', 'DCC_EXCHRATE', 'DCC_EXCHRATESOURCE', 'DCC_EXCHRATETS', 'DCC_INDICATOR', 'DCC_MARGINPERCENTAGE', 'DCC_VALIDHOUS', 'DIGESTCARDNO', 'ECI', 'ED', 'ENCCARDNO', 'IP', 'IPCTY', 'NBREMAILUSAGE', 'NBRIPUSAGE', 'NBRIPUSAGE_ALLTX', 'NBRUSAGE', 'NCERROR', 'ORDERID', 'PAYID', 'PM', 'SCO_CATEGORY', 'SCORING', 'STATUS', 'TRXDATE', 'VC'];
I made this method to make the hash:
/**
* #return string
*/
protected function getShaOutSign()
{
$hash = '';
$values = \Input::all();
$values = array_change_key_case($values, CASE_UPPER);
ksort($values);
foreach ($values as $key => $value) {
if (in_array($key, $this->shaOut)) {
if(!empty($value))
{
$hash .= $key . '=' . $values[$key] . $this->settings->shaout;
}
}
}
return strtoupper(sha1($hash));
}
I'm 100% sure the SHA out key is correct.
The string it makes before I do SHA1:
ACCEPTANCE=0000000000abcDEFghj1234560987654AMOUNT=90.82abcDEFghj1234560987654BRAND=iDEALabcDEFghj1234560987654ORDERID=476abcDEFghj1234560987654PAYID=43934127abcDEFghj1234560987654PM=iDEALabcDEFghj1234560987654STATUS=9abcDEFghj1234560987654
And the final hash I get is:
68E459CB933E04B582A5D564CE6F591D5819B7F1
No matter what I try, I just can't get it to match it with the one in the $_GET request.
My sha-out key: abcDEFghj1234560987654
What can I try next?
The problem is clearly that part:
if(!empty($value))
{
$hash .= $key . '=' . $values[$key] . $this->settings->shaout;
}
Your request contains '...&NCERROR=0...'.
So the value is 0. And 0 is empty.
I had the same problem. But I used array_filter() function:
$parameters = array_filter($parameters);
Also array_filter() removed my 'empty' ncerror field.
The sha out calculation is wrong. This is the code I use in my projects to calculate it, $sha_parms is the full response of Ogone. So $_POST or $_GET
/**
* Function to calculate the sha that is received from Ogone
*/
public function getShaOut($sha_parms, $sha_out = null) {
$sha_out = $sha_out ?: self::PASS_PHRASE_OUT;
$sha_parms = $this->ogoneSort($sha_parms);
$sha_string = '';
foreach ($sha_parms as $key => $value) {
if ($key != 'SHASIGN' && $value != '') {
$sha_string .= $key . '=' . $value . $sha_out;
}
}
//return($sha_string);
return strtoupper(sha1($sha_string));
}
/**
*
*
**/
private function ogoneSort($array) {
$arrayToSort = array();
$origArray = array();
foreach ($array as $key => $value) {
$arrayToSort[strtolower($key)] = $value;
//stores the original value in an array
$origArray[strtolower($key)] = $key;
}
ksort($arrayToSort);
$sortedArray = array();
foreach($arrayToSort as $key => $value) {
//switch the lowercase keys back to their originals
$key = strtoupper($origArray[$key]);
$sortedArray[$key] = $value;
}
return $sortedArray;
}
$array['a:b']['c:d'] = 'test';
$array['a:b']['e:f']= 'abc';
I need output like below. array can have multiple level . Its comes with api so we do not know where colon come.
$array['ab']['cd'] = 'test';
$array['ab']['ef']= 'abc';
(untested code) but the idea should be correct if want to remove ':' from keys:
function clean_keys(&$array)
{
// it's bad to modify the array being iterated on, so we do this in 2 steps:
// find the affected keys first
// then move then in a second loop
$to_move = array();
forach($array as $key => $value) {
if (strpos($key, ':') >= 0) {
$target_key = str_replace(':','', $key);
if (array_key_exists($target_key, $array)) {
throw new Exception('Key conflict detected: ' . $key . ' -> ' . $target_key);
}
array_push($to_move, array(
"old_key" => $key,
"new_key" => $target_key
));
}
// recursive descent
if (is_array($value)) {
clean_keys($array[$key]);
}
}
foreach($to_move as $map) {
$array[$map["new_key"]] = $array[$map["old_key"]];
unset($array[$map["old_key"]]);
}
}
try this:
$array=array();
$array[str_replace(':','','a:b')][str_replace(':','','c:d')]="test";
print_r($array);
This seems like the simplest and most performant approach:
foreach ($array as $key => $val) {
$newArray[str_replace($search, $replace, $key)] = $val;
}
I have a huge array from a json_decode result (assoc set to true) and have the following code to check if (one of the arrays within, a random serial) has the key 'set_true'
$out = "";
foreach ($array as $sub) {
//$out[] = $sub['set_true'];
if (in_array($sub['set_true'], $sub) && $sub['set_true'] == '1' ) {
$out[] = 'User: ' . $sub . ' has set_true = 1';
}
}
That code lists all the users with that array key set to 1, but $sub returns 'array' and not the current key I'm on! (the random serial)
How do I return it?
If you are looping through an array with foreach, and want to know the key you're currently on in the loop, you can use this syntax :
foreach ($array as $key => $value) {
// $key contains the name of the current key
// and $value the current value
}
What's up with your in_array call? I don't think that is correct. Why do you look for $sub in $sub?
I think you mean:
$out = "";
foreach ($array as $key => $sub) {
if (array_key_exists('set_true', $sub) && $sub['set_true'] == '1' ) {
$out[] = 'User: ' . $key . ' has set_true = 1';
}
}
I'm looking for the name of the PHP function to build a query string from an array of key value pairs. Please note, I am looking for the built in PHP function to do this, not a homebrew one (that's all a google search seems to return). There is one, I just can't remember its name or find it on php.net. IIRC its name isn't that intuitive.
You're looking for http_build_query().
Here's a simple php4-friendly implementation:
/**
* Builds an http query string.
* #param array $query // of key value pairs to be used in the query
* #return string // http query string.
**/
function build_http_query( $query ){
$query_array = array();
foreach( $query as $key => $key_value ){
$query_array[] = urlencode( $key ) . '=' . urlencode( $key_value );
}
return implode( '&', $query_array );
}
Just as addition to #thatjuan's answer.
More compatible PHP4 version of this:
if (!function_exists('http_build_query')) {
if (!defined('PHP_QUERY_RFC1738')) {
define('PHP_QUERY_RFC1738', 1);
}
if (!defined('PHP_QUERY_RFC3986')) {
define('PHP_QUERY_RFC3986', 2);
}
function http_build_query($query_data, $numeric_prefix = '', $arg_separator = '&', $enc_type = PHP_QUERY_RFC1738)
{
$data = array();
foreach ($query_data as $key => $value) {
if (is_numeric($key)) {
$key = $numeric_prefix . $key;
}
if (is_scalar($value)) {
$k = $enc_type == PHP_QUERY_RFC3986 ? urlencode($key) : rawurlencode($key);
$v = $enc_type == PHP_QUERY_RFC3986 ? urlencode($value) : rawurlencode($value);
$data[] = "$k=$v";
} else {
foreach ($value as $sub_k => $val) {
$k = "$key[$sub_k]";
$k = $enc_type == PHP_QUERY_RFC3986 ? urlencode($k) : rawurlencode($k);
$v = $enc_type == PHP_QUERY_RFC3986 ? urlencode($val) : rawurlencode($val);
$data[] = "$k=$v";
}
}
}
return implode($arg_separator, $data);
}
}
Implode will combine an array into a string for you, but to make an SQL query out a kay/value pair you'll have to write your own function.