Link to home
Start Free TrialLog in
Avatar of Bill_B
Bill_B

asked on

CGI/Perl script doesn't work after server migration

I'm having some problems with a script that operates on the posted returns from Authorize.net after a successful transaction. We've recently migrated servers and in the process, the version of Perl was upgraded from 5.005_03 to 5.8.

Note: The script in question worked fine for about 2 years on the old server and no code has been changed before being placed on this new server.

Now that we're on the new server, the scripts are taking about 5-15 minutes to execute AFTER the response is received back from Authorize.net. We've been tracing it on the server and are absolutely sure that the response is back from Authorize.net almost immediately. The script eventually completes properly, with the receipt emails being sent out and the results of the order inserted into a mySQL database, but this is far, far longer than the script took on the old server (normally about 10-20 seconds from submission as opposed to 5-15 minutes now).
 
By inserting debug commands that write times out to a log file every other line, we've tracked this issue down to one line which is requiring extremely long processing times, which then results in the scripts pausing for an extremely long time. Once this line is passed, the rest of the script executes in less than 1 second.
 
The problematic line is here:
 
my $s_combined_name = "$s_firstname $s_lastname";
 
We've discovered that the script is able to jump past this line to contine on if the variables $s_firstname and $s_lastname are set with a static value in advance, but if they are not set (in other words, they're blank) in the post back from Authorize.net, the the script hangs. These lines refer to shipping address information. Sometimes this info is not set because the shipping address is the same as billing so the customer does not enter any shipping info. If information is entered for shipping first name ($s_firstname) and shipping last name ($s_lastname), the script runs quickly. Without entries for shipping address, though, it takes forever. I've pasted the full code up to the line in question down below.

Is this something you've seen before? Is this a result of some strict configuration of perl that does not allow blank variables to be parsed or used in an equation? A weird variable scope issue? Something that has to do with the param() method of reading in a POST? We have explored this in great depth over the past two days and are not coming up with an explanation.
 
Again, this script worked fine on the old version of perl, version 5.005_03 built for i386-freebsd. The code has not been changed except for the debugging and tracking code which has now been inserted for troubleshooting purposes.

Thanks!

-------------------------------------------

#!/usr/bin/perl -w

$|=1;           # Switch off buffering


require("xxx-lib.pl");
use strict;
use CGI qw(:standard); #import shortcuts

######################################
#  BEGIN VARIABLES FROM PAGE         #
######################################
#order information
my $itemsOrdered = param("itemsOrdered");
my $total = param("total");
my $clientEmail = param("email");

#customer information
my $firstname = param("firstname");
my $lastname = param("lastname");
my $addressLine1 = param("addressLine1");
my $addressLine2 = param("addressLine2");
my $city = param("city");
my $state = param("state");
my $zipCode = param("zipCode");
my $country = param("country");
my $phone = param("phone");

my $s_firstname = param("shipToFirstName");
my $s_lastname = param("shipToLastName");
my $s_addressLine1 = param("shipToAddressLine1");
my $s_addressLine2 = param("shipToAddressLine2");
my $s_city = param("shipToCity");
my $s_state = param("shipToState");
my $s_zipCode = param("shipToZipCode");
my $s_country = param("shipToCountry");
my $s_phone = param("shipToPhone");
my $s_clientEmail = param("shipToEmail");

my $shipping = param("shipping");
my $shipping_option = param("shipping_option");
my $coupon = param("Coupon");
my $creditCardName = param("creditCardName");
my $creditCardNumber = param("creditCardNumber");
my $expirationMonth = param("expirationMonth");
my $expirationYear = param("expirationYear");
my $hiddenSubTotal = param("hiddenSubTotal");
my $tax = param("tax");

######################################
#  BEGIN LOCAL SCRIPT VARIABLES      #
######################################

my $serverEmail = "xxx\@xxx.com";
my $combined_name = "$firstname $lastname";
my $s_combined_name = "$s_firstname $s_lastname";

my $mailprog = "/usr/sbin/sendmail";
my $discount = "0";
my $coupon_usage = param("coupon_usage");

my $x_response_code = param("x_response_code");
my $order_num;

if ( param("x_response_code") )
{

# AUTHORIZE.NET IS SENDING BACK A RESPONSE CODE, SO CALL
# THE SUBROUTINES TO FINISH UP THE ORDER AND REDIRECT

      &processOrder();
      exit;

}

<snipped the end of the script>


-------------------------------------------
ASKER CERTIFIED SOLUTION
Avatar of healthstatus
healthstatus

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Bill_B
Bill_B

ASKER

Thanks. I'll give this a shot. This is exactly the type of thing I was fishing for, but on first attempt it doesn't appear to be fixing the issue. I'll explore further and let you know.

The strange thing is that I can move the script back and forth between one box (old version of Perl) and another (new version of Perl) and it will work without fail on one but always have problems on the other.
I would really like you to think about going to the object oriented version of CGI, and making things a little slicker, along the lines of:

UNTESTED CODE FOLLOWS
# object def
my $input = CGI->new;
# get an array of all the parameters with stuff in them
my @what_i_got_back = $input->param();

#create a hash of the return parameters to use and the corresponding variable name
my %i_need = (
firstname => '$firstname',
lastname => '$lastname',
shipToFirstName => '$s_firstname',
 shipToLastName => '$s_lastname',
etc....
);

# go through the array one at a time
foreach my $param (@what_i_got_back){
      if(exists $i_need{$param}){    # if the parameter is in your %i_need hash
            ${$i_need{$param}} = $input->param($param) ;  # put the value in the named variable
            }
      }

You may have an old version of CGI with the 5.005 which handles timing differently than the more current ones.
Avatar of Tintin
healthstatus.

You can simply do

use CGI;
my $q = new CGI;
my %param = $q->Vars;

to popular the param hash.
Yes, but the param names don't match the variable names below, by setting a hash that cross references the input params with the variables he can keep the rest of the program as is.....
Whoops.  Didn't look at the code carefully enough.
Avatar of Bill_B

ASKER

Thanks so much for the help HealthStatus (and TinTin). Your posts were quite informative and helpful.

In the end, I believe that part of the problem was when a variable would end up being undefined and so your

  $param("variablename") || '';

fix helped the speed of the cycling.

The big thing that was really going on, though, was that the code was repeatedly re-declaring global variables. Sometimes from within subroutines, sometimes it would just declare a global variable again for no reason on the next line. I assume the old version of Perl ignored this, but the new version is more strict on syntax and variable scope.

In the end, I went through the whole thing one subroutine at a time, analyzed what was going on and removed excessive declarations. That speeded it up quite a bit.

Thanks!
Avatar of Bill_B

ASKER

By the way, that debugging that pointed to a pause at a certain line may or may not have been helpful. In retrospective, it doesn't seem to have been pointing to the real problem. When I'm less burnt out, maybe I'll go back and see if the tests really point to what was going on.