<?php
//
// Edit History:
//
// Last $Author: munroe $
// Last Modified: $Date: 2006/09/26 14:39:46 $
//
// Dick Munroe (hide@address.com) 28-Feb-2006
// Initial version created
//
// Dick Munroe (hide@address.com) 24-Mar-2006
// Modify getData interface to allow access to the entire contents of
// the m_IPNData member. Used by the PDT processing to long the
// retrieved data.
//
/**
* @author Dick Munroe <hide@address.com>
* @copyright copyright @ 2006 by Dick Munroe, Cottage Software Works, Inc.
* @license http://www.csworks.com/publications/ModifiedNetBSD.html
* @version 1.0.0
* @package dm.paypal
* @example ./example.php
*
* This is derived from a paypal IPN class written originally by Herve Foucher
* <hide@address.com> and published through phpclasses.org under the GPL.
* Herve appears to no longer support this package so I'm updating the support
* to 2005 and redesigning a bunch of the internal structure to allow a substantially
* more object oriented approach to the whole problem.
*/
include_once('class.paypalIPNAdvancedAndCustomInformation.php') ;
include_once('class.paypalIPNAuctions.php') ;
include_once('class.paypalIPNBasicInformation.php') ;
include_once('class.paypalIPNBuyerInformation.php') ;
include_once('class.paypalIPNCurrencyAndExchangeInformation.php') ;
include_once('class.paypalIPNDisputeNotification.php') ;
include_once('class.paypalIPNMassPayment.php') ;
include_once('class.paypalIPNPDTSpecific.php') ;
include_once('class.paypalIPNSubscriptions.php') ;
include_once('class.paypalIPNWebsiteAndRefundInformation.php') ;
class paypalIPNData
{
/**
* @desc The collection of IPN data values.
* @var array Associative array relating field names to values.
* @access private
*/
var $m_IPNData ;
/**
* @desc The ORDER of items as they appear in the IPN data source.
*
* Apparently yet another undocumented problem with Paypal is that unless you send
* the IPN fields back in the same ORDER as well as with the same DATA you appear
* to get invalid responses across the board.
*
* @var array The field names, in the order in which they apper in the source.
* @access private
*/
var $m_IPNDataOrder ;
/**
* Constructor.
*
* Pull the arguments passed in the source array into the
* IPN data object.
*
* @param array $theSource [by reference] The source array containing the variables to
* be pulled into the IPN data object.
* @param boolean $theReducingFlag [optional] When true, the elements moved into the
* IPN data object are removed from the $_POST array.
* @return void
* @access public
*/
function paypalIPNData (&$theSource, $anyAdditionalFields = NULL, $theReducingFlag = TRUE)
{
$this->m_IPNData = array() ;
$this->m_IPNDataOrder = array_keys($theSource) ;
$theObjects = array() ;
if ($theReducingFlag)
{
$theLocalSource =& $theSource ;
}
else
{
$theLocalSource = $theSource ;
}
/*
* Gather all the Paypal IPN into their seperate objects.
* The "bunches" of small IPN specific objects are just to make
* it easier to figure out what variables go with what applications.
*/
$theObjects[] = new paypalIPNBasicInformation($theLocalSource) ;
$theObjects[] = new paypalIPNAdvancedAndCustomInformation($theLocalSource) ;
$theObjects[] = new paypalIPNAuctions($theLocalSource) ;
$theObjects[] = new paypalIPNBuyerInformation($theLocalSource) ;
$theObjects[] = new paypalIPNCurrencyAndExchangeInformation($theLocalSource) ;
$theObjects[] = new paypalIPNDisputeNotification($theLocalSource) ;
$theObjects[] = new paypalIPNMassPayment($theLocalSource) ;
$theObjects[] = new paypalIPNPDTSpecific($theLocalSource) ;
$theObjects[] = new paypalIPNSubscriptions($theLocalSource) ;
$theObjects[] = new paypalIPNWebsiteAndRefundInformation($theLocalSource) ;
/*
* Start everything with the additional fields. Fields of idential names from
* the source will override these settings.
*/
if (!is_null($anyAdditionalFields))
{
if (is_array($anyAdditionalFields))
{
$this->m_IPNData = $anyAdditionalFields ;
}
}
/*
* Now go through the objects and copy all the defined variables to this one.
* All copying will be done by reference.
*/
foreach ($theObjects as $theObject)
{
if ($theObject->m_dirty)
{
$theVariables = get_object_vars($theObject) ;
foreach ($theVariables as $theVariableName => $theValue)
{
if (substr($theVariableName, 0, 2) != "m_")
{
if (!is_null($theValue))
{
$this->m_IPNData[$theVariableName] =& $theObject->$theVariableName ;
}
}
else if ($theVariableName == "m_dynamicVariables")
{
$this->m_IPNData = array_merge($this->m_IPNData, $theObject->m_dynamicVariables) ;
}
}
}
}
}
/**
* @desc Add arbitrary IPN variable/values to the set collected already.
* @param reference to associative array $theSource containing name/value pairs.
* @return void
* @access public
*/
function addData(&$theSource)
{
if (is_array($theSource))
{
$this->m_IPNData = array_merge($this->m_IPNData, $theSource) ;
}
}
/**
* @desc fetch IPN data.
* @return reference to the IPN data item.
* @param string [optional] The name of the IPN data item. If omitted a reference to m_IPNData is returned.
* @access public
*/
function &getData($theName = NULL)
{
if ($theName === NULL)
{
return $this->m_IPNData ;
}
else
{
if (isset($this->m_IPNData[$theName]))
{
return $this->m_IPNData[$theName] ;
}
else
{
$x = NULL ;
return $x ;
}
}
}
/**
* @desc Convert the variables in the data object to post string form.
*
* Apparently there is another "little" restriction with Paypal in that the
* ORDER of the IPN fields as well as the VALUES must be preserved.
*
* @return string
* @access public
*/
function &asPostString ()
{
/*
* It appears that Paypal insists that the data be posted back in the SAME ORDER
* it was received.
*/
$theKeys = array_keys($this->m_IPNData) ;
$theKeys = array_flip($theKeys) ;
$thePostString = "";
foreach ($this->m_IPNDataOrder as $xxx => $theKey)
{
if (array_key_exists($theKey, $this->m_IPNData))
{
$thePostString = $thePostString . "&" . $theKey . '=' . urlencode($this->m_IPNData[$theKey]) ;
unset($theKeys[$theKey]) ;
}
}
/*
* There MAY be extra stuff that needs to be sent back to Paypal (notably the cmd
* field). It all goes on the front of the post string and in the same order it
* appears in the keys array (which explains the reverse).
*/
$theKeys = array_reverse($theKeys) ;
foreach ($theKeys as $theKey => $xxx)
{
$thePostString = "&" . $theKey . '=' . urlencode($this->m_IPNData[$theKey]) . $thePostString ;
}
/*
* This is an undocumented change in the Paypal URL encoding.
* The encoding results of the HEX value have to be in upper case.
*/
preg_replace_callback('/%[\da-f]{2}/', create_function('$match', 'return strtoupper($match[0]) ;'), $thePostString) ;
$thePostString = substr($thePostString, 1) ;
return $thePostString ;
}
}
?>