Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 14 of 14
  1. #1
    Senior Coder timgolding's Avatar
    Join Date
    Aug 2006
    Location
    Southampton
    Posts
    1,519
    Thanks
    114
    Thanked 110 Times in 109 Posts

    php alternative to hidden post form

    I have a hidden form that is posting some data to our payments provider. This is a hidden html form that is meant to be automatically submitted with javascript within the onload event.

    Code:
    <body onLoad="document.forms[0].submit()">
    We had a problem where the user was been redirected more than once. Whilst this doesnt usually happen. it did happen three times in a day. I wondered if there was cross browser compatibility issue with this js code? I have tested as many browsers as i have access to and all seem to redirect fine so far.

    I wonder can POST data be submitted with a php header redirect. I am reading it cant. I did find this article . But don't like using other peoples code unless i can understand what its doing i don't see how using fopen can help surely any file operation is internal to the server. Don't see how fopen will redirect the user to the payment provider?
    You can not say you know how to do something, until you can teach it to someone else.

  • #2
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,987
    Thanks
    4
    Thanked 2,660 Times in 2,629 Posts
    Post data can never be passed by a redirect, as that implies the method is GET. The code you posted simply establishes a connection to the host, and provides the data manually as specified with the http stream wrappers. It's a bit less complicated than doing it manually since the stream wrappers know how to interpret the http. On a local server you can of course use sessions instead.
    fopen will work so long as the ini configuration for allow_url_fopen is enabled. Otherwise, you could use curl or sockets instead where socket connections are the most reliable.
    PHP Code:
    header('HTTP/1.1 420 Enhance Your Calm'); 

  • #3
    Senior Coder timgolding's Avatar
    Join Date
    Aug 2006
    Location
    Southampton
    Posts
    1,519
    Thanks
    114
    Thanked 110 Times in 109 Posts
    ooo sockets that sounds hard? Have you got any examples of this i dont really want to enable allow_url_fopen if i dont have to. I wonder if a jquery solution would be more browser compatible

    Code:
    function submit_Form(){
    		var form = $("#Form");
    		form.attr('method', 'post');
    		form.submit();
    	}
    Code:
    <body onLoad="submit_Form();">
    if not how do i go about learning sockets programming
    You can not say you know how to do something, until you can teach it to someone else.

  • #4
    Regular Coder
    Join Date
    Sep 2002
    Posts
    456
    Thanks
    0
    Thanked 20 Times in 20 Posts
    It may not be you at all. If you run ads from other other websites they could be using redirects...it happens! The question is, where are they being redirected to? Is it your payment providers website or somewhere else?
    NO Limits!! DHCreationStation.com
    ------------------------------------------------------------
    Broken items wanted for tinkerin'! PostItNow@BrokenEquipment.com
    Global Complaint Dept.

  • #5
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,987
    Thanks
    4
    Thanked 2,660 Times in 2,629 Posts
    jquery would be *less* compatible than a PHP solution.
    Sockets are as simple as:
    PHP Code:
    $domain "www.site.com";
    $script "processing.php";
    $port 80;
    $timeout 5;

    $postData http_build_query($_POST);

    if (
    false !== ($fp fsockopen($domain$port$errno$error$timeout)))
    {
        
    fwrite($fp"POST $script HTTP/1.1\r\n");
        
    fwrite($fp"Host: $domain\r\n");
        
    fwrite($fp"Content-Type: application/x-www-form-urlencoded\r\n");
        
    fwrite($fp"Content-Length: " strlen($postData) . "\r\n");
        
    fwrite($fp"Connection: Close\r\n");
        
    fwrite($fp"\r\n");

        
    $reply "";
        while (!
    feof($fp))
        {
            
    $reply .= fread($fp1024);
        }
        
    fclose($fp);
    }
    else
    {
        
    printf("Failed to connect to host: %d - %s"$errno$error);

    $reply now contains the result http request. You can split the header off from the body by detecting \r\n\r\n.
    PHP Code:
    header('HTTP/1.1 420 Enhance Your Calm'); 

  • Users who have thanked Fou-Lu for this post:

    timgolding (01-31-2014)

  • #6
    Senior Coder
    Join Date
    Sep 2010
    Posts
    1,997
    Thanks
    15
    Thanked 234 Times in 234 Posts
    You might want to use a cookie to remember if the form has already been submitted. For php a cookie has to be made at the start of the page, javascript can make it anytime. It can only be read on a new page or page reload. And php has a much easier job of reading a cookie, since it just treats it as an array..
    Welcome to http://www.myphotowizard.net

    where you can edit images, make a photo calendar, add text to images, and do much more.


    When you know what you're doing it's called Engineering, when you don't know, it's called Research and Development. And you can always charge more for Research and Development.

  • Users who have thanked DrDOS for this post:

    timgolding (01-31-2014)

  • #7
    Senior Coder timgolding's Avatar
    Join Date
    Aug 2006
    Location
    Southampton
    Posts
    1,519
    Thanks
    114
    Thanked 110 Times in 109 Posts
    Im a bit confused the post data has to come from the client. If i implement this sockets method wont the data get posted from the server?

    So i can use a cookie to check that the user hasn't submitted the form twice?
    You can not say you know how to do something, until you can teach it to someone else.

  • #8
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,987
    Thanks
    4
    Thanked 2,660 Times in 2,629 Posts
    No, my understanding of your problem is you are retrieving post from a form, and you are passing post to a different processing script. So yes, it is posted from the server to another server (or potentially the same), but the input is still originally from the client.

    As for a redirection problem, there are many potential causes. A cookie may be sufficient for that.
    PHP Code:
    header('HTTP/1.1 420 Enhance Your Calm'); 

  • #9
    Senior Coder timgolding's Avatar
    Join Date
    Aug 2006
    Location
    Southampton
    Posts
    1,519
    Thanks
    114
    Thanked 110 Times in 109 Posts
    I am at a loss here. I don't want the user to have to click a button unless js is disabled. I looked through my apache logs and tail grep the IP of the user. He only went to this page that jumps to the payment provider once. But the payments providers said the form was submitted twice. For this reason i am not sure if the cookies will help because surley testing the cookie will only occur when this page is refreshed well its not being it is very strange because i have tested.

    Code:
    document.forms[0].submit();
    on 40 browsers and logged UA strings, times and post data for every submission the form data was only posted to the process page once on every test. If the user was clicking back then he would have to resend the post data and i would have a double entry in my apache log.

    I have even tried to to click refresh on the first page of the payments provider so the form data is resent without going to the form. But this didn't generate an error.

    I dont see how this can be because the payment provider told me that thee errors are generated when the same oid are sumbitted. But why wouldnt refreshing this payment page generate that error?

    here is my cookie code

    Code:
    <?php
    
    session_start();
    if(isset($_POST["site_name"]) && preg_match("/^[A-Za-z0-9\.]*$/", $_POST["site_name"]))
    {
        $_SESSION["SITE_NAME"]= $_POST["site_name"];
    }
    else
    {
        $_SESSION["SITE_NAME"]="example.com";
    }
    $template="";
    $err = "";
    if(!validate_post($err, $template))
        die($err);
        
    ?>
    <html>
    <head>
     <title>Page Jump</title>
     <script>
     
     
     function setCookie(cname,cvalue,exdays)
    {
    var d = new Date();
    d.setTime(d.getTime()+(exdays*24*60*60*1000));
    var expires = "expires="+d.toGMTString();
    document.cookie = cname + "=" + cvalue + "; " + expires;
    } 
    
    function getCookie(cname)
    {
    var name = cname + "=";
    var ca = document.cookie.split(';');
    for(var i=0; i<ca.length; i++)
      {
      var c = ca[i].trim();
      if (c.indexOf(name)==0) return c.substring(name.length,c.length);
      }
    return "";
    } 
     
     	function submit_pay()
    {
    	if(getCookie('oid') != <?php echo "'".$_POST["ORDER_ID"]."'"; ?>)
    	{
    		setCookie('oid', <?php echo "'".$_POST["ORDER_ID"]."'"; ?>, 365);
    		
    		document.getElementById('pay_form').submit();
    		return false;
    	}
    	else
    		window.alert("this order id has already been used");
    	
    }
    
     </script>
    </head>
    <body onLoad="submit_pay();">
    <form method="post" id="pay_form" action="https://paymentsprovider.com">
    <?php
    require("../../config/config.php");
    
    if(DOCUMENT_ROOT=="")
        $domain = "http://www.example.com";
    else
        $domain = "http://192.168.1.99/example.com/web";
        
    echo'
    <input type="hidden" name="MERCHANT_ID" value="'.$_POST["MERCHANT_ID"].'" />
    <input type="hidden" name="ORDER_ID" value="'.$_POST["ORDER_ID"].'" />
    <input type="hidden" name="CURRENCY" value="GBP">
    <input type="hidden" name="AMOUNT" value="'.$_POST["AMOUNT"].'" />
    <input type="hidden" name="TIMESTAMP" value="'.$_POST["TIMESTAMP"].'" />
    <input type="hidden" name="MD5HASH" value="'.strip_tags($_POST["MD5HASH"]).'" />
    <input type="hidden" name="AUTO_SETTLE_FLAG" value="'.$_POST["AUTO_SETTLE_FLAG"].'">
    <input type="hidden" name="BILLING_CODE" value="'.$_POST["BILLING_CODE"].'">
    <input type="hidden" name="ACCOUNT" value="'.$template.'">';
    
        
    function validate_post(&$err, &$template)
    {
        $valid = true;
        
        if(!isset($_POST["MERCHANT_ID"]) || !in_array($_POST["MERCHANT_ID"], array("exampleltd", "exampleltdtest")))
        {
            $valid = false;
            $err .= "Merchant Id is either not present or is invalid";
        }
        
        if(!isset($_POST["ORDER_ID"]) || !is_numeric($_POST["ORDER_ID"]))
        {
            $valid = false;
            $err .= "Order Id is either not present or is invalid";
        }
        
        if(!isset($_POST["AMOUNT"]) || !is_numeric($_POST["AMOUNT"]))
        {
            $valid = false;
            $err .= "Amount is either not present or is invalid";
        }
        
        if(!isset($_POST["TIMESTAMP"]) || !is_numeric($_POST["TIMESTAMP"]))
        {
            $valid = false;
            $err .= "Timestamp is either not present or is invalid";
        }
        
        if(!isset($_POST["MD5HASH"]))
        {
            $valid = false;
            $err .= "Hash is not present.";
        }
        
        if(!isset($_POST["AUTO_SETTLE_FLAG"]) || !in_array($_POST["AUTO_SETTLE_FLAG"], array("1", "0")))
        {
            $valid = false;
            $err .= "AUTO_SETTLE_FLAG is not present or is invalid.";
        }
        
        if(!isset($_POST["BILLING_CODE"]) || !preg_match("/^[0-9]*\|[0-9]*$/", $_POST["BILLING_CODE"]))
        {
            $valid = false;
            $err .= "BILLING_CODE is not present or is invalid.";
        }
        
        if(isset($_POST["ACCOUNT"]) && in_array($_POST["ACCOUNT"], array("template1", "template2")))
        {
            //ok
            $template = $_POST["ACCOUNT"];
        }
        else
        {
            $template = "template1";
        }
        
        return $valid;
    }
    ?>
    <noscript><input type="submit" VALUE="purchase"></noscript> 
    </form>
    </body>
    </html>
    Im sure this is better but not convinced it will fix the issue
    You can not say you know how to do something, until you can teach it to someone else.

  • #10
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,987
    Thanks
    4
    Thanked 2,660 Times in 2,629 Posts
    This is all sounding like a client issue, not a server one.
    I recall reading about developer tools in browsers being responsible for multiple requests.

    When it comes to a form, you can use sessions with token consumption. That's simply a matter of:
    PHP Code:
    session_start();
    $_SESSION['token'] = sha1(uniqid()); // doesn't matter, just make it uniqueish.

    ...
    printf('<input type="hidden" name="token" value="%s"/>'$_SESSION['token']); 
    Then on your processing form, load the token from both the form and from session and verify they match before continuing. unset it once verified; the process should only happen if the session has a token and the token matches the client side.
    That should eliminate multiple calls. Its like hitting refresh on a posted page, if you accept resending the post data, it would include the token. But since you've already processed that token, you instead receive an error that indicates the token is not valid.
    PHP Code:
    header('HTTP/1.1 420 Enhance Your Calm'); 

  • #11
    Senior Coder timgolding's Avatar
    Join Date
    Aug 2006
    Location
    Southampton
    Posts
    1,519
    Thanks
    114
    Thanked 110 Times in 109 Posts
    Problem is the process page e.g the page this form is posted to is handled by the payments provider so i have no control over that.

    Or do you mean between the checkout page and the page jump?

    im starting to wonder if this is something to do with cached pages in the browser. Hence the reason i am not getting double entries in the apache logs
    Last edited by timgolding; 01-31-2014 at 04:30 PM.
    You can not say you know how to do something, until you can teach it to someone else.

  • #12
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,987
    Thanks
    4
    Thanked 2,660 Times in 2,629 Posts
    I'm confused, I thought that you were forwarding a post request from your domain to another domain and you were sending multiple requests when its to be only one? You won't see these in your apache log either since these don't go through apache. The apache will cover incoming, not outgoing.
    PHP Code:
    header('HTTP/1.1 420 Enhance Your Calm'); 

  • #13
    Senior Coder
    Join Date
    Feb 2011
    Location
    Your Monitor
    Posts
    4,329
    Thanks
    60
    Thanked 526 Times in 513 Posts
    Blog Entries
    4
    Quote Originally Posted by timgolding View Post
    Code:
    document.forms[0].submit();
    I have a hunch.

    Have you specifically named or given your form the id name of 0?

    Reason i ask is that if you've been hacked and had another hidden frame with a form inserted into your page above your own form, from the looks of your code, it may well submit a different form from the one you're expecting it to.

    I'm no expert on javascript but the [0] thing in your javascript looks like it is pointing to the 1st item in an array of forms. If you've got a hidden form in there you don't know of then it may well be meaning that instead.

    I may be miles out with this hunch but I thought it might be worth mentioning.
    See my new CodingForums Blog: http://www.codingforums.com/blogs/tangoforce/

    Many useful explanations and tips including: Cannot modify headers - already sent, The IE if (isset($_POST['submit'])) bug explained, unexpected T_CONSTANT_ENCAPSED_STRING, debugging tips and much more!

  • #14
    Senior Coder timgolding's Avatar
    Join Date
    Aug 2006
    Location
    Southampton
    Posts
    1,519
    Thanks
    114
    Thanked 110 Times in 109 Posts
    To determine if it was the Javascript that was causing this double submission i decided to turn off the javascript auto submit and provide a button for the user to press instead to forward the form. I left the javascript disabled for two weeks and the double submissions stopped. So this was enough test data to conclude that it was the javascript that was causing the double submissions.

    I did some more research around other people who had a similar problem
    Javascript submits form twice ? mozillaZine Forums This pointed to the problem being an encoding issue.

    I decided to include
    - Some cookie control to prevent the same oid being submitted to the form in the frst place. Prevents the user refreshing the from
    - Some cache control to prevent the form being cached in browser
    - Correct page encoding defined in header
    - A javascript flag to prevent a double submission

    Code:
    <?php
    
    session_start();
    // if its a valid site
    if(isset($_POST["site_name"]) && preg_match("/^[A-Za-z0-9\.]*$/", $_POST["site_name"]))
    {
    	// store the session so gets redirected correctly
        $_SESSION["SITE_NAME"]= $_POST["site_name"];
    }
    else
    {
    	// otherwise use the default parent site
        $_SESSION["SITE_NAME"]="example.com";
    }
    $template="";
    $err = "";
    // some simple validation of form data and set template if not present
    if(!validate_post($err, $template))
        die($err);
        
    ?>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <meta http-equiv="cache-control" content="no-cache" />
     <title>Page Jump</title>
     <script type="text/javascript">
     <!--
     
     
     if(typeof String.prototype.trim !== 'function') {
      String.prototype.trim = function() {
        return this.replace(/^\s+|\s+$/g, ''); 
      }
    }
    
     function setCookie(cname,cvalue,exdays)
    {
    var d = new Date();
    d.setTime(d.getTime()+(exdays*24*60*60*1000));
    var expires = "expires="+d.toGMTString();
    document.cookie = cname + "=" + cvalue + "; " + expires;
    } 
    
    function getCookie(cname)
    {
    var name = cname + "=";
    var ca = document.cookie.split(';');
    for(var i=0; i<ca.length; i++)
      {
      var c = ca[i].trim();
      if (c.indexOf(name)==0) return c.substring(name.length,c.length);
      }
    return "";
    } 
     
     function submit_form()
    {
    	// if order id in users cookies dont submt the form othewise set the cookie and submit the form
    	if(getCookie('oid') != <?php echo "'".$_POST["ORDER_ID"]."'"; ?>)
    	{
    		setCookie('oid', <?php echo "'".$_POST["ORDER_ID"]."'"; ?>, 365);
    		
    		if(!submitted)
    		{
    			document.getElementById('my_form').submit();
    		}
    	}
    	else
    		window.alert("this order id has already been used");
    	
    }
    
    var submitted = false;
    document.getElementById('my_form').onSubmit() = function(){
    		submitted = true;
    }
    //-->
     </script>
    </head>
    <body>
    <form method="post" id="my_form" onLoad="submit_form();" action="https://payments.com/payments.page.htm">
    <?php
    
        
    echo'
    <input type="hidden" name="MERCHANT_ID" value="'.$_POST["MERCHANT_ID"].'" />
    <input type="hidden" name="ORDER_ID" value="'.$_POST["ORDER_ID"].'" />
    <input type="hidden" name="CURRENCY" value="GBP">
    <input type="hidden" name="AMOUNT" value="'.$_POST["AMOUNT"].'" />
    <input type="hidden" name="TIMESTAMP" value="'.$_POST["TIMESTAMP"].'" />
    <input type="hidden" name="MD5HASH" value="'.htmlentities(strip_tags($_POST["MD5HASH"])).'" />
    <input type="hidden" name="AUTO_SETTLE_FLAG" value="'.$_POST["AUTO_SETTLE_FLAG"].'" />
    <input type="hidden" name="BILLING_CODE" value="'.$_POST["BILLING_CODE"].'" />
    <input type="hidden" name="ACCOUNT" value="'.$template.'" />';
    
        
    function validate_post(&$err, &$template)
    {
        $valid = true;
        
        if(!isset($_POST["MERCHANT_ID"]) || !in_array($_POST["MERCHANT_ID"], array("example", "exampletest")))
        {
            $valid = false;
            $err .= "Merchant Id is either not present or is invalid";
        }
        
        if(!isset($_POST["ORDER_ID"]) || !is_numeric($_POST["ORDER_ID"]))
        {
            $valid = false;
            $err .= "Order Id is either not present or is invalid";
        }
        
        if(!isset($_POST["AMOUNT"]) || !is_numeric($_POST["AMOUNT"]))
        {
            $valid = false;
            $err .= "Amount is either not present or is invalid";
        }
        
        if(!isset($_POST["TIMESTAMP"]) || !is_numeric($_POST["TIMESTAMP"]))
        {
            $valid = false;
            $err .= "Timestamp is either not present or is invalid";
        }
        
        if(!isset($_POST["MD5HASH"]))
        {
            $valid = false;
            $err .= "Hash is not present.";
        }
        
        if(!isset($_POST["AUTO_SETTLE_FLAG"]) || !in_array($_POST["AUTO_SETTLE_FLAG"], array("1", "0")))
        {
            $valid = false;
            $err .= "AUTO_SETTLE_FLAG is not present or is invalid.";
        }
        
        if(!isset($_POST["BILLING_CODE"]) || !preg_match("/^[0-9]*\|[0-9]*$/", $_POST["BILLING_CODE"]))
        {
            $valid = false;
            $err .= "BILLING_CODE is not present or is invalid.";
        }
        
        if(isset($_POST["ACCOUNT"]) && in_array($_POST["ACCOUNT"], array("template1", "internet", "orangevista", "orangevista-mobile", "template1mobile")))
        {
            //ok
            $template = $_POST["ACCOUNT"];
        }
        else
        {
            $template = "internet";
        }
        
        return $valid;
    }
    ?>
    <noscript><input type="sumbit" value="Continue to Pay" /></noscript> 
    </form>
    </body>
    </html>
    Seems to work so far.So fingers crossed
    You can not say you know how to do something, until you can teach it to someone else.


  •  

    Tags for this Thread

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •