Author Topic: UPS shipping module, Godaddy and ConnectionTools.class FIXED!!  (Read 5479 times)

texasdave

  • Beginner
  • *
  • Posts: 1

I am soooooo happy because finally after solving the puzzle my UPS shipping module works!

My system is:

Shared godaddy hosting
Joomla 1.0.15
Virtuemart 1.1.1

My problem was the UPS module stalling or hanging after the checkout button was clicked.  It would timeout with errors that appeared that the proxy required by godaddy to get data outside the firewall wasn't connecting to the UPS server. 

This is what you need to do if you are having this problem.  The main problem is in the connectiontools.class.php file -- this is a wonderful and thanks to soren for writing it, it's awesome, but for those of us on godaddy shared hosting, you need to hardcode the godaddy proxy server into the php file located at:

administrator/components/com_virtuemart/classes/

this is the contents of the file that fixes the problem.  What you should do is backup your existing connectiontools.class.php file and then replace the whole file with this content:




<?php
if( !defined( '_VALID_MOS' ) && !defined( '_JEXEC' ) ) die( 'Direct Access to '.basename(__FILE__).' is not allowed.' );
/**
*
* @version $Id:connectionTools.class.php 431 2006-10-17 21:55:46 +0200 (Di, 17 Okt 2006) soeren_nb $
* @package VirtueMart
* @subpackage classes
* @copyright Copyright (C) 2004-2007 soeren - All rights reserved.
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL, see LICENSE.php
* VirtueMart is free software. This version may have been modified pursuant
* to the GNU General Public License, and as distributed it includes or
* is derivative of works licensed under the GNU General Public License or
* other free or open source software licenses.
* See /administrator/components/com_virtuemart/COPYRIGHT.php for copyright notices and details.
*
* http://virtuemart.net
*/

/// NOTE: THIS FILE IS A VARIATION ON SOEREN'S ORIGINAL, TWEAKED TO WORK ON A JOOMLA SITE HOSTED ON GODADDY


define( 'VM_PROXY_URL', '' );
define( 'VM_PROXY_PORT', '' );
define( 'VM_PROXY_USER', '' );
define( 'VM_PROXY_PASS', '' );
/**
 * Provides general tools to handle connections (http, headers, ... )
 *
 * @author soeren
 * @since VirtueMart 1.1.0
 */
class vmConnector {

   var $handle = null;

   /**
    * Clears the output buffer, sends a http status code and a content if given
    * @static
    * @param int $http_status
    * @param string $mime_type
    * @param string $content
    */
   function sendHeaderAndContent( $http_status=200, $content='', $mime_type='text/html' ) {

      // Clear all Joomla header and buffer stuff
      while( @ob_end_clean() );

      $http_status = intval( $http_status );
      @header("HTTP/1.0 $http_status");
      if( $mime_type ) {
         @header( "Content-type: $mime_type; charset=".vmGetCharset() );
      } elseif( $mime_type != '' ) {
         @header( "Content-type: text/html; charset=".vmGetCharset() );
      }
      if( $content ) {
         echo $content;
      }
   }
   /**
    * This is a general function to safely open a connection to a server,
    * post data when needed and read the result.
    * Tries using cURL and switches to fopen/fsockopen if cURL is not available
    * @since VirtueMart 1.1.0
    * @static
    * @param string $url
    * @param string $postData
    * @param array $headers
    * @param resource $fileToSaveData
    * @return mixed
    */
   function handleCommunication( $url, $postData='', $headers=array(), $fileToSaveData=null ) {
      global $vmLogger;

      $urlParts = parse_url( $url );
      if( !isset( $urlParts['port'] )) $urlParts['port'] = 80;
      if( !isset( $urlParts['scheme'] )) $urlParts['scheme'] = 'http';

      // Check proxy
      if( trim( @VM_PROXY_URL ) != '') {
         if( !stristr(VM_PROXY_URL, 'http')) {
            $proxyURL['host'] = VM_PROXY_URL;
            $proxyURL['scheme'] = 'http';
         } else {
            $proxyURL = parse_url(VM_PROXY_URL);
         }
      }
      else {
         $proxyURL = '';
      }

      if( function_exists( "curl_init" )) {

         $vmLogger->debug( 'Using the cURL library for communicating with '.$urlParts['host'] );

         $CR = curl_init();
         curl_setopt($CR, CURLOPT_URL, $url);
         //curl_setopt($ch, CURLOPT_VERBOSE, 1);

         // just to get sure the script doesn't die
         curl_setopt($CR, CURLOPT_TIMEOUT, 30 );
         if( !empty( $headers )) {
            // Add additional headers if provided
            curl_setopt($CR, CURLOPT_HTTPHEADER, $headers);
         }
         curl_setopt($CR, CURLOPT_FAILONERROR, true);
         if( $postData ) {
            curl_setopt($CR, CURLOPT_POSTFIELDS, $postData );
            curl_setopt($CR, CURLOPT_POST, 1);
         }
         if( is_resource($fileToSaveData)) {
            curl_setopt($CR, CURLOPT_FILE, $fileToSaveData );
         } else {
            curl_setopt($CR, CURLOPT_RETURNTRANSFER, 1);
         }
         // Do we need to set up the proxy?
         if( !empty($proxyURL) ) {
            $vmLogger->debug( 'Setting up proxy: '.$proxyURL['host'].':'.VM_PROXY_PORT );
            curl_setopt($CR, CURLOPT_HTTPPROXYTUNNEL, true);
            curl_setopt($CR, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
            //curl_setopt($CR, CURLOPT_PROXY, $proxyURL['host'] );
            //curl_setopt($CR, CURLOPT_PROXYPORT, VM_PROXY_PORT );
            curl_setopt($CR, CURLOPT_PROXY,"http://proxy.shr.secureserver.net:3128");   ///////  IMPORTANT! ENTER YOUR PROXY SERVER URL AND PORT INFORMATION HERE! IT WILL LOOK SOMETHING LIKE  http://url.of.yourproxyserver.com:portnumber YOU CAN FIND GODADDY'S INFO HERE: http://help.godaddy.com/article/289
            curl_setopt($CR, CURLOPT_SSL_VERIFYPEER, FALSE);
            // Check if the proxy needs authentication
            if( trim( @VM_PROXY_USER ) != '') {
               $vmLogger->debug( 'Using proxy authentication!' );
               curl_setopt($CR, CURLOPT_PROXYUSERPWD, VM_PROXY_USER.':'.VM_PROXY_PASS );
            }
         }

         if( $urlParts['scheme'] == 'https') {
            // No PEER certificate validation...as we don't have
            // a certificate file for it to authenticate the host www.ups.com against!
            // curl_setopt($CR, CURLOPT_SSL_VERIFYPEER, 0);
            //curl_setopt($CR, CURLOPT_SSLCERT , "/usr/locale/xxxx/clientcertificate.pem");
         }
         $result = curl_exec( $CR );
         $error = curl_error( $CR );
         if( !empty( $error ) && stristr( $error, '502') && !empty( $proxyURL )) {
            $vmLogger->debug( 'Switching to NTLM authenticaton.');
            curl_setopt( $CR, CURLOPT_PROXYAUTH, CURLAUTH_NTLM );
            $result = curl_exec( $CR );
            $error = curl_error( $CR );
         }
         curl_close( $CR );

         if( !empty( $error )) {
            $vmLogger->err( $error );
            return false;
         }
         else {
            return $result;
         }
      }
      else {
         if( $postData ) {
            if( !empty( $proxyURL )) {
               // If we have something to post we need to write into a socket
               if( $proxyURL['scheme'] == 'https'){
                  $protocol = 'ssl';
               }
               else {
                  $protocol = 'http';
               }
               $fp = fsockopen("$protocol://".$proxyURL['host'], VM_PROXY_PORT, $errno, $errstr, $timeout = 30);
            }
            else {
               // If we have something to post we need to write into a socket
               if( $urlParts['scheme'] == 'https'){
                  $protocol = 'ssl';
               }
               else {
                  $protocol = $urlParts['scheme'];
               }
               $fp = fsockopen("$protocol://".$urlParts['host'], $urlParts['port'], $errno, $errstr, $timeout = 30);
            }
         }
         else {
            if( !empty( $proxyURL )) {
               // Do a read-only fopen transaction
               $fp = fopen( $proxyURL['scheme'].'://'.$proxyURL['host'].':'.VM_PROXY_PORT, 'rb' );
            }
            else {
               // Do a read-only fopen transaction
               $fp = fopen( $urlParts['scheme'].'://'.$urlParts['host'].':'.$urlParts['port'].$urlParts['path'], 'rb' );
            }
         }
         if(!$fp){
            //error tell us
            $vmLogger->err( "Possible server error! - $errstr ($errno)\n" );
            return false;
         }
         else {
            $vmLogger->debug( 'Connection opened to '.$urlParts['host']);
         }
         if( $postData ) {
            $vmLogger->debug('Now posting the variables.' );
            //send the server request
            if( !empty( $proxyURL )) {
               fputs($fp, "POST ".$urlParts['host'].':'.$urlParts['port'].$urlParts['path']." HTTP/1.0\r\n");
               fputs($fp, "Host: ".$proxyURL['host']."\r\n");

               if( trim( @VM_PROXY_USER )!= '') {
                  fputs($fp, "Proxy-Authorization: Basic " . base64_encode (VM_PROXY_USER.':'.VM_PROXY_PASS ) . "\r\n\r\n");
               }
            }
            else {
               fputs($fp, 'POST '.$urlParts['path']." HTTP/1.0\r\n");
               fputs($fp, 'Host:'. $urlParts['host']."\r\n");
            }
            fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
            fputs($fp, "Content-length: ".strlen($postData)."\r\n");
            fputs($fp, "Connection: close\r\n\r\n");
            fputs($fp, $postData . "\r\n\r\n");
         }
         else {
            if( !empty( $proxyURL )) {
               fputs($fp, "GET ".$urlParts['host'].':'.$urlParts['port'].$urlParts['path']." HTTP/1.0\r\n");
               fputs($fp, "Host: ".$proxyURL['host']."\r\n");
               if( trim( @VM_PROXY_USER )!= '') {
                  fputs($fp, "Proxy-Authorization: Basic " . base64_encode (VM_PROXY_USER.':'.VM_PROXY_PASS ) . "\r\n\r\n");
               }
            }
            else {
               fputs($fp, 'GET '.$urlParts['path']." HTTP/1.0\r\n");
               fputs($fp, 'Host:'. $urlParts['host']."\r\n");
            }
         }
         // Add additional headers if provided
         foreach( $headers as $header ) {
            fputs($fp, $header."\r\n");
         }
         $data = "";
         while (!feof($fp)) {
            $data .= @fgets ($fp, 4096);
         }
         fclose( $fp );

         // If didnt get content-lenght, something is wrong, return false.
         if ( trim($data) == '' ) {
            $vmLogger->err('An error occured while communicating with the server '.$urlParts['host'].'. It didn\'t reply (correctly). Please try again later, thank you.' );
            return false;
         }
         $result = trim( $data );
         if( is_resource($fileToSaveData )) {
            fwrite($fileToSaveData, $result );
            return true;
         } else {
            return $result;
         }
      }
   }
   /**
   * Set headers and send the file to the client
   *
   * @author Andreas Gohr <andi@splitbrain.org>
   * @param string The full path to the file
   * @param string The Mime Type of the file
   */
   function sendFile($file,$mime, $overrideFileName=''){
      global $vm_mainframe;
      // send headers
      header("Content-Type: $mime");
      
      list($start,$len) = vmConnector::http_rangeRequest(filesize($file));
      
      header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
      header('Pragma: public');
      header('Accept-Ranges: bytes');

      //application mime type is downloadable
      if(strtolower(substr($mime,0,11)) == 'application'){
         if( $overrideFileName == '') {
            $filename = basename($file);
         } else {
            $filename = $overrideFileName;
         }
         header('Content-Disposition: attachment; filename="'.$filename.'";');
      }
      
      $chunksize = 1*(1024*1024);
      // send file contents
      $fp = @fopen($file,"rb");
      if($fp){
         fseek($fp,$start); //seek to start of range

         $chunk = ($len > $chunksize) ? $chunksize : $len;
         while (!feof($fp) && $chunk > 0) {
            @set_time_limit(); // large files can take a lot of time
            print fread($fp, $chunk);
            flush();
            $len -= $chunk;
            $chunk = ($len > $chunksize) ? $chunksize : $len;
         }
         fclose($fp);
      }else{
         header("HTTP/1.0 500 Internal Server Error");
         print "Could not read $file - bad permissions?";
         $vm_mainframe->close(true);
      }
   }
   /**
   * Checks and sets headers to handle range requets
   *
   * @author  Andreas Gohr <andi@splitbrain.org>
   * @return array The start byte and the amount of bytes to send
   * @param int The file size
   */
   function http_rangeRequest($size, $exitOnError=true ){
      global $vm_mainframe;
      if(!isset($_SERVER['HTTP_RANGE'])){
         // no range requested - send the whole file
         header("Content-Length: $size");
         return array(0,$size);
      }

      $t = explode('=', $_SERVER['HTTP_RANGE']);
      if (!$t[0]=='bytes') {
         // we only understand byte ranges - send the whole file
         header("Content-Length: $size");
         return array(0,$size);
      }

      $r = explode('-', $t[1]);
      $start = (int)$r[0];
      $end = (int)$r[1];
      if (!$end) $end = $size - 1;
      if ($start > $end || $start > $size || $end > $size){
         if( $exitOnError ) {
            header('HTTP/1.1 416 Requested Range Not Satisfiable');
            print 'Bad Range Request!';
            $vm_mainframe->close(true);
         } else {
            return array(0,$size);
         }
      }

      $tot = $end - $start + 1;
      header('HTTP/1.1 206 Partial Content');
      header("Content-Range: bytes {$start}-{$end}/{$size}");
      header("Content-Length: $tot");

      return array($start,$tot);
   }
}
?>

///////////////////////////////////////STOP  HERE //////////////////////////


So, you will notice that the godaddy proxy service is: 

http://proxy.shr.secureserver.net:3128


You are NOT finished.  That is just the file you need to change.  There are some settings in VM that you need to double check:


1)  in VM 1.1.1, go to Admin/Configuration, click on the Security tab.  down at the lower right you'll need to fill in the global proxy settings and SAVE.

Proxy:  proxy.shr.secureserver.net
Port:  3128
username:  ((leave it blank))
password:  ((leave it blank))

2)  Click on the shipping tab in the same configuration page.  Be sure that the UPS shipping module is checked ON.

3)  Click on STORE on the left hand navigation area.  it will spread out to reveal the Shipping Module List. -- Click shipping modules list.  In here the UPS module should be check ON with a green arrow. Click on UPS configure ship method link.  Here's where you need OTHER info from UPS.  You will need to get your Developer's key and then get your XML access key (code) from them at: 

http://www.ups.com/e_comm_access/gettools_index?loc=en_US

Remember you want the XML one!!!!  There's a bunch of registrations forms, just try to get through it -- I did!

In the settings you need to put in your UPS developer account info:

access code:  ((it's a long string characters)
username
password

ship from zip code:  ((your zipcode you are shipping from!!!))

make sure you have a few shipping methods checked like UPS ground and 2nd day air.

4)  you need a secure certificate -- godaddy offers them for a flat fee per year.    Put your secure cert. URL in the Configuration / Security area.  should be like this:  https://yoursite.com



That's IT..  Thanks to the guy who showed it to me, he hardcoded it, not me... i will find his name, and also thanks to Soeren.

I hope this works for people on godaddy.













beerbelly

  • Beginner
  • *
  • Posts: 3
Re: UPS shipping module, Godaddy and ConnectionTools.class FIXED!!
« Reply #1 on: July 30, 2008, 06:44:26 am »
Wow, this one did it.  It actually got it all working with UPS.  Thanks so much for this post!  I was not aware GoDaddy had a proxy server for this type of stuff.  I would never have even bothered to consider that that was part of the problem.