<?php 
 
// Sauen PHP Surepay lib - version 0.1.1 Beta - 2002 March 19
 // sausurepay.php - The main classes and functions library file        
 // ---------------------------------------------------------------------------
 /* Licensed under GNU General Public License (GPL) v2.0
    Code collection providing functions and classes for the Surepay.Com gateway.
    Copyright (C) 2001-2002 J.T.Stokkeland and Sauen.Com.

    This code-collection is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 // With this file you should have received the file license.txt which contains
 // the full GNU GPL license details. Author contact information:
 //   Jon T Stokkeland aka /Stoke/  SauSurepay@Sauen.com
 //   302 E State St, Salamanca, NY, 14779, USA
 // ---------------------------------------------------------------------------
 // For more information about versions and other helpful info, see readme.*  
 // Homepage of this PHP code collection lib: http://sausurepay.sourceforge.net
 // PS! This version is NOT a complete library of all the Surepay functions!
 // ---------------------------------------------------------------------------
 // "namespace" sausp_ is used for all global functions/classes



### Main class - the only one users need to interreact with
class sausp {
 
   
###############################
   #
   #  Public Functions
   #
   #     Parameters listed as R is required, O is optional.
   #
   ###############################


   # add_auth : create an AUTH object

     
function add_auth (
        
$params = array(),       # R: Associative array. Must include surepay pp.auth params
        
$ship_address = array(), # O: Associative array.
        
$ordertext = array() )   # O: Associative array. (One element)
     
{
        if (
is_array($params) && $params) {
            
$this->request['request'][$idx = ++$this->request['cnt']]['type'] = 'pp.auth';
            
$this->request['request'][$idx]['params'] = $params;
            
$this->request['request'][$idx]['cnt'] = 0;
            
$pstr '['.$idx.']';
            if (
$ship_address) {
                if (
is_array($ship_address)) {
                    
$this->add_shipping_address($pstr,$ship_address);
                } else {
                    
$this->err 'Address supplied to add_auth was not an array';
                }
            }
            if (!
$this->err && $ordertext) {
                if (
is_array($ordertext)) {
                    
reset($ordertext);
                    
$this->add_ordertext($pstr,
                        
key($ordertext),
                        
$ordertext[key($ordertext)]
                     );
                } else {
                    
$this->err 'ordertext supplied to add_auth was not an array';
                }
            }
            if (!
$this->err) return $pstr;
        } else {
            
$this->err 'pp.auth parameters error. Not given or none-array';
        }
     }


   
# add_shipping_address : adds an adress of type shipping

     
function add_shipping_address (
         
$pstr,         # "Object" identifier
         
$params )      # Array: address parameters excluding type
     
{
         
$params array_merge
             array( 
'type' => 'shipping' ),
             
$params);
         return 
$this->add_address($pstr,$params);
     }


   
# add_billing_address : adds an adress of type billing

     
function add_billing_address (
         
$pstr,         # "Object" identifier
         
$params )      # Array: address parameters excluding type
     
{
         
$params array_merge
             array( 
'type' => 'billing' ),
             
$params);
         return 
$this->add_address($pstr,$params);
     }


   
# add_ordertext : adds an ordertext object

     
function add_ordertext (
         
$pstr,     # "Object" identifier
         
$type,     # String
         
$data )    # String        
     
{
        if ( 
strlen($data) > 25 ) {
            
$this->err 'Order text length exceeded 25 characters';
        }
        elseif (
               ( 
strtolower($type) == 'description'
            || ( 
strtolower($type) == 'instructions')
            || ( 
strtolower($type) == 'classification')
           ) 
        {
             eval(
$this->peval($pstr));
             
$idx = ++$ptr['cnt'];
             
$ptr[$idx]['type'] = 'pp.ordertext';
             
$ptr[$idx]['params'] = array('type'=> strtolower($type));
             
$ptr[$idx]['data'] = trim($data);
             
$ptr[$idx]['cnt'] = 0;
             return 
$pstr.'['.$idx.']';
        } 
        else {
            
$this->err 'ordertext type was not (description|instructions|classification)';
        }
     }


   
# add_creditcard : add a credit card object
   #     Planned for future versions: Validate even more parameters.

     
function add_creditcard (
       
$pstr,               # "Object" identifier
       
$number,             # string cc number
       
$expiration,         # string expiration format mm/yy
       
$cvv2,               # string (must be 0 or '' if not used, then set stat to 0 or 9)
       
$cvv2status 1,     # int set(0,1,9)
       
$baddress=array() )  # Array
     
{
        if (!
$number || !$expiration ) {
          
$this->err 'Number or Expiration not present in add_creditcard';
        }
        elseif (!
preg_match('/^[0-9]{1,2}\/[0-9]{1,2}$/',$expiration)) {
          
$this->err 'Expiration is formatted wrong (mm/yy)';
        }
        elseif (!
$cvv2 && $cvv2status == 1) {
          
$this->err 'cvv2 enabled but no cvv2 given';
        }
        elseif (
$cvv2status == && strlen($cvv2) > 4) {
          
$this->err 'cvv2 code to long (max 4)';
        }
        elseif (
$cvv2status == && strlen($cvv2) < 3) {
          
$this->err 'cvv2 code to short (min 3)';
        }
        else {
             if (!
$cvv2$cvv2 '0';
             eval(
$this->peval($pstr));
             
$idx = ++$ptr['cnt'];
             
$ptr[$idx]['type'] = 'pp.creditcard';
             
$ptr[$idx]['params'] = array(
                  
'number'=> $number,
                  
'expiration'=> $expiration,
                  
'cvv2'=> $cvv2,
                  
'cvv2status'=> $cvv2status
              
);
             
$ptr[$idx]['data'] = '';
             
$ptr[$idx]['cnt'] = 0;
             
$pstr $pstr.'['.$idx.']';
             if (
$baddress) {
                  if (
is_array($baddress)) {
                      
$this->add_billing_address($pstr,$baddress);
                  } else {
                      
$this->err 'Billing address supplied in add_cc but was not an array';
                  }
             }
             if (!
$this->err) return $pstr;
        }
     }



   
# add_lineitem : add an item object to an auth object
   #   Planned for future versions: Better validation of parameters.

     
function add_lineitem (
             
$pstr,           # Object identifier
             
$quantity,       # int
             
$sku,            # product sku
             
$description,    # string (200)
             
$unitprice,      # string (nnn.nnUSD)
             
$taxrate='0',    # real (0.08 = 8%)
             
$options=array() # Optional options array
       
)
     {  
        if (!
$quantity || !$sku || !$description || !$unitprice ) {
           
$this->err 'Missing required parameters for add_lineitem';
        }
        else {
             eval(
$this->peval($pstr));
             
$idx = ++$ptr['cnt'];
             
$ptr[$idx]['type'] = 'pp.lineitem';
             
$ptr[$idx]['params'] = array(
                  
'quantity'=> $quantity,
                  
'sku'=> $sku,
                  
'description'=>substr($description,0,200),
                  
'unitprice'=> $unitprice,
                  
'taxrate'=> $taxrate
              
);
             
$ptr[$idx]['data'] = '';
             
$ptr[$idx]['cnt'] = 0;
             
$pstr $pstr.'['.$idx.']';
             if (
$options) {
                  if (
is_array($options)) {
                      
reset($options);
                      
$cnt 3;  # Max 3 options per line item
                      
while ((list($key,$val)=each($options)) && $cnt--) { 
                         
$this->add_option($pstr,$key,$val);
                      }
                  } else {
                      
$this->err 'Options defined but was not an array for add_lineitem';
                  }
             }
             if (!
$this->err) return $pstr;
        }
    }   


   
# add_option : adds an option (for line item)

     
function add_option (
        
$pstr,       # Object identifier
        
$label,      # String
        
$value  )    # String
     
{
        if (!
$label) {
             
$this->err 'Option label not specified';
        }
        else {
             eval(
$this->peval($pstr));
             
$idx = ++$ptr['cnt'];
             
$ptr[$idx]['type'] = 'pp.option';
             
$ptr[$idx]['params'] = array(
                  
'label'=> $label,
                  
'value'=> $value
              
);
             
$ptr[$idx]['data'] = '';
             
$ptr[$idx]['cnt'] = 0;
             return 
$pstr.'['.$idx.']';
        }
     }


   
# add_telecheck : adds a telecheck

   ##  object_identifier: add_telecheck (
   ##      object_identifier: parent object
   ##     ,string: Check number
   ##     ,string: MICR number (Continous string of EVERY number on the bottom of the check)
   ##     ,boolean: isbusiness (true = business, false=persona)
   ##    [,array: identification object attributes (Dr.license)]
   ##    [,array: billing address]
   ##  )

     
function add_telecheck (
         
$pstr,             # Object identifier
         
$number,           # String (int)
         
$micr,             # String
         
$isbusiness,       # Boolean
         
$id=array(),       # Array
         
$baddress=array()) # Array
     
{
         if (
strlen($number) > 6) { $this->err 'Check number to long (max 6 digits)'; }
         elseif (!
$number) { $this->err 'No Check number provided'; }
         elseif (
strlen($micr) > 35) { $this->err 'Check MICR is to long (max 35)'; }
         else {
             if (
$isbusiness$isbusiness 'true'; else $isbusiness 'false';
             eval(
$this->peval($pstr));
             
$idx = ++$ptr['cnt'];
             
$pstr $pstr.'['.$idx.']';
             
$ptr[$idx]['type'] = 'pp.telecheck';
             
$ptr[$idx]['params'] = array(
                  
'number'=> $number,
                  
'micr'=> $micr,
                  
'isbusiness'=> $isbusiness
              
);
             
$ptr[$idx]['data'] = '';
             
$ptr[$idx]['cnt'] = 0;
             if (
$id) {
                 if (!
is_array($id)) {
                     
$this->err 'identification data supplied to add_telecheck but was not an array';
                 } else {
                     
$this->add_identification $pstr$id );
                 }
             }
             if (
$baddress && !$this->err) {
                 if (!
is_array($baddress)) {
                     
$this->err 'billing address data supplied to add_telecheck but was not an array';
                 } else {
                     
$this->add_billing_address $pstr$baddress );
                 }
             }
             if (!
$this->err) return $pstr;
         }
     }


   
# add_id_driverslicense : Add a id object

   
function add_id_driverslicense (
       
$pstr,       # Object_identifier
       
$number,     # String
       
$issuedby )  # String
   
{
       if (!
$number || !$issuedby) {
           
$this->err 'Required ID number and Issue (State-abr) is missing';
       }
       else {
           return 
$this->add_identification (
               
$pstr,
               array(
                 
'type' => 'driverslicense',
                 
'number' => $number,
                 
'issuedby' => $issuedby ) );
       }
   }
               


   
# prepare_request : build the xml document from held data
   # This function does not nest dynamically any level, I was too tired when
   # creating it so it is limited to 3 levels now..
   # In the future we should use a level digger and auto generation fo any tag,
   # and perhaps use DOM for the objects to begin with.
   # ..adding \n's in the output to make it readable

     
function prepare_request () {
         if (
$this->request['cnt']) {
           
$requests '';
           
reset($this->request['request']);
           while (list(
$idx,$req) = each($this->request['request'])) {
               
$requests2 '';
               for(
$idx2=$this->request["request"][$idx]['cnt']; $idx2$idx2--) {
                   
$requests3 '';
                   for(
$idx3=$this->request["request"][$idx][$idx2]['cnt']; $idx3$idx3--) {                   
                      
$requests3 .= "\n".$this->xmltag(
                         
$this->request["request"][$idx][$idx2][$idx3]['type'],
                         
$this->request["request"][$idx][$idx2][$idx3]['params'],
                         
trim($this->request["request"][$idx][$idx2][$idx3]['data']));
                   }
                   if (
$requests3$requests3 .= "\n";
                   
$requests2 .= "\n".$this->xmltag(
                      
$this->request["request"][$idx][$idx2]['type'],
                      
$this->request["request"][$idx][$idx2]['params'],
                      
trim($this->request["request"][$idx][$idx2]['data']) . "$requests3");
               }
               if (
$requests2$requests2 .= "\n";
               
$requests .= "\n" $this->xmltag(
                   
$this->request["request"][$idx]['type'],
                   
$this->request["request"][$idx]['params'],
                   
trim($this->request["request"][$idx]['data']) . "$requests2");
           }
           
$this->xml_request 
              
$this->xmldtd($this->request_dtd
              . 
"\n" $this->xmltag(
                  
$this->xml_root,
                  
$this->request['params'],
                  
$this->request['data']. $requests "\n"
                
) . "\n";
         } else {
             
$this->err 'No request objects??';
         }
         if (!
$this->err) return $this->xml_request;
     }


   
# submit_request : Post the request XML to surepays server.

     
function submit_request (
       
$timeout=90,      # Integer
       
$sslver=)       # Integer 0/2/3
     
{
        if (!
$this->xml_request) { $this->err 'No XML data to post'; }
        else {
            
$curlsession curl_init();
            
curl_setopt ($curlsessionCURLOPT_URL$this->serverurl);
            
curl_setopt ($curlsessionCURLOPT_POST1);
            
curl_setopt ($curlsessionCURLOPT_POSTFIELDS'xml='.$this->xml_request);
            
curl_setopt ($curlsessionCURLOPT_TIMEOUT$timeout);
            
curl_setopt ($curlsessionCURLOPT_HEADER0);
               
curl_setopt ($curlsessionCURLOPT_SSLVERSION$sslver);
            
curl_setopt ($curlsessionCURLOPT_RETURNTRANSFER1);
            
$this->xml_response curl_exec ($curlsession);    
            
$curlinfo curl_getinfo($curlsession);
            if (!
$this->xml_response) {
               
$curl_error curl_error($curlsession);
               
$curl_errno curl_errno($curlsession);
               
$this->err 'Curl error: '.$curl_errno.' '.$curl_error."\nConnection details:\n";
               if (
is_array($curlinfo)) {
                    while (
$row each($curlinfo)) {
                         
$curl_info .= '  ' $row[0] . ' => ' $row[1] . "\n";
                    }
               } else {
                   
$curl_info .= '  '.$curlinfo;
               }
            } 
            
curl_close($curlsession);
            if (!
$this->err) return $this->xml_response;
        }
     }


    function 
parse_response() {
        if (!
$this->xml_response) { $this->err 'No response XML to parse'; }
        else {
            return 
$this->parse($this->xml_response);
        }
    }




  
# Some functions for returning status of response

  // Return amount of AUTH response records found
    
function count_auth_response () {
         return 
count($this->responseattr['PP.AUTHRESPONSE']) ;
    }

  
// AUTHRESPONSE: transaction id by orderno
    
function auth_trans_id ($on) {
         return 
$this->responseattr['PP.AUTHRESPONSE'][$on]['TRANSACTIONID'];
    }

  
// AUTHRESPONSE: cvv2result by orderno
    
function auth_cvv2result ($on) {
         return 
$this->responseattr['PP.AUTHRESPONSE'][$on]['CVV2RESULT'];
    }

  
// AUTHRESPONSE: response avs by orderno
    
function auth_avs ($on) {
         return 
$this->responseattr['PP.AUTHRESPONSE'][$on]['AVS'];
    }

  
// AUTHRESPONSE: Return auth status by orderno
    
function auth_status ($on) {
        return 
$this->responseattr['PP.AUTHRESPONSE'][$on]['AUTHSTATUS'];
    }
    
  
// AUTHRESPONSE: return authcode if status is AUTH and there is no failure
    
function auth_authcode ($on) {
        if (
                
$this->auth_status($on) == 'AUTH'
            
&& !$this->auth_failure($on)
           )
           return 
$this->responseattr['PP.AUTHRESPONSE'][$on]['AUTHCODE'];
    }

  
// AUTHRESPONSE: return failure attribute
    
function auth_failure($on) {
        return 
$this->responseattr['PP.AUTHRESPONSE'][$on]['FAILURE'];
    }

  
// AUTHRESPONSE: return response text (Should only hold data if DCL, REF or ERR status)
    
function auth_text ($on) {
         return 
$this->responsedata['PP.AUTHRESPONSE'][$on];
    }

  
// AUTHRESPONSE: return an array of all AUTH response order numbers
    
function auths () {
         return 
array_keys($this->responseattr['PP.AUTHRESPONSE']);
    }



   
###############################
   #
   #  Functions for internal use by class sausp
   #
   ###############################

   # Initialization of the class (Ran automatically when object is created)

     
function sausp (
         
$live false,       # R: boolean (False = surepay test, true = real surepay transaction)
         
$merchant '',      # R: string (numeric?)
         
$passwd '',        # R: string
         
$params = array() )  # O: Associative array
     
{

      
# Set server to use (live or test)

        
if ($live) {
            
$this->serverurl 'https://xml.surepay.com';
        } else {
            
$this->serverurl 'https://xml.test.surepay.com';
        }

      
# Default doctype/dtd specs as of the release date of this lib
        
$this->request_dtd =
             
'pp.request PUBLIC "-//IMALL//DTD PUREPAYMENTS 1.0//EN" "http://www.purepayments.com/dtd/purepayments.dtd"';
        
$this->response_dtd 
             
'pp.response PUBLIC "-//IMALL//DTD PUREPAYMENTS 1.0//EN" "http://www.purepayments.com/dtd/purepayments.dtd"';

      
# Lib version and info
        
$this->version '0.1.1';
        
$this->lib 'SauSurepay v'.$this->version.', Copyright 2001-2002 Jon T Stokkeland and Sauen.Com';

      
# Do some error control
        
if (!$merchant || !$passwd) {
           
$this->err 'Merchant id and/or password not specified';
        }
        elseif (!
is_array($params)) {
           
$this->err 'Extra pp.request parameters was provided but not as an array';
        }
        else 
$this->err '';  

      
# Put stuff together (we'll try even if there has been an error)
        
$params array_merge
            array (
              
'merchant' => $merchant,
              
'password' => $passwd
            
),
            
$params 
         
);

      
# Some XML parsing settings
   
         
$this->parse_responsetypes = array (    // Known response types
             
"PP.AUTHRESPONSE"
         
);    
           
# Excluded for now: "PP.ADJUSTRESPONSE","PP.REPLACERESPONSE",
           #                   "PP.CREDITRESPONSE","PP.SETTLENOWRESPONSE"

         
$this->parse_xmlroot 'PP.RESPONSE'# Root element
   
      # Set up stuff
        
$this->request = array( 
            
'dtd'     => $this->request_dtd,
            
'cnt'     => 0,
            
'params'  => $params,
            
'request' => array()
         );
         
$this->xml_root 'pp.request';

      
# Clear stuff
        
$this->response = array();
        
$this->xml_request '';
        
$this->xml_response '';
        
$this->responseattr = array();
        
$this->responsedata = array();
        if (!
$this->err) return 1;
     }


   
# xmltag : creation of xml tag
   #     Planned for future version: Check tagnames and field values for use of
   #     legal characters and entities, perhaps automatic XML entity conversion?
   #     could need something like xml_entities(str) ...

     
function xmltag (
       
$tagname,           # R: String
       
$params = array(),  # O: Assosiative array
       
$data ='' )         # O: String
     
{
         
$result "<$tagname";
         if (
$params) {
           while (list (
$key$val) = each ($params)) {
           
$result .= ' '.$key.'="'.addslashes($val).'"';
         }     
     } 
        if (
trim($data)) { 
            if (!
preg_match('/<.+?(\/>|>.*?<\/.+?>)/',$data)) { # unless it contains XML tags and data...
                # <? # Added this line to fool my txt editor here, it got confused about that regex :)
                # Here I try to remove any special chars which surepay may fail on, replaced with _
                # Had some oddities with [] and ^ so I separated them..
                
$data preg_replace('/([^A-z0-9$._\-()]|\^|\[|\])/','_',$data);
            } 
            

            
$result .= '>'.$data.'</'.$tagname.'>'
        }
        else { 
$result .= " />"; }
        
$this->$err '';  # No error control as of yet
        
if (!$this->err) return $result;
     }


   
   
# xmldtd : return a doctype tag

     
function xmldtd (
       
$str )  # String
     
{
    if (
$str) return '<!DOCTYPE '.$str.'>';
        else { 
$this->err 'No doctype string given'; }
     }



   
# add_address : add an address to the object
   #     Planned for future versions: Validate parameters. 

     
function add_address (
         
$pstr,         # "Object" identifier
         
$params )      # Array: address parameters excluding type
     
{
         eval(
$this->peval($pstr));
         
$idx = ++$ptr['cnt'];
         
$ptr[$idx]['type'] = 'pp.address';
         
$ptr[$idx]['params'] = $params;
         
$ptr[$idx]['data'] = '';
         
$ptr[$idx]['cnt'] = 0;
         return 
$pstr.'['.$idx.']';
     }


   
# add_identification
   #   Only reason this was made was for compliance with possible future options
   #   of surepay/telecheck accepting any other than drivers license.

     
function add_identification (
         
$pstr,     # Object identifier
         
$params )  # Array: id parameters
     
{
         
# Change/add to these if future types are added
         
$validtypes = array( 'driverslicense' );
         
$required['driverslicense'] = array('number','issuedby');

         if ( !
$params['type'] ) { $this->err 'Identification type not specified'; }
         elseif ( !
in_array( ($params['type'] = strtolower($params['type'])) ,$validtypes )) {
             
$this->err 'Identification type not valid'
         }
         else {
             while ((
$row each($required[$params['type']])) && !$this->err) {
                 if (!
$params[$row[1]]) {
                     
$this->err 'Required argument '.$row[1].' was not given to add_identification';
                 }
             }
             if (!
$this->err) {
                 eval(
$this->peval($pstr));
                 
$idx = ++$ptr['cnt'];
                 
$ptr[$idx]['type'] = 'pp.identification';
                 
$ptr[$idx]['params'] = $params;
                 
$ptr[$idx]['data'] = '';
                 
$ptr[$idx]['cnt'] = 0;
                 return 
$pstr.'['.$idx.']';
             }
         }
     }


   
# peval : Create eval ready string for object pointers
   # This is sort of a trick, only way I found at the moment to 
   # make a reliable/re-usable ref to array inside object
   
     
function peval ($pstr) {
         return 
'$ptr = & $this->request["request"]'.$pstr.';';
     }
 

  
# parse : parses xml data and create a multidim array of the data.

  
function parse($xmldata) { 
    
# This was just copied from version 0.0.1 with a few minor changes.
    // The whole XML parser here got started off the wrong way. It works, but it is not very
    // maintainable for possible future releases of the surepay XML DTD, if more levels
    // are added or sub tags and so on. The xml parsing could need some rethinking.
    
$this->parse_lvl "0";
    
$this->parse_mother "/";
    
$this->responseattr = array();
    
$this->responsedata = array();
    
$this->parseerr 0;
    
$this->last_char_data '';
    if (!
preg_match ('/^<!DOCTYPE .*>/',$xmldata,$dtd)) {
        
$this->err "No DOCTYPE declaration/dtd found in XML data";
    }
    
$this->parse_dtd $dtd[0];
    if ( !
$this->err && !($dtd[0] == $this->xmldtd($this->response_dtd))) {
        
$this->err "DOCTYPE declaration/dtd not supported (New version?)";
    }
    if ( !
$this->err ) {
        
$this->parse_parser xml_parser_create();    //Create the object
        
xml_set_object($this->parse_parser,&$this);    //Reference to the object from this object
        
xml_set_element_handler($this->parse_parser,"startElement","endElement");
        
xml_set_character_data_handler($this->parse_parser,"chdata");
        if (!
xml_parse($this->parse_parser$xmldata)) {
            
$this->parse_err =  sprintf("XML response data error: %s at line %d",
                   
xml_error_string(xml_get_error_code($this->parse_parser)),
                   
xml_get_current_line_number($this->parse_parser));
        }
        
xml_parser_free($this->parse_parser); 
        if (!
$this->err ) { return $this->count_auth_response(); }
        
$this->err preg_replace('/{sp.text}/',$this->last_char_data,$this->err);
    }
  }
  
   function 
startElement($parser$name$attrib) {
     if ((
$this->parse_mother == '/') && !( $name == $this->parse_xmlroot)) {
        
$this->err 'Unknown root element in XML response data';
     }
     elseif ( 
$this->parse_lvl >= ) {
       if (
in_array($name,$this->parse_responsetypes)) {
          
$this->parse_current_order $attrib['ORDERNUMBER'];
          if (
$this->parse_current_order) { 
                
$this->responseattr[$name][$this->parse_current_order] = $attrib;
                if (
$attrib['AUTHSTATUS'] == 'AUTH') { $this->parse_auth[$attrib['ORDERNUMBER']] = true; }
                else { 
$this->parse_auth[$attrib['ORDERNUMBER']] = false; }
          }
          else { 
             
$this->err 'No order number response. Gateway said: {sp.text}'
             
$this->parseerr 1;
          }
       }
       else { 
$this->err "Unknown response type $name"; }
     }
     
$this->parse_mother $name;
     
$this->parse_lvl++;
   }

   function 
endElement($parser$name) {
       if ( 
$this->parse_lvl <= ) { $this->parse_mother '/'; }
       elseif ( 
$this->parse_lvl == ) { $this->parse_mother =  $this->parse_xmlroot; }
       else { 
$this->err 'Too many levels in XML data (' $this->parse_lvl ')'; }
       
$this->parse_lvl--;
   }

   function 
chdata($parser,$chdata) {
       if (!
$this->parseerr && trim($chdata) && (in_array($this->parse_mother,$this->parse_responsetypes))) {
          
$this->responsedata[$this->parse_mother][$this->parse_current_order] = trim($chdata);
       }
       else {
         
$this->last_char_data .= trim($chdata);
         
$this->parseerr 0;
       }
   }

# End of class
   

?>