SitePoint Sponsor

User Tag List

Results 1 to 8 of 8
  1. #1
    SitePoint Enthusiast aweb4u's Avatar
    Join Date
    Jun 2007
    Location
    Auckland, New Zealand
    Posts
    75
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Query String Vanishing?

    The Scenario
    I've got a PHP script (PHP version 5.2.17) that creates an order record in a MySQL database and then looks at how the user elected to pay for the order (credit card, PayPal, etc) and redirects to the appropriate payment page. As part of the redirection the Order ID is passed as a URL query string so that the relevant order may be retrieved by the payment page.

    The payment page grabs the Order ID from the query string and retrieves the relevant order and then goes on to continue processing the order.

    The Problem
    99% of the time this works fine. But a very small number of times the payment page fails and emails me an error message saying that the order record couldn't be read and that the Order ID was empty. If I compare the timestamp on the email with the timestamp of records in the Orders table I can see that an order was indeed created at that time and it has an Order ID. The only conclusion that I can come to is that the query string is somehow being altered to remove the Order ID.

    The Code
    The portion of code that generates the Order ID, saves the record and redirects to the appropriate payment page looks like this:

    PHP Code:
    $orderid md5(uniqid(rand())); 
    $schoolid mysql_real_escape_string($_SESSION['SchoolID']); 
    $parentname mysql_real_escape_string($_SESSION['ParentName']); 
    $email mysql_real_escape_string($_SESSION['Email']); 
    $phone mysql_real_escape_string($_SESSION['Phone']); 
    $sql "INSERT INTO orders (OrderID,SchoolID,OrderDate,ParentName,Email,Phone) VALUES " 
    "(\"$orderid\",\"$schoolid\",CURDATE(),\"$parentname\",\"$email\",\"$phone\")"
    mysql_query($sql); 
    if (
    mysql_error()) { 
      
    DisplayMySQLError("Could not create Orders record"$sqlTRUE); 


    switch(
    $paymentmethod) { 
      case 
    "DPS"
        
    header("Location: payment-dps-send.php?orderid=$orderid"); 
        break; 
      case 
    "Direct Credit"
        
    header("Location: payment-direct-credit-response.php?orderid=$orderid"); 
        break; 
      case 
    "School"
        
    header("Location: payment-school-response.php?orderid=$orderid"); 
        break; 

    exit; 
    And then in each payment page I do the following:

    PHP Code:
    $orderid = isset($_GET['orderid']) ? $_GET['orderid'] : ""
    if (!
    $ordersRow GetOrdersRecord($orderid)) { 
      echo 
    "Invalid Order ID"
      
    $msg "Could not find Orders record for Order ID \"$orderid\" in " $_SERVER['PHP_SELF']; 
      
    NotifyWebmaster($msg); 
      exit; 

    I know there are a few functions here that I haven't included (ie GetOrdersRecords()) but I don't think they are at fault.

    I get an error saying: Could not find Orders record for Order ID "" in /payment-direct-credit-response.php

    The error only seems to occur about 1% of the time, the rest of the time everything works fine. I've never been able to cause the error to occur myself, it's only with live users (who unfortunately I've been unable to communicate with). The user usually tries again and everything goes through ok.

    Things I've Considered
    If the payment pages are accessed directly (i.e. not through the order page) then the Order ID won't be sent in the query string and I will see the behaviour that I'm getting (an error message sent to me saying that there was no Order ID). I can think of a few different ways that the payment pages could be access directly:

    1. A user types the URL in directly
    2. A search engine or other automated spider is accessing the page
    3. A browser add-on is trying to pre-fetch the page to speed up access
    4. An anti-virus program is requesting the page so it can check it for malware


    I don't think it's #1 or #2 because I know that these are real orders because real data is being stored in the database, which tells me that the order page has been accessed first.

    I don't think it's #3 or #4 because why would they remove the query string before retrieving the page?

    I'm now wondering if there is a bug in PHP that sometimes causes it to mis-handle query strings. Or maybe a bad browser that sometimes mangles the query string.

    The fact that it works 99% of the time makes me believe that it isn't my code that is at fault and it's something outside my control.

    I'm using this order setup on 5 different websites, all hosted by the same host, and they all get this error from time to time.

    Does anyone have any ideas on what the problem might be?

  2. #2
    SitePoint Wizard silver trophybronze trophy Cups's Avatar
    Join Date
    Oct 2006
    Location
    France, deep rural.
    Posts
    6,869
    Mentioned
    17 Post(s)
    Tagged
    1 Thread(s)
    Some more things you could try:

    check your server log files and see if indeed an empty string is passed in these cases.

    check the offending database entries, do they have similar characteristics?

    The code in your payments page is somewhat ambiguous in that it will give out the same message given either case that:

    $_GET['orderid'] is set at all

    OR

    if it is set, it does not match that from your db.

    So, you might need to differentiate the cases and give yourself a different message:

    PHP Code:
    $orderid = isset($_GET['orderid']) ? $_GET['orderid'] : "";  

    if(
    $orderid === ""){
      echo 
    "Invalid Order ID";  
      
    // get some more useful info about the process .. you could add more
      
    $msg "Failed to pass and order id in " $_SERVER['PHP_SELF'] . " entire SERVER vars were " var_export($_SERVERtrue);  
      
    NotifyWebmaster($msg);  
      exit;  
    } elseif (
    $ordersRow != GetOrdersRecord($orderid)) {  // changed condition slightly
      
    echo "Invalid Order ID";  
      
    $msg "Could not find Orders record for Order ID \"$orderid\" in " $_SERVER['PHP_SELF'];  
      
    NotifyWebmaster($msg);  
      exit;  

    Overall though, unless I am missing a vital piece of information, would $_SESSION not be the correct place to store and retrieve such a crucial piece of information rather than leave your app open to query string abuse?

  3. #3
    SitePoint Enthusiast aweb4u's Avatar
    Join Date
    Jun 2007
    Location
    Auckland, New Zealand
    Posts
    75
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for your suggestions, Cups, I'll definitely follow them up and see what I can find out.

  4. #4
    SitePoint Wizard silver trophybronze trophy Cups's Avatar
    Join Date
    Oct 2006
    Location
    France, deep rural.
    Posts
    6,869
    Mentioned
    17 Post(s)
    Tagged
    1 Thread(s)
    Let us know how you get on.

  5. #5
    SitePoint Enthusiast aweb4u's Avatar
    Join Date
    Jun 2007
    Location
    Auckland, New Zealand
    Posts
    75
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Someone else on another forum pointed out to me that my header() calls didn't follow the specification because they weren't absolute URI's. I was doing:
    Code:
    header("Location: payment-dps-send.php?orderid=$orderid");
    when I should have been doing:
    Code:
    header("Location: http://www.example.com/payment-dps-send.php?orderid=$orderid");
    I don't think this error was causing the problem but I've updated my header() calls and also added in more diagnostics in the email I receive when the error occurs to see if I can pick up any patterns. Unfortunately the problem hasn't reoccurred since I've made those changes.

  6. #6
    SitePoint Member blogaddition's Avatar
    Join Date
    Sep 2012
    Location
    India
    Posts
    23
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    When you insert the unique order id in mysql database then pass the same order id on payment page by using $order_id = mysql_insert_id; and pass this id to the payment page. I think that can help you out.

  7. #7
    SitePoint Enthusiast aweb4u's Avatar
    Join Date
    Jun 2007
    Location
    Auckland, New Zealand
    Posts
    75
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by blogaddition View Post
    When you insert the unique order id in mysql database then pass the same order id on payment page by using $order_id = mysql_insert_id; and pass this id to the payment page. I think that can help you out.
    I don't use mysql_insert_id() because I generate the Order ID myself rather than using MySQL's auto increment. This is because the Order ID may become public knowledge and I don't want people to be able to guess the sequence and possibly interfere with things by injecting their own Order ID.

  8. #8
    SitePoint Member blogaddition's Avatar
    Join Date
    Sep 2012
    Location
    India
    Posts
    23
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    mysql_insert_id is the last inserted id in your table. I mean first you generate the unique id with unique function then it is inserted into mysql table and then use mysql_insert_id to payment page so that there will be no misconfustion that what id is going on payment page. Just i wanted to say.


Bookmarks

Posting Permissions

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