skip to Main Content

I have an XML webservice URL that I do cURL requests to it.

My cURL request works fine but sometimes it is sent twice resulting in the user being charged twice.

So basically I have a form with an amount and the user clicks on submit to validate the payment. The form code is below.

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="content-type" content="text/html; charset=utf-8">
        <meta content="IE=edge" http-equiv="X-UA-Compatible">
        <meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
        <title>Payment Page</title>
        <link rel="stylesheet" href="css/spin.css">
        <script src="js/jquery-3.3.1.min.js"></script>
        <script>
            $(document).ready(function () {
                $('#submit_btn_echeck').click(function () {
                    $('#cover-spin').show();
                    setTimeout(function () {
                        $('#cover-spin').hide();
                    }, 6000);
                });
            });
        </script>
    </head>
    <body id="main_body" class="no_guidelines">
        <div id="form_container" class="StandShadow SLarge">
            <form action="pay_echeck/retained" method="post">
                <input type="hidden" name="csrf_token_name" value="8825288f44db225ff01b86d3ec8c166c" />
                <input type="hidden" name="amount_to_pay" value="119.62" />
                <div class="form_description">
                    <h2>Payment Information</h2>
                    <p>Please review the details below before submitting your payment.</p>
                </div>
                <ul class="payment_summary">
                    <li class="payment_summary_amount">
                        <table>
                            <tr>
                                <td style="float:right;border-bottom:1px dashed #ccc;">Charge Amount:&nbsp;</td>
                                <td style="border-left:1px dashed #ccc;border-bottom:1px dashed #ccc;"><span style="float:right;">&#36;119.62</span></td>
                            </tr>
                                                        <tr>
                                <td style="float:right;"><b>TOTAL:&nbsp;</b></td>
                                <td style="border-left:1px dashed #ccc;"><span style="float:right;"><b id="totalCC">&nbsp;&#36;119.62</b></span></td>
                            </tr>
                        </table>                                                        
                    </li>   

                </ul>
                <input id="submit_btn_echeck" class="button_text btn_primary" type="submit" value="Submit" />
                <div id="cover-spin"></div>
            </form>
        </div>
    </body>
</html>

When the user submits the form I take the value of the hidden input named amount_to_pay and send it to the web-service via PHP cURL using the code below.

ob_start();  
$out = fopen('curl_log_'.date('mdY_his').'.txt', 'w');
$ch = curl_init();
curl_setopt($ch, CURLOPT_VERBOSE, true);  
curl_setopt($ch, CURLOPT_STDERR, $out);  
curl_setopt($ch, CURLOPT_URL, "https://mywebserviceurl.com");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 60000);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);//data sent as PHP XML object
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_CAINFO, __DIR__."/cacert.pem");
curl_setopt($ch, CURLOPT_CAPATH, __DIR__."/cacert.pem");
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: text/xml;charset=UTF-8', 'SoapAction; *']);
$content = trim(curl_exec($ch));
curl_close($ch);
$debug = ob_get_clean();
fwrite($out,$debug);
fwrite($out,$content);
fclose($out);
if (isset($content)) {
    return $content;
} 

Everything works fine, some users pay with no issues but some others get charged twice and when I try to debug the curl request sent and the response received for one of those users for example I see that cURL request was sent twice. Below is a debug of the Curl request that was sent twice:

First request sent

*   Trying xx.xx.xxx.xx:443...
* TCP_NODELAY set
* Connected to webservice.com (xx.xx.xx.xx) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: .../application/libraries/cacert.pem
  CApath: .../application/libraries/cacert.pem
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: OU=Domain Control Validated; CN=*.webservice.com
*  start date: Sep 13 15:44:59 2019 GMT
*  expire date: Sep 13 15:44:59 2020 GMT
*  subjectAltName: host "webservice.com" matched cert's "webservice.com"
*  issuer: C=BE; O=GlobalSign nv-sa; CN=AlphaSSL CA - SHA256 - G2
*  SSL certificate verify ok.
> POST /ws/webservice_svc.cfc?wsdl HTTP/1.1
Host: webservice.com
Accept: */*
Content-Type: text/xml;charset=UTF-8
SoapAction: *
Content-Length: 939

* upload completely sent off: 939 out of 939 bytes
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Sun, 06 Oct 2019 22:59:33 GMT
< Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips mod_fcgid/2.3.9 PHP/5.4.16 mod_jk/1.2.41
< Strict-Transport-Security: max-age=15768000
< Set-Cookie: CFID=2685691; Expires=Mon, 07-Oct-2019 **08:59:33 GMT**; Path=/; Secure; HttpOnly
< Set-Cookie: CFTOKEN=d3c5d1e31b91dd7d-60FEB753-CF6E-1A16-AB0F8681EB1809A6; Expires=Mon, 07-Oct-2019 08:59:33 GMT; Path=/; Secure; HttpOnly
< X-XSS-Protection: 1; mode=block
< X-Content-Type-Options: nosniff
< X-Frame-Options: ALLOW-FROM https://foundationtitlemelbourne.com/
< Referrer-Policy: same-origin
< Transfer-Encoding: chunked
< Content-Type: text/xml;charset=utf-8
< 
* Connection #0 to host webservice.com left intact
<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <soapenv:Body>
  <ns1:PayRPOResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://ws">
   <PayRPOReturn xsi:type="xsd:string">&lt;result&gt;Successful, 3990631&lt;/result&gt;</PayRPOReturn>
  </ns1:PayRPOResponse>
 </soapenv:Body>
</soapenv:Envelope>

Second same request sent, the only difference I see is that it was sent 8 seconds after the first one above

*   Trying xx.xx.xxx.xx:443...
* TCP_NODELAY set
* Connected to webservice.com (xx.xx.xx.xx) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: .../application/libraries/cacert.pem
  CApath: .../application/libraries/cacert.pem
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: OU=Domain Control Validated; CN=*.webservice.com
*  start date: Sep 13 15:44:59 2019 GMT
*  expire date: Sep 13 15:44:59 2020 GMT
*  subjectAltName: host "webservice.com" matched cert's "webservice.com"
*  issuer: C=BE; O=GlobalSign nv-sa; CN=AlphaSSL CA - SHA256 - G2
*  SSL certificate verify ok.
> POST /ws/webservice_svc.cfc?wsdl HTTP/1.1
Host: webservice.com
Accept: */*
Content-Type: text/xml;charset=UTF-8
SoapAction: *
Content-Length: 939

* upload completely sent off: 939 out of 939 bytes
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Sun, 06 Oct 2019 22:59:33 GMT
< Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips mod_fcgid/2.3.9 PHP/5.4.16 mod_jk/1.2.41
< Strict-Transport-Security: max-age=15768000
< Set-Cookie: CFID=2685691; Expires=Mon, 07-Oct-2019 **08:59:41 GMT**; Path=/; Secure; HttpOnly
< Set-Cookie: CFTOKEN=d3c5d1e31b91dd7d-60FEB753-CF6E-1A16-AB0F8681EB1809A6; Expires=Mon, 07-Oct-2019 08:59:33 GMT; Path=/; Secure; HttpOnly
< X-XSS-Protection: 1; mode=block
< X-Content-Type-Options: nosniff
< X-Frame-Options: ALLOW-FROM https://foundationtitlemelbourne.com/
< Referrer-Policy: same-origin
< Transfer-Encoding: chunked
< Content-Type: text/xml;charset=utf-8
< 
* Connection #0 to host webservice.com left intact
<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <soapenv:Body>
  <ns1:PayRPOResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://ws">
   <PayRPOReturn xsi:type="xsd:string">&lt;result&gt;Successful, 3990631&lt;/result&gt;</PayRPOReturn>
  </ns1:PayRPOResponse>
 </soapenv:Body>
</soapenv:Envelope>

Any lead or help please on what could be happening would be very appreciated.

Thanks.

2

Answers


  1. Sometimes the payment gateway can respond twice for one payment request.

    It is normal to happen, because the server which sends the response can be down for a period of time.
    In this case the payment system tries to send the respond once, or multiple times.

    It is your duty as a developer to treat this exception.

    You can do it based on the id of the transaction send/retunred from the payment system.

    Login or Signup to reply.
  2. I think the problem lies here:

                    $('#cover-spin').show();
                    setTimeout(function () {
                        $('#cover-spin').hide();
                    }, 6000);
    

    You are showing the submit button again after 6 seconds, so the user is likely to click it again, because it would seem as if the payment did not work the first time.

    I would keep the #cover_spin visible, and let it disappear when the page navigates to the success or failure page.

    I’d also disable the submit button after it is clicked for extra measure.

    $('#submit_btn_echeck').prop('disabled', true);

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search