/** * Sends request and receive response from eWAY payment process. * * @param array $params * * @return array|object * @throws \Exception */ public function doDirectPayment(&$params) { if (CRM_Utils_Array::value('is_recur', $params) == TRUE) { CRM_Core_Error::fatal(ts('eWAY - recurring payments not implemented')); } if (!defined('CURLOPT_SSLCERT')) { CRM_Core_Error::fatal(ts('eWAY - Gateway requires curl with SSL support')); } // eWAY Client ID $ewayCustomerID = $this->_paymentProcessor['user_name']; // eWAY Gateway URL $gateway_URL = $this->_paymentProcessor['url_site']; //------------------------------------ // create eWAY gateway objects //------------------------------------ $eWAYRequest = new GatewayRequest(); if ($eWAYRequest == NULL || !$eWAYRequest instanceof GatewayRequest) { return self::errorExit(9001, "Error: Unable to create eWAY Request object."); } $eWAYResponse = new GatewayResponse(); if ($eWAYResponse == NULL || !$eWAYResponse instanceof GatewayResponse) { return self::errorExit(9002, "Error: Unable to create eWAY Response object."); } /* //------------------------------------------------------------- // NOTE: eWAY Doesn't use the following at the moment: //------------------------------------------------------------- $creditCardType = $params['credit_card_type']; $currentcyID = $params['currencyID']; $country = $params['country']; */ //------------------------------------------------------------- // Prepare some composite data from _paymentProcessor fields //------------------------------------------------------------- $fullAddress = $params['street_address'] . ", " . $params['city'] . ", " . $params['state_province'] . "."; $expireYear = substr($params['year'], 2, 2); $expireMonth = sprintf('%02d', (int) $params['month']); // CiviCRM V1.9 - Picks up reasonable description //$description = $params['amount_level']; // CiviCRM V2.0 - Picks up description $description = $params['description']; $txtOptions = ""; $amountInCents = round((double) $params['amount'] * 100); $credit_card_name = $params['first_name'] . " "; if (strlen($params['middle_name']) > 0) { $credit_card_name .= $params['middle_name'] . " "; } $credit_card_name .= $params['last_name']; //---------------------------------------------------------------------------------------------------- // We use CiviCRM's param's 'invoiceID' as the unique transaction token to feed to eWAY // Trouble is that eWAY only accepts 16 chars for the token, while CiviCRM's invoiceID is an 32. // As its made from a "$invoiceID = md5(uniqid(rand(), true));" then using the fierst 16 chars // should be alright //---------------------------------------------------------------------------------------------------- $uniqueTrnxNum = substr($params['invoiceID'], 0, 16); //---------------------------------------------------------------------------------------------------- // OPTIONAL: If TEST Card Number force an Override of URL and CutomerID. // During testing CiviCRM once used the LIVE URL. // This code can be uncommented to override the LIVE URL that if CiviCRM does that again. //---------------------------------------------------------------------------------------------------- // if ( ( $gateway_URL == "https://www.eway.com.au/gateway_cvn/xmlpayment.asp") // && ( $params['credit_card_number'] == "4444333322221111" ) ) { // $ewayCustomerID = "87654321"; // $gateway_URL = "https://www.eway.com.au/gateway_cvn/xmltest/testpage.asp"; // } //---------------------------------------------------------------------------------------------------- // Now set the payment details - see http://www.eway.com.au/Support/Developer/PaymentsRealTime.aspx //---------------------------------------------------------------------------------------------------- // 8 Chars - ewayCustomerID - Required $eWAYRequest->EwayCustomerID($ewayCustomerID); // 12 Chars - ewayTotalAmount (in cents) - Required $eWAYRequest->InvoiceAmount($amountInCents); // 50 Chars - ewayCustomerFirstName $eWAYRequest->PurchaserFirstName($params['first_name']); // 50 Chars - ewayCustomerLastName $eWAYRequest->PurchaserLastName($params['last_name']); // 50 Chars - ewayCustomerEmail $eWAYRequest->PurchaserEmailAddress($params['email']); // 255 Chars - ewayCustomerAddress $eWAYRequest->PurchaserAddress($fullAddress); // 6 Chars - ewayCustomerPostcode $eWAYRequest->PurchaserPostalCode($params['postal_code']); // 1000 Chars - ewayCustomerInvoiceDescription $eWAYRequest->InvoiceDescription($description); // 50 Chars - ewayCustomerInvoiceRef $eWAYRequest->InvoiceReference($params['invoiceID']); // 50 Chars - ewayCardHoldersName - Required $eWAYRequest->CardHolderName($credit_card_name); // 20 Chars - ewayCardNumber - Required $eWAYRequest->CardNumber($params['credit_card_number']); // 2 Chars - ewayCardExpiryMonth - Required $eWAYRequest->CardExpiryMonth($expireMonth); // 2 Chars - ewayCardExpiryYear - Required $eWAYRequest->CardExpiryYear($expireYear); // 4 Chars - ewayCVN - Required if CVN Gateway used $eWAYRequest->CVN($params['cvv2']); // 16 Chars - ewayTrxnNumber $eWAYRequest->TransactionNumber($uniqueTrnxNum); // 255 Chars - ewayOption1 $eWAYRequest->EwayOption1($txtOptions); // 255 Chars - ewayOption2 $eWAYRequest->EwayOption2($txtOptions); // 255 Chars - ewayOption3 $eWAYRequest->EwayOption3($txtOptions); $eWAYRequest->CustomerIPAddress($params['ip_address']); $eWAYRequest->CustomerBillingCountry($params['country']); // Allow further manipulation of the arguments via custom hooks .. CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $eWAYRequest); //---------------------------------------------------------------------------------------------------- // Check to see if we have a duplicate before we send //---------------------------------------------------------------------------------------------------- if ($this->checkDupe($params['invoiceID'], CRM_Utils_Array::value('contributionID', $params))) { return self::errorExit(9003, 'It appears that this transaction is a duplicate. Have you already submitted the form once? If so there may have been a connection problem. Check your email for a receipt from eWAY. If you do not receive a receipt within 2 hours you can try your transaction again. If you continue to have problems please contact the site administrator.'); } //---------------------------------------------------------------------------------------------------- // Convert to XML and send the payment information //---------------------------------------------------------------------------------------------------- $requestxml = $eWAYRequest->ToXML(); $submit = curl_init($gateway_URL); if (!$submit) { return self::errorExit(9004, 'Could not initiate connection to payment gateway'); } curl_setopt($submit, CURLOPT_POST, TRUE); // return the result on success, FALSE on failure curl_setopt($submit, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($submit, CURLOPT_POSTFIELDS, $requestxml); curl_setopt($submit, CURLOPT_TIMEOUT, 36000); // if open_basedir or safe_mode are enabled in PHP settings CURLOPT_FOLLOWLOCATION won't work so don't apply it // it's not really required CRM-5841 if (ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) { // ensures any Location headers are followed curl_setopt($submit, CURLOPT_FOLLOWLOCATION, 1); } // Send the data out over the wire //-------------------------------- $responseData = curl_exec($submit); //---------------------------------------------------------------------------------------------------- // See if we had a curl error - if so tell 'em and bail out // // NOTE: curl_error does not return a logical value (see its documentation), but // a string, which is empty when there was no error. //---------------------------------------------------------------------------------------------------- if (curl_errno($submit) > 0 || strlen(curl_error($submit)) > 0) { $errorNum = curl_errno($submit); $errorDesc = curl_error($submit); // Paranoia - in the unlikley event that 'curl' errno fails if ($errorNum == 0) { $errorNum = 9005; } // Paranoia - in the unlikley event that 'curl' error fails if (strlen($errorDesc) == 0) { $errorDesc = "Connection to eWAY payment gateway failed"; } return self::errorExit($errorNum, $errorDesc); } //---------------------------------------------------------------------------------------------------- // If null data returned - tell 'em and bail out // // NOTE: You will not necessarily get a string back, if the request failed for // any reason, the return value will be the boolean false. //---------------------------------------------------------------------------------------------------- if ($responseData === FALSE || strlen($responseData) == 0) { return self::errorExit(9006, "Error: Connection to payment gateway failed - no data returned."); } //---------------------------------------------------------------------------------------------------- // If gateway returned no data - tell 'em and bail out //---------------------------------------------------------------------------------------------------- if (empty($responseData)) { return self::errorExit(9007, "Error: No data returned from payment gateway."); } //---------------------------------------------------------------------------------------------------- // Success so far - close the curl and check the data //---------------------------------------------------------------------------------------------------- curl_close($submit); //---------------------------------------------------------------------------------------------------- // Payment successfully sent to gateway - process the response now //---------------------------------------------------------------------------------------------------- $eWAYResponse->ProcessResponse($responseData); //---------------------------------------------------------------------------------------------------- // See if we got an OK result - if not tell 'em and bail out //---------------------------------------------------------------------------------------------------- if (self::isError($eWAYResponse)) { $eWayTrxnError = $eWAYResponse->Error(); CRM_Core_Error::debug_var('eWay Error', $eWayTrxnError, TRUE, TRUE); if (substr($eWayTrxnError, 0, 6) == "Error:") { return self::errorExit(9008, $eWayTrxnError); } $eWayErrorCode = substr($eWayTrxnError, 0, 2); $eWayErrorDesc = substr($eWayTrxnError, 3); return self::errorExit(9008, "Error: [" . $eWayErrorCode . "] - " . $eWayErrorDesc . "."); } //----------------------------------------------------------------------------------------------------- // Cross-Check - the unique 'TrxnReference' we sent out should match the just received 'TrxnReference' // // PLEASE NOTE: If this occurs (which is highly unlikely) its a serious error as it would mean we have // received an OK status from eWAY, but their Gateway has not returned the correct unique // token - ie something is broken, BUT money has been taken from the client's account, // so we can't very well error-out as CiviCRM will then not process the registration. // There is an error message commented out here but my preferred response to this unlikley // possibility is to email '*****@*****.**' //----------------------------------------------------------------------------------------------------- $eWayTrxnReference_OUT = $eWAYRequest->GetTransactionNumber(); $eWayTrxnReference_IN = $eWAYResponse->InvoiceReference(); if ($eWayTrxnReference_IN != $eWayTrxnReference_OUT) { // return self::errorExit( 9009, "Error: Unique Trxn code was not returned by eWAY Gateway. This is extremely unusual! Please contact the administrator of this site immediately with details of this transaction."); } /* //---------------------------------------------------------------------------------------------------- // Test mode always returns trxn_id = 0 - so we fix that here // // NOTE: This code was taken from the AuthorizeNet payment processor, however it now appears // unnecessary for the eWAY gateway - Left here in case it proves useful //---------------------------------------------------------------------------------------------------- if ( $this->_mode == 'test' ) { $query = "SELECT MAX(trxn_id) FROM civicrm_contribution WHERE trxn_id LIKE 'test%'"; $p = array( ); $trxn_id = strval( CRM_Core_Dao::singleValueQuery( $query, $p ) ); $trxn_id = str_replace( 'test', '', $trxn_id ); $trxn_id = intval($trxn_id) + 1; $params['trxn_id'] = sprintf('test%08d', $trxn_id); } else { $params['trxn_id'] = $eWAYResponse->TransactionNumber(); } */ //============= // Success ! //============= $beaglestatus = $eWAYResponse->BeagleScore(); if (!empty($beaglestatus)) { $beaglestatus = ": " . $beaglestatus; } $params['trxn_result_code'] = $eWAYResponse->Status() . $beaglestatus; $params['gross_amount'] = $eWAYResponse->Amount(); $params['trxn_id'] = $eWAYResponse->TransactionNumber(); return $params; }
/** * Process a one-off payment and return result or throw exception. * * @param $params * * @return array * Result of payment. * @throws \CRM_Core_Exception */ protected function processSinglePayment(&$params) { $eWAYRequest = $this->getEwayRequest($params); if ($this->getDummySuccessResult()) { return $this->getDummySuccessResult(); } $eWAYResponse = new GatewayResponse(); if ($eWAYResponse == NULL || !$eWAYResponse instanceof GatewayResponse) { throw new CRM_Core_Exception("Error: Unable to create eWAY Response object."); } //---------------------------------------------------------------------------------------------------- // Convert to XML and send the payment information //---------------------------------------------------------------------------------------------------- $requestXML = $eWAYRequest->ToXML(); $responseData = $this->callEwayGateway($requestXML); //---------------------------------------------------------------------------------------------------- // Payment successfully sent to gateway - process the response now //---------------------------------------------------------------------------------------------------- $eWAYResponse->ProcessResponse($responseData); //---------------------------------------------------------------------------------------------------- // See if we got an OK result - if not tell 'em and bail out //---------------------------------------------------------------------------------------------------- if (self::isError($eWAYResponse)) { $eWayTrxnError = $eWAYResponse->Error(); if (substr($eWayTrxnError, 0, 6) == "Error:") { throw new CRM_Core_Exception($eWayTrxnError); } $eWayErrorCode = substr($eWayTrxnError, 0, 2); $eWayErrorDesc = substr($eWayTrxnError, 3); throw new CRM_Core_Exception("Error: [" . $eWayErrorCode . "] - " . $eWayErrorDesc . "."); } //----------------------------------------------------------------------------------------------------- // Cross-Check - the unique 'TrxnReference' we sent out should match the just received 'TrxnReference' // // PLEASE NOTE: If this occurs (which is highly unlikely) its a serious error as it would mean we have // received an OK status from eWAY, but their Gateway has not returned the correct unique // token - ie something is broken, BUT money has been taken from the client's account, // so we can't very well error-out as CiviCRM will then not process the registration. // There is an error message commented out here but my preferred response to this unlikely // possibility is to email '*****@*****.**' //----------------------------------------------------------------------------------------------------- $eWayTrxnReference_OUT = $params['invoiceID']; $eWayTrxnReference_IN = $eWAYResponse->InvoiceReference(); if ($eWayTrxnReference_IN != $eWayTrxnReference_OUT) { // return self::errorExit( 9009, "Error: Unique Trxn code was not returned by eWAY Gateway. This is extremely unusual! Please contact the administrator of this site immediately with details of this transaction."); self::send_alert_email($eWAYResponse->TransactionNumber(), $eWayTrxnReference_OUT, $eWayTrxnReference_IN, $requestXML, $responseData); } $status = $eWAYResponse->BeagleScore() ? $eWAYResponse->Status() . ': ' . $eWAYResponse->BeagleScore() : $eWAYResponse->Status(); $result = array('gross_amount' => $eWAYResponse->Amount(), 'trxn_id' => $eWAYResponse->TransactionNumber(), 'trxn_result_code' => $status, 'payment_status_id' => 1); return $result; }
protected function createGatewayResponse() { $gatewayresponse = new GatewayResponse($this->payment); $gatewayresponse->setRedirectURL($this->getRedirectURL()); return $gatewayresponse; }
if ($transaction_types[$trans_type] == 'AUTH_CAPTURE') { $service_response = $service->PerformPurchase($request, $response); $transaction_type = 'sale'; } elseif ($transaction_types[$trans_type] == 'AUTH_ONLY') { $service_response = $service->PerformAuthOnly($request, $response); $transaction_type = 'auth'; } // Gateway answered $pp_response = array(); if ($response->Get(GatewayResponse::RESPONSE_CODE()) == GatewayCodes__RESPONSE_SUCCESS) { // check CVV2 response $cvv_code = $response->Get(GatewayResponse::CVV2_CODE()); switch ($cvv_code) { case 'N': case 'P': case 'S': case 'U': $pp_response['order_status'] = 'F'; $pp_response['reason_text'] = $processor_error['cvv'][$cvv_code]; break; default: $pp_response['order_status'] = 'P'; $pp_response['reason_text'] = ''; break; } } else { $pp_response['order_status'] = 'F'; $pp_response['reason_text'] = $tran_error[$response->Get(GatewayResponse::REASON_CODE())]; } $pp_response['transaction_id'] = $response->Get(GatewayResponse::TRANSACT_ID());
/** * Low level HTTP request. * * @param $method the HTTP method type i.e., GET, * POST, PUT, and DELETE. * @param $endpoint the HTTP endpoint url to invoke. * @param $params the HTTP request parameters. * @param $secure TRUE if HTTP Basic Authentication * is required. * * @return GatewayResponse with the disposition of * invoking the specified endpoint. */ public function call($method, $endpoint, $params, $secure) { $curl = curl_init(); // prepare HTTP GET if ($method == 'GET') { if (count($params) != 0) { $endpoint .= '?' . $params; } } curl_setopt($curl, CURLOPT_URL, $endpoint); curl_setopt($curl, CURLOPT_FOLLOWLOCATION, TRUE); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); // prepare credentials (HTTP format) if ($secure) { curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($curl, CURLOPT_USERPWD, $this->getCredentials()); } // prepare HTTP POST if ($method == 'POST') { curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_POSTFIELDS, $params); } // prepare HTTP PUT (not supported) if ($method == 'PUT') { /* curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT'); curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Length: '.strlen($this->getPayload()))); curl_setopt($curl, CURLOPT_POSTFIELDS, $payload); */ } // prepare HTTP DEL (needs to be tested) if ($method == 'DEL') { curl_setopt($curl, CURLOPT_HEADER, 0); curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-Type:application/atom+xml")); curl_setopt($curl, CURLOPT_FAILONERROR, TRUE); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE'); } if ($method == 'JSON') { curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/json', 'Content-Type: application/json')); curl_setopt($curl, CURLOPT_POSTFIELDS, $params); } // prepare default headers curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE); //curl_setopt($curl, CURLOPT_HTTPHEADER, array('Expect:')); // invoke HTTP request $data = curl_exec($curl); $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); curl_close($curl); $response = new GatewayResponse(); $response->setData($data); $response->setHttpStatus($status); $response->setRequest($params); $response->setEndpoint($endpoint); try { // track gateway operation /* $event = new GatewayTracker(); $event->partner = $this->getPartnerName(); $event->endpoint = $this->getEndpoint(); $event->method = $method; $event->payload = $params; $event->response = htmlspecialchars($data, ENT_COMPAT); $event->status = $status; $event->credentials = $this->getCredentials(); $event->saveOrUpdate(); */ } catch (Exception $exception) { // TODO: fire email notification. echo "Failed to track: " . $exception->getMessage(); } return $response; }
public function PerformCURLTransaction($host, $request, $response) { // // Reset the response object and turn the request into // a string that can be transmitted. // $response->Reset(); // Clear old contents $requestBytes = $request->ToXMLString(); // Change to XML request // // Gather override attibutes used for the connection URL. // $urlServlet = $request->Get("gatewayServlet"); $urlProtocol = $request->Get("gatewayProtocol"); $urlPortNo = $request->Get("gatewayPortNo"); // // If the parameters were not set in the request, // use the system defaults. // if ($urlServlet == NULL) { $urlServlet = $this->rocketGateServlet; } if ($urlProtocol == NULL) { $urlProtocol = $this->rocketGateProtocol; } if ($urlPortNo == NULL) { $urlPortNo = $this->rocketGatePortNo; } // // Build the URL for the gateway service. // $url = $urlProtocol . "://" . $host . ":" . $urlPortNo . "/" . $urlServlet; // Add servlet path // // Gather the override timeout values that will be used // for the connection. // $connectTimeout = $request->Get("gatewayConnectTimeout"); $readTimeout = $request->Get("gatewayReadTimeout"); // // Use default values if the parameters were not set. // if ($connectTimeout == NULL) { // No connect timeout specified? $connectTimeout = $this->rocketGateConnectTimeout; } if ($readTimeout == NULL) { $readTimeout = $this->rocketGateReadTimeout; } // // Create a handle that can be used for the URL operation. // if (!($handle = curl_init())) { // Failed to initialize? $response->Set(GatewayResponse::EXCEPTION(), "curl_init() error"); $response->SetResults(GatewayCodes__RESPONSE_REQUEST_ERROR, GatewayCodes__REASON_INVALID_URL); return GatewayCodes__RESPONSE_REQUEST_ERROR; } // // Set timeout values used in the operation. // curl_setopt($handle, CURLOPT_NOSIGNAL, TRUE); curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, $connectTimeout); curl_setopt($handle, CURLOPT_TIMEOUT, $readTimeout); // // Setup verification for SSL connections. // curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, FALSE); // // Setup the call to the URL. // curl_setopt($handle, CURLOPT_POST, TRUE); curl_setopt($handle, CURLOPT_POSTFIELDS, $requestBytes); curl_setopt($handle, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($handle, CURLOPT_URL, $url); curl_setopt($handle, CURLOPT_FAILONERROR, TRUE); ////////////////////////////////////////////////////////////////////// // // 04-30-2013 darcy // // Updated user agent. // // 12-20-2011 darcy // // Updated user agent. // // 08-25-2011 darcy // // Updated user agent. // // 05-31-2009 darcy // // Updated the user agent. // // 04-27-2009 darcy // // Set the user-agent. // // curl_setopt($handle, CURLOPT_USERAGENT, "RG PHP Client 2.0"); // curl_setopt($handle, CURLOPT_USERAGENT, "RG PHP Client 2.1"); // curl_setopt($handle, CURLOPT_USERAGENT, "RG PHP Client 3.0"); // ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // // 2/21/2010 Jason. Set content-type. // curl_setopt($handle, CURLOPT_HTTPHEADER, array("Content-Type: text/xml")); ////////////////////////////////////////////////////////////////////// // // Execute the operation. // $results = curl_exec($handle); // Execute the operation if (!$results) { // Did it fail? $errorCode = curl_errno($handle); // Get the error code $errorString = curl_error($handle); // Get the error text curl_close($handle); // Done with handle // // Translate the CURL error code into a Gateway code. // switch ($errorCode) { // Classify error code case CURLE_SSL_CONNECT_ERROR: // Connection failures // Connection failures case CURLE_COULDNT_CONNECT: $internalCode = GatewayCodes__REASON_UNABLE_TO_CONNECT; break; // Done with request // Done with request case CURLE_SEND_ERROR: // Failed sending data $internalCode = GatewayCodes__REASON_REQUEST_XMIT_ERROR; break; // Done with request // Done with request case CURLE_OPERATION_TIMEOUTED: // Time-out reached $internalCode = GatewayCodes__REASON_RESPONSE_READ_TIMEOUT; break; // Done with request // Done with request case CURLE_RECV_ERROR: // Failed reading data // Failed reading data case CURLE_READ_ERROR: default: $internalCode = GatewayCodes__REASON_RESPONSE_READ_ERROR; } // // If the operation failed, return an error code. // if (strlen($errorString) != 0) { // Have an error? $response->Set(GatewayResponse::EXCEPTION(), $errorString); } $response->SetResults(GatewayCodes__RESPONSE_SYSTEM_ERROR, $internalCode); return GatewayCodes__RESPONSE_SYSTEM_ERROR; } // // Parse the returned message into the response // object. // curl_close($handle); // Done with handle $response->SetFromXML($results); // Set response return $response->Get(GatewayResponse::RESPONSE_CODE()); }
public function SetFromXML($xmlString) { // // Create a parser for the XML. // $parser = xml_parser_create(''); xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); // // Parse the input string. If there is an error, // note it in the response. // if (xml_parse_into_struct($parser, $xmlString, $vals, $index) == 0) { $this->Set(GatewayResponse::EXCEPTION(), xml_error_string(xml_get_error_code($parser))); $this->SetResults(GatewayCodes__RESPONSE_SYSTEM_ERROR, GatewayCodes__REASON_XML_ERROR); xml_parser_free($parser); // Release the parser return; // And we're done } // // Loop over the items in the XML document and // save them in the response. // foreach ($vals as $val) { // Loop over elements if (isset($val['value'])) { // Is value set? $this->Set($val['tag'], $val['value']); } // Save in parameters } // // Release the parser and quit. // xml_parser_free($parser); // Release the parser }