Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue in gateways with METHOD_HTML_FORM redirection method, if multidimensional is passed. #73

Closed
knit-pay opened this issue Sep 24, 2022 · 4 comments · Fixed by #76
Closed
Assignees

Comments

@knit-pay
Copy link
Contributor

The below code fails if we pass a multidimensional array to html_hidden_fields function.

wp-pay-core/src/Util.php

Lines 211 to 213 in ecb3e11

foreach ( $data as $name => $value ) {
$html .= sprintf( '<input type="hidden" name="%s" value="%s" />', esc_attr( $name ), esc_attr( $value ) );
}

In Some payment gateways, data is passed as multidimensional array. See example below
https://razorpay.com/docs/payments/payment-gateway/web-integration/hosted/build-integration/#code-to-add-pay-button

Here field prefill[name] is creating an issue.

Before running the loop, if we will call below function, issue will be fixed.

$data = self::flatten_array($data);
	public static function flatten_array($array, $prefix = '', $parent = true) {
	    $result = array();
	    foreach($array as $key=>$value) {
	        if(is_array($value)) {
	            if($parent){
	                $result = $result + self::flatten_array($value, "{$key}", false);
	            }else {
	                $result = $result + self::flatten_array($value, "{$prefix}[{$key}]", false);
	            }
	        } else if ($parent){
	            $result["{$prefix}{$key}"] = $value;
	        }
	        else {
	            $result["{$prefix}[{$key}]"] = $value;
	        }
	    }
	    return $result;
	}

Do you have any better suggestion for the same?

@remcotolsma
Copy link
Member

remcotolsma commented Sep 27, 2022

You want to pass in a an array like:

return [
	'key_id'       => 'YOUR_KEY_ID',
	'amount'       => '1001',
	'order_id'     => 'razorpay_order_id',
	'name'         => 'Acme Corp',
	'description'  => 'A Wild Sheep Chase',
	'image'        => 'https://cdn.razorpay.com/logos/BUVwvgaqVByGp2_large.jpg',
	'prefill' => [
		'name'    => 'Gaurav Kumar',
		'contact' => '9123456780',
		'email'   => '[email protected]',
	],
	'notes'   => [
		'shipping address' => 'L-16, The Business Centre, 61 Wellfield Road, New Delhi - 110001',
	],
	'callback_url' => 'https://example.com/payment-callback',
	'cancel_url'   => 'https://example.com/payment-cancel',
];

You can just build a flat array?

return [
	'key_id'                  => 'YOUR_KEY_ID',
	'amount'                  => '1001',
	'order_id'                => 'razorpay_order_id',
	'name'                    => 'Acme Corp',
	'description'             => 'A Wild Sheep Chase',
	'image'                   => 'https://cdn.razorpay.com/logos/BUVwvgaqVByGp2_large.jpg',
	'prefill[name]'           => 'Gaurav Kumar',
	'prefill[contact]'        => '9123456780',
	'prefill[email]'          => '[email protected]',
	'notes[shipping address]' => 'L-16, The Business Centre, 61 Wellfield Road, New Delhi - 110001',
	'callback_url'            => 'https://example.com/payment-callback',
	'cancel_url'              => 'https://example.com/payment-cancel',
];

We could implement support for multidimensional arrays, we don't really need this ourselves, so maybe this should remain gateway territory?

https://www.php.net/manual/en/function.http-build-query.php


Solution with RecursiveIteratorIterator?
<?php

$data = [
	'key_id'       => 'YOUR_KEY_ID',
	'amount'       => '1001',
	'order_id'     => 'razorpay_order_id',
	'name'         => 'Acme Corp',
	'description'  => 'A Wild Sheep Chase',
	'image'        => 'https://cdn.razorpay.com/logos/BUVwvgaqVByGp2_large.jpg',
	'prefill' => [
		'name'    => 'Gaurav Kumar',
		'contact' => '9123456780',
		'email'   => '[email protected]',
	],
	'notes'   => [
		'shipping address' => 'L-16, The Business Centre, 61 Wellfield Road, New Delhi - 110001',
	],
	'callback_url' => 'https://example.com/payment-callback',
	'cancel_url'   => 'https://example.com/payment-cancel',
	1 => 'test',
];

$iterator = new class( new RecursiveArrayIterator( $data ) ) extends RecursiveIteratorIterator {
	function key() {
		$key = $this->getSubIterator( 0 )->key();

		for ( $i = 1; $i <= $this->getDepth(); $i++ ) {
			$key .= '[' . $this->getSubIterator( $i )->key() . ']';
		}

		return $key;
	}
};

foreach ( $iterator as $key => $item ) {
    var_dump( $key );
    var_dump( $item );
    echo PHP_EOL;
}

@knit-pay
Copy link
Contributor Author

You want to pass in a an array like:

Yes, I need to pass an array like the first one in post form.

You can just build a flat array?

Yes, need to pass a flat array like the one you provided. The first array is getting used for another purpose also. So, developing a second array directly is not possible. Either I will have to convert the normal array to a flat array within the get_output_fields function before returning. Using a function similar to the function given below or I will have to recreate the complete array. For the time being, I have already handled it within my gateway code to convert it within the get_output_fields function. It's just a suggestion that we can handle it within the wp-pay-core code itself as other gateways might also need similar functionality.

	public static function flatten_array($array, $prefix = '', $parent = true) {
	    $result = array();
	    foreach($array as $key=>$value) {
	        if(is_array($value)) {
	            if($parent){
	                $result = $result + self::flatten_array($value, "{$key}", false);
	            }else {
	                $result = $result + self::flatten_array($value, "{$prefix}[{$key}]", false);
	            }
	        } else if ($parent){
	            $result["{$prefix}{$key}"] = $value;
	        }
	        else {
	            $result["{$prefix}[{$key}]"] = $value;
	        }
	    }
	    return $result;
	}

https://www.php.net/manual/en/function.http-build-query.php

Yes, this function is good for creating query strings. add_query_arg or http_build_query can be used for sending parameters in GET requests. But I think we can't use it for POST form submission. Correct me if I am wrong.

Solution with RecursiveIteratorIterator?

Thanks for the suggestion, I will try to use this also.

What do you think, I should handle this within gateway or you can include it in wp-pay-core also?

@remcotolsma
Copy link
Member

remcotolsma commented Sep 27, 2022

What do you think, I should handle this within gateway or you can include it in wp-pay-core also?

I think we could include this in the core library, it might be useful if this works like for example like the body argument in the wp_remote_post function. I think the WordPress HTTP library is using the http_build_query function for this. I will discuss this internally with @rvdsteege and double check if a RecursiveIteratorIterator solution is handy.

function flat( $data, $parent = '', $result = [] ) {
    foreach ( $data as $key => $item ) {
        if ( '' !== $parent ) {
            $key = $parent . '[' . $key . ']';
        }

        if ( is_array( $item ) ) {
            $result = flat( $item, $key, $result );
        } else {
            $result[ $key ] = $item;
        }
    }
    
    return $result;
}

var_dump( flat( $data ) );

@remcotolsma remcotolsma assigned remcotolsma and rvdsteege and unassigned knit-pay Sep 27, 2022
@remcotolsma remcotolsma moved this to In Progress in Pronamic Pay Sep 27, 2022
@remcotolsma
Copy link
Member

remcotolsma commented Sep 28, 2022

Naming helper function, perhaps like array_dot:

private static function array_square_bracket( $data, $parent = '', $result = [] ) {
    foreach ( $data as $key => $item ) {
        if ( '' !== $parent ) {
            $key = $parent . '[' . $key . ']';
        }

        if ( is_array( $item ) ) {
            $result = self::array_square_bracket( $item, $key, $result );
        } else {
            $result[ $key ] = $item;
        }
    }
    
    return $result;
}

rvdsteege added a commit that referenced this issue Sep 29, 2022
…)` method (#76).

* Add support for multi-dimensional array in `Util::html_hidden_fields( $data )` method.

#73

Co-authored-by: Reüel van der Steege <[email protected]>
Repository owner moved this from In Progress to Done in Pronamic Pay Sep 29, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

3 participants