|
Fatal error: Call to a member function asXml() on a non-object in
Hi Coding gurus,
I have downloaded a script to work with Worldpay to show how to make direct payments, After making a few modifications of my own I realised it does not actually work I get the error:
ERROR: "Fatal error: Call to a member function asXml() on a non-object in \WPDirect\WPDirect.php on line 889"
There is a few pages so I have attached the one which causes the problem, please let me know if you need any more to help me solve the problem, I have tried printing information to get to the bottom but I am not having much luck!!
PHP Code:
<?php
require_once('WPPaymentDetails.php');
require_once('IssuerForm.php');
/**
* WPDirect
*
* @package wpdirect
* @version $id$
* @copyright 2009 Peter Reisinger
* @author Peter Reisinger <p.reisinger@gmail.com>
* @license GNU General Public License
*/
class WPDirect
{
/**
* xml file - skeleton for request
*/
const REQUEST_FILE = '/xml/request.xml';
/**
* testEnv
*
* if true than uses test environment
*
* @var boolean
* @access private
*/
private $testEnv;
/**
* merchantCode
*
* login name as well
*
* @var string
* @access private
*/
private $merchantCode;
/**
* installationId
*
* password for login as well
*
* @var string
* @access private
*/
private $installationId;
/**
* password
*
* usually the same as installationId
*
* @var <type>
* @access private
*/
private $password;
/**
* cookieFolder
*
* folder to hold cookies for requests
*
* @var string
* @access private
*/
private $cookieFolder;
/**
* errorLogFile
*
* error log file
*
* @var string
* @access private
*/
private $errorLogFile;
/**
* orderCode
*
* unique value for every request
*
* @var string unique value
* @access private
*/
private $orderCode;
/**
* description
*
* @var string
* @access private
*/
private $description;
/**
* currency
*
* default currency
*
* @var string
* @access private
*/
private $currency = 'GBP';
/**
* value
*
* total value - !!! value is withoud comma or dot
* so 15.45 is 1545 and 15 would be 1500
*
* @var int
* @access private
*/
private $value;
/**
* orderContent
*
* can be html but no script
*
* @var mixed
* @access private
*/
private $orderContent;
/**
* paymentDetails
*
* object of appropriate payment detail
*
* @var object
* @access private
*/
private $paymentDetails;
/**
* shopper
*
* shopper element
*
* @var array
* @access private
*/
private $shopper = array();
/**
* shippingAddress
*
* @var array
* @access private
*/
private $shippingAddress;
public function __construct()
{
// --- default values ---
$this->testEnv = true; // change!!!
$this->merchantCode = ''; // change!!!
$this->installationId = ''; // change!!!
$this->password = ''; // change!!!
// set default files
$this->cookieFolder = dirname(__FILE__).'/cookie-file/';
$this->errorLogFile = dirname(__FILE__). '/log/error-log.txt';
if (!is_writable($this->errorLogFile)) {
trigger_error('File'.$this->errorLogFile.' is not readable/writable', E_USER_NOTICE);
}
// cookie folder check if it's writable, readable
if (@file_put_contents($this->cookieFolder.'test.txt', '') === FALSE) {
trigger_error('Folder '.$this->cookieFolder.' is not readable/writable', E_USER_NOTICE);
}
if (!is_writable($this->cookieFolder.'test.txt')) {
trigger_error('File'.$this->errorLogFile.' is not readable/writable', E_USER_NOTICE);
}
if (!is_readable($this->cookieFolder.'test.txt')) {
trigger_error('File'.$this->errorLogFile.' is not readable/writable', E_USER_NOTICE);
}
// if somebody changes default currency then appropriate exponent is loaded
$this->setCurrency($this->currency);
/*
if (strlen($description) > 255) {
trigger_error('Description can be max 255 characters long', E_USER_ERROR);
}
*/
// set session if is not set
if (!isset($_SESSION)) {
session_start();
}
}
/**
* setTestEnv
*
* @param boolean $test
* @access public
* @return void
*/
public function setTestEnv($test)
{
$this->testEnv = ($test) ? true : false;
}
/**
* setMerchantCode
*
* @param string $merchantCode
* @access public
* @return void
*/
public function setMerchantCode($merchantCode)
{
$this->merchantCode = $merchantCode;
}
/**
* setInstallationId
*
* @param string $installationId
* @access public
* @return void
*/
public function setInstallationId($installationId)
{
$this->installationId = $installationId;
}
/**
* setPassword
*
* @param string $password
* @access public
* @return void
*/
public function setPassword($password)
{
$this->password = $password;
}
/**
* setOrderCode
*
* this must be unique for every request
* and is compulsory for first request
* pattern - (^[^\s\'\"\<\>]{1,64}$)
*
* @param string $orderCode unique for every request
* @access public
* @return void
*/
public function setOrderCode($orderCode)
{
$pattern = '/(^[^\s\'\"\<\>]{1,64}$)/'; // pattern for orderCode
if (!preg_match($pattern, $orderCode)) {
trigger_error('Order code has to be in this patter: '.$pattern, E_USER_ERROR);
}
$this->orderCode = $orderCode;
}
/**
* setDescription
*
* compulsory for the first request
*
* @param string $description
* @access public
* @return void
*/
public function setDescription($description)
{
$this->description = $description;
}
/**
* setValue
*
* compulsory for the first request
*
* @param integer $value amount to be paid
* @access public
* @return void
*/
public function setValue($value)
{
// checks if it is integer - cannot check just is_int, because
// if input is from post, then it's string
if (!preg_match('/^\d+$/', $value)) {
pr2($value);
trigger_error('value has to be integer, 14.95 is 1495, 15 is 1500, etc.', E_USER_ERROR);
}
$this->value = $value;
}
/**
* isValidAddress
*
* helper method - checks if address fields are valid
*
* allowed values:
* --- compulsory ---
* - street
* - postalCode
* - countryCode
* --- optional ---
* - firstName
* - lastName
* - houseName
* - houseNumber
* - houseNumberExtension
* - city
* - state
* - telephoneNumber
*
* @param array $address
* @access private
* @return boolean
*/
private function isValidAddress(array $address)
{
$valid = true;
// --- allowed fields, true is compulsory, false is optional ---
$addressFields = array(
'firstName' => false, 'lastName' => false,
'street' => true, 'houseName' => false,
'houseNumber' => false, 'houseNumberExtension' => false,
'postalCode' => true, 'city' => false,
'state' => false, 'countryCode' => true,
'telephoneNumber' => false
);
// --- check compulsory fields ---
foreach ($addressFields as $key => $value) {
if ($value) {
if (!isset($address[$key])) {
$valid = false;
trigger_error($key . ' address field is compulsory', E_USER_ERROR);
}
}
}
// --- check fields ---
foreach ($address as $key => $value) {
if (!isset($addressFields[$key])) {
$valid = false;
trigger_error($key . ' address field is not allowed', E_USER_ERROR);
}
}
return $valid;
}
/**
* setShippingAddress
*
* allowed values:
* --- compulsory ---
* - street
* - postalCode
* - countryCode
* --- optional ---
* - firstName
* - lastName
* - houseName
* - houseNumber
* - houseNumberExtension
* - city
* - state
* - telephoneNumber
*
* @param array $address
* @access public
* @return void
*/
public function setShippingAddress(array $address)
{
if ($this->isValidAddress($address)) {
$this->shippingAddress['address'] = $address;
}
}
/**
* setOrderContent
*
* can be html, but no script, max 10kb
*
* @param string $orderContent can be HTML
* @access public
* @return void
*/
public function setOrderContent($orderContent)
{
$this->orderContent = $orderContent;
}
/**
* setShopperEmailAddress
*
* inside shopper element
*
* @param string $shopperEmailAddress
* @access public
* @return void
*/
public function setShopperEmailAddress($shopperEmailAddress)
{
$this->shopper['shopperEmailAddress'] = $shopperEmailAddress;
}
/**
* setAuthenticatedShopperID
*
* inside shopper element
*
* @param mixed $authenticatedShopperID
* @access public
* @return void
*/
public function setAuthenticatedShopperID($authenticatedShopperID)
{
$this->shopper['authenticatedShopperID'] = $authenticatedShopperID;
}
/**
* setCookieFolder
*
* use if you need to use differnt folder for
* curl cookies
*
* @param string $path full path
* @access public
* @return void
*/
public function setCookieFolder($path)
{
$this->cookieFolder = $path;
// cookie folder check if it's writable, readable
if (!file_put_contents($this->cookieFolder.'test.txt', '')) {
trigger_error('Folder '.$this->cookieFolder.' is not readable/writable', E_USER_NOTICE);
}
if (!is_writable($this->cookieFolder.'test.txt')) {
trigger_error('File'.$this->errorLogFile.' is not readable/writable', E_USER_NOTICE);
}
if (!is_readable($this->cookieFolder.'test.txt')) {
trigger_error('File'.$this->errorLogFile.' is not readable/writable', E_USER_NOTICE);
}
}
/**
* setErrorLogFile
*
* use only if you need to log errors in different file
*
* @param string $errorLogFile full path
* @access public
* @return void
*/
public function setErrorLogFile($errorLogFile)
{
$this->errorLogFile = $errorLogFile;
if (!is_writable($this->errorLogFile)) {
trigger_error('File'.$this->errorLogFile.' is not readable/writable', E_USER_NOTICE);
}
}
/**
* setCurrency
*
* @param string $currency
* @access public
* @return void
*/
public function setCurrency($currency)
{
$currency = strtoupper($currency);
// --- currency is key and exponent is value ---
$currencies = array(
'ARS' => 2, 'AUD' => 2, 'BRL' => 2, 'CAD' => 2, 'CHF' => 2,
'CLP' => 2, 'CNY' => 2, 'COP' => 2, 'CZK' => 2, 'DKK' => 2,
'EUR' => 2, 'GBP' => 2, 'HKD' => 2, 'HUF' => 2, 'IDR' => 0,
'ISK' => 2, 'JPY' => 2, 'KES' => 2, 'KRW' => 2, 'MXP' => 2,
'MYR' => 2, 'NOK' => 2, 'NZD' => 2, 'PHP' => 2, 'PLN' => 2,
'PTE' => 2, 'SEK' => 2, 'SGD' => 2, 'SKK' => 2, 'THB' => 2,
'TWD' => 2, 'USD' => 2, 'VND' => 2, 'ZAR' => 2);
if (!isset($currencies[$currency])) {
trigger_error('This currency is not allowed', E_USER_ERROR);
}
$this->exponent = $currencies[$currency];
$this->currency = $currency;
}
/*
+---------------------------------------------------------------+
| Payment methods: |
|================================================= ==============|
| - setAmexSSLPayment = Amex |
| - setDinersSSLPayment = Diners Card |
| - setElvSSLPayment = ELV |
| - setJcbSSLPayment = JCB Card |
| - setEcmcSSLPayment = MasterCard |
| - setSoloGbSSLPayment = Solo Card |
| - setMaestroSSLPayment = Maestro |
| - setVisaSSLPayment = Visa Card, Visa Delta, |
| Visa Electron, Visa Purchasing |
+---------------------------------------------------------------+
*/
/**
* getAmexSSLPayment
*
* @param string $cardNumber
* @param array $expiryDate array('month' => MM, 'year' => YYYY)
* @param string $cardHolderName
* @static
* @access public
* @return void
*/
public static function getAmexSSLPayment($cardNumber, $expiryDate, $cardHolderName)
{
require_once('AmexSSL.php');
return new AmexSSL($cardNumber, $expiryDate, $cardHolderName);
}
/**
* getDinersSSLPayment
*
* @param string $cardNumber
* @param array $expiryDate array('month' => MM, 'year' => YYYY)
* @param string $cardHolderName
* @static
* @access public
* @return void
*/
public static function getDinersSSLPayment($cardNumber, $expiryDate, $cardHolderName)
{
require_once('DinersSSL.php');
return new DinersSSL($cardNumber, $expiryDate, $cardHolderName);
}
/**
* getElvSSLPayment
*
* @param string $accountHolderName
* @param string $bankAccountNr
* @param string $bankName
* @param string $bankLocation
* @param string $bankLocationId
* @static
* @access public
* @return void
*/
public static function getElvSSLPayment($accountHolderName, $bankAccountNr, $bankName, $bankLocation, $bankLocationId)
{
require_once('ElvSSL.php');
return new ElvSSL($accountHolderName, $bankAccountNr, $bankName, $bankLocation, $bankLocationId);
}
/**
* getJcbSSLPayment
*
* @param string $cardNumber
* @param array $expiryDate array('month' => MM, 'year' => YYYY)
* @param string $cardHolderName
* @static
* @access public
* @return void
*/
public static function getJcbSSLPayment($cardNumber, $expiryDate, $cardHolderName)
{
require_once('JcbSSL.php');
return new JcbSSL($cardNumber, $expiryDate, $cardHolderName);
}
/**
* getEcmcSSLPayment
*
* @param string $cardNumber
* @param array $expiryDate array('month' => MM, 'year' => YYYY)
* @param string $cardHolderName
* @static
* @access public
* @return void
*/
public static function getEcmcSSLPayment($cardNumber, $expiryDate, $cardHolderName)
{
require_once('EcmcSSL.php');
return new EcmcSSL($cardNumber, $expiryDate, $cardHolderName);
}
/**
* getSoloGbSSLPayment
*
* @param string $cardNumber
* @param array $expiryDate array('month' => MM, 'year' => YYYY)
* @param string $cardHolderName
* @param mixed $issueNumber optional
* @param array $startDate optional array('month' => MM, 'year' => YYYY)
* @static
* @access public
* @return void
*/
public static function getSoloGbSSLPayment($cardNumber, $expiryDate, $cardHolderName, $issueNumber = NULL, $startDate = NULL)
{
require_once('SoloGbSSL.php');
return new SoloGbSSL($cardNumber, $expiryDate, $cardHolderName, $issueNumber, $startDate);
}
/**
* getMaestroSSLPayment
*
* @param string $cardNumber
* @param array $expiryDate array('month' => MM, 'year' => YYYY)
* @param string $cardHolderName
* @static
* @access public
* @return void
*/
public static function getMaestroSSLPayment($cardNumber, $expiryDate, $cardHolderName)
{
require_once('MaestroSSL.php');
return new MaestroSSL($cardNumber, $expiryDate, $cardHolderName);
}
/**
* getVisaSSLPayment
*
* @param string $cardNumber
* @param array $expiryDate array('month' => MM, 'year' => YYYY)
* @param string $cardHolderName
* @static
* @access public
* @return void
*/
public static function getVisaSSLPayment($cardNumber, $expiryDate, $cardHolderName)
{
require_once('VisaSSL.php');
return new VisaSSL($cardNumber, $expiryDate, $cardHolderName);
}
/**
* setPayment
*
* @param WPPaymentDetails $paymentDetails
* @access public
* @return void
*/
public function setPayment(WPPaymentDetails $paymentDetails)
{
// --- hold xml ---
$this->paymentDetails = $paymentDetails->getXml();
}
/**
* getResponse
*
* returns response from world pay
* or displays html form for 3D validation
*
* @access public
* @return xml
*/
public function getResponse()
{
// --- second request ---
if (isset($_POST['PaRes'], $_SESSION['WPDirect']['WPRequest'])) {
// load xml (first request) from session
$xml = simplexml_load_string($_SESSION['WPDirect']['WPRequest']);
// set orderCode - so cookie can be deleted after response is received
$this->orderCode = (string) $xml->submit->order->attributes()->orderCode;
// create second request - add some data to the previous request
$xml->submit->order->paymentDetails->addChild('info3DSecure');
$xml->submit->order->paymentDetails->info3DSecure->addChild('paResponse');
$xml->submit->order->paymentDetails->info3DSecure->paResponse = $_POST['PaRes'];
$xml->submit->order->addChild('echoData');
$xml->submit->order->echoData = $_SESSION['WPDirect']['echoData'];
$xml = $xml->asXml();
// --- first request ---
} else {
// check if it is request or not
if (isset($this->paymentDetails)) {
// check if compulsory values has been set
if (!isset($this->orderCode, $this->description, $this->value)) {
trigger_error('You have to set OrderCode, Description and Value before sending request', E_USER_NOTICE);
}
// this is not real request, so just return
} else {
return;
}
$xml = simplexml_load_file(dirname(__FILE__).self::REQUES T_FILE);
// add merchant code
$xml->addAttribute('merchantCode', $this->merchantCode);
// order
$xml->submit->order->addAttribute('orderCode', $this->orderCode);
$xml->submit->order->addAttribute('installationId', $this->installationId);
// description
$xml->submit->order->description = $this->description;
// amount
$xml->submit->order->amount->addAttribute('currencyCode', $this->currency);
$xml->submit->order->amount->addAttribute('exponent', $this->exponent);
$xml->submit->order->amount->addAttribute('value', $this->value);
// 3-D secure order
$xml->submit->order->shopper->addChild('browser');
$xml->submit->order->shopper->browser->addChild('acceptHeader', $_SERVER['HTTP_ACCEPT']);
$xml->submit->order->shopper->browser->addChild('userAgentHeader', $_SERVER['HTTP_USER_AGENT']);
// check if we have more shopper children elements
if (isset($this->shopper)) {
foreach($this->shopper as $key => $value) {
$xml->submit->order->shopper->addChild($key, $value);
}
}
// check if we have shipping address
if (isset($this->shippingAddress)) {
$xml->submit->order->addChild('shippingAddress');
foreach ($this->shippingAddress as $key => $value) {
$xml->submit->order->shippingAddress->addChild($key, $value);
}
}
$xml = $xml->asXml();
// orderContent - CDATA so has to be replaced
$this->orderContent = (isset($this->orderContent)) ? $this->orderContent : ' ';
$xml = trim(str_replace('<?orderContent?>', $this->orderContent, $xml));
// remove xml declaration
$paymentDetails = trim(preg_replace('/<\?xml.*\?>/', '', $this->paymentDetails, 1));
// insert payment details in the xml
$xml = trim(str_replace('<?paymentDetails?>', $paymentDetails, $xml));
}
//echo $xml;exit;
//print_r($xml);exit;
/* +---------------+
| send xml |
+---------------+ */
// changes url if it's testing environment
$url = ($this->testEnv) ? '-test' : '';
$url = 'https://secure'.$url.'.ims.rbsworldpay.com/jsp/merchant/xml/paymentService.jsp';
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($ch, CURLOPT_FRESH_CONNECT,true);
curl_setopt($ch, CURLOPT_USERPWD, $this->merchantCode.":".$this->password);
// second request
if (isset($_POST['PaRes'], $_SESSION['WPDirect']['WPRequest'])) {
// read cookie file
curl_setopt($ch, CURLOPT_COOKIEFILE, $this->cookieFolder.$this->orderCode.'cookie.txt');
// first request
} else {
// write cookie file
curl_setopt($ch, CURLOPT_COOKIEJAR, $this->cookieFolder.$this->orderCode.'cookie.txt');
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1) ;
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_TIMEOUT, 240);
$result = curl_exec($ch);
curl_close($ch);
// --- unset session, delete cookie file ---
if (isset($_POST['PaRes'], $_SESSION['WPDirect']['WPRequest'])) {
// delete cookie file
unlink($this->cookieFolder.$this->orderCode.'cookie.txt');
// delete session
unset($_SESSION['WPDirect']);
}
// --- handle response ---
$result = simplexml_load_string($result);
//print_r($result);exit;
// --- check for errors and if there are any, write them into error log ---
if (isset($result->reply->error) || isset($result->reply->orderStatus->error)) {
// date/time
$output = date('d-m-Y H:i:s').' ';
if (isset($result->reply->error)) {
// error code
$output .= (string) $result->reply->error->attributes()->code.' ';
// error
$output .= (string) $result->reply->error."\n";
} else { // --- this is last response ---
// error code
$output .= (string) $result->reply->orderStatus->error->attributes()->code.' ';
// error
$output .= (string) $result->reply->orderStatus->error."\n";
}
// write to the file
if (!$handle = fopen($this->errorLogFile, 'a')) {
echo "Cannot open file ($this->errorLogFile)";
exit;
}
// lock file
if (flock($handle, LOCK_EX)) {
if (fwrite($handle, $output) === FALSE) {
echo "Cannot write to file ($this->errorLogFile)";
exit;
}
fflush($handle);
// release lock
flock($handle, LOCK_UN);
} else {
echo "Couldn't lock the file - " . $this->errorLogFile;
}
fclose($handle);
}
//print_r($result->asXml());exit;
// if it's secure 3D then display form and set data for second request
// you can add && !isset($_POST['PaRes']) - to make sure
if (isset($result->reply->orderStatus->requestInfo->request3DSecure)) {
// --- set data for second request ---
$_SESSION['WPDirect']['WPRequest'] = $xml; // this is first request
$_SESSION['WPDirect']['echoData'] = (string) $result->reply->orderStatus->echoData;
// --- form ---
$paRequest = (string) $result->reply->orderStatus->requestInfo->request3DSecure->paRequest;
$issuerURL = (string) $result->reply->orderStatus->requestInfo->request3DSecure->issuerURL;
$form = new IssuerForm($paRequest, $issuerURL);
// --- return form instead of response and exit script ---
echo $form->getIssuerForm();exit;
}
// --- if it's not 3D, or it's second request then return response ---
//echo $result->asXml();exit;
return $result->asXml();
}
public function getOrderCode()
{
$log_file = dirname(__FILE__).'/log/order.log';
if(!$file = @fopen($log_file, 'r+'))
{
header('HTTP/1.0 500 Internal Server Error');
$log = "Cannot open " . $log_file . " file.\n" .
"Logs are not writable, set them to 777";
return false;
}
else
{
$code = (int) fread($file, 1024)+1;
fclose($file);
$file = @fopen($log_file, 'w');
fwrite($file, $code);
return $code;
}
}
}
By the way the line with the error is right at the bottom above public function getOrderCode()!!
Thanks
|