611 lines
17 KiB
PHP
611 lines
17 KiB
PHP
<?php
|
|
|
|
/* vim: set expandtab tabstop=4 shiftwidth=4: */
|
|
|
|
/**
|
|
* Holds code shared between all processors
|
|
*
|
|
* PHP versions 4 and 5
|
|
*
|
|
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
|
* that is available through the world-wide-web at the following URI:
|
|
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
|
* the PHP License and are unable to obtain it through the web, please
|
|
* send a note to license@php.net so we can mail you a copy immediately.
|
|
*
|
|
* @category Payment
|
|
* @package Payment_Process
|
|
* @author Ian Eure <ieure@php.net>
|
|
* @author Joe Stump <joe@joestump.net>
|
|
* @copyright 1997-2005 The PHP Group
|
|
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
|
* @version CVS: $Id: Common.php,v 1.32 2005/12/13 00:00:29 jstump Exp $
|
|
* @link http://pear.php.net/package/Payment_Process
|
|
*/
|
|
|
|
require_once('Payment/Process.php');
|
|
require_once('Payment/Process/Type.php');
|
|
|
|
class Payment_Process_Common {
|
|
// {{{ Private Properties
|
|
/**
|
|
* Options.
|
|
*
|
|
* @var array
|
|
* @see setOptions()
|
|
* @access private;
|
|
*/
|
|
var $_options = '';
|
|
|
|
/**
|
|
* Array of fields which are required.
|
|
*
|
|
* @var array
|
|
* @access private
|
|
* @see _makeRequired()
|
|
*/
|
|
var $_required = array();
|
|
|
|
/**
|
|
* Processor-specific data.
|
|
*
|
|
* @access private
|
|
* @var array
|
|
*/
|
|
var $_data = array();
|
|
|
|
/**
|
|
* $_driver
|
|
*
|
|
* @author Joe Stump <joe@joestump.net>
|
|
* @var string $_driver
|
|
* @access private
|
|
*/
|
|
var $_driver = null;
|
|
|
|
/**
|
|
* PEAR::Log instance
|
|
*
|
|
* @var object
|
|
* @access protected
|
|
* @see Log
|
|
*/
|
|
var $_log;
|
|
|
|
/**
|
|
* Mapping between API fields and processors'
|
|
*
|
|
* @var mixed $_typeFieldMap
|
|
* @access protected
|
|
*/
|
|
var $_typeFieldMap = array();
|
|
|
|
/**
|
|
* Reference to payment type
|
|
*
|
|
* An internal reference to the Payment_Process_Type that is currently
|
|
* being processed.
|
|
*
|
|
* @var mixed $_payment Instance of Payment_Type
|
|
* @access protected
|
|
* @see Payment_Process_Common::setPayment()
|
|
*/
|
|
var $_payment = null;
|
|
// }}}
|
|
// {{{ Public Properties
|
|
/**
|
|
* Your login name to use for authentication to the online processor.
|
|
*
|
|
* @var string
|
|
*/
|
|
var $login = '';
|
|
|
|
/**
|
|
* Your password to use for authentication to the online processor.
|
|
*
|
|
* @var string
|
|
*/
|
|
var $password = '';
|
|
|
|
/**
|
|
* Processing action.
|
|
*
|
|
* This should be set to one of the PAYMENT_PROCESS_ACTION_* constants.
|
|
*
|
|
* @var int
|
|
*/
|
|
var $action = '';
|
|
|
|
/**
|
|
* A description of the transaction (used by some processors to send
|
|
* information to the client, normally not a required field).
|
|
* @var string
|
|
*/
|
|
var $description = '';
|
|
|
|
/**
|
|
* The transaction amount.
|
|
*
|
|
* @var double
|
|
*/
|
|
var $amount = 0;
|
|
|
|
/**
|
|
* An invoice number.
|
|
*
|
|
* @var mixed string or int
|
|
*/
|
|
var $invoiceNumber = '';
|
|
|
|
/**
|
|
* Customer identifier
|
|
*
|
|
* @var mixed string or int
|
|
*/
|
|
var $customerId = '';
|
|
|
|
/**
|
|
* Transaction source.
|
|
*
|
|
* This should be set to one of the PAYMENT_PROCESS_SOURCE_* constants.
|
|
*
|
|
* @var int
|
|
*/
|
|
var $transactionSource;
|
|
// }}}
|
|
// {{{ __construct($options = false)
|
|
/**
|
|
* __construct
|
|
*
|
|
* PHP 5.x constructor
|
|
*
|
|
* @author Joe Stump <joe@joestump.net>
|
|
* @access public
|
|
*/
|
|
function __construct($options = false)
|
|
{
|
|
$this->setOptions($options);
|
|
}
|
|
// }}}
|
|
// {{{ setPayment(&$payment)
|
|
/**
|
|
* Sets payment
|
|
*
|
|
* Returns false if payment could not be set. This usually means the
|
|
* payment type is not valid or that the payment type is valid, but did
|
|
* not validate. It could also mean that the payment type is not supported
|
|
* by the given processor.
|
|
*
|
|
* @param mixed $payment Object of Payment_Process_Type
|
|
* @return bool
|
|
* @access public
|
|
* @author Joe Stump <joe@joestump.net>
|
|
*/
|
|
function setPayment(&$payment)
|
|
{
|
|
if (isset($this->_typeFieldMap[$payment->getType()]) &&
|
|
is_array($this->_typeFieldMap[$payment->getType()]) &&
|
|
count($this->_typeFieldMap[$payment->getType()])) {
|
|
|
|
$result = Payment_Process_Type::isValid($payment);
|
|
if (PEAR::isError($result)) {
|
|
return $result;
|
|
}
|
|
|
|
$this->_payment = $payment;
|
|
// Map over the payment specific fields. Check out
|
|
// $_typeFieldMap for more information.
|
|
$paymentType = $payment->getType();
|
|
foreach ($this->_typeFieldMap[$paymentType] as $generic => $specific) {
|
|
|
|
$func = '_handle'.ucfirst($generic);
|
|
if (method_exists($this, $func)) {
|
|
$result = $this->$func();
|
|
if (PEAR::isError($result)) {
|
|
return $result;
|
|
}
|
|
} else {
|
|
// TODO This may screw things up - the problem is that
|
|
// CC information is no longer member variables, so we
|
|
// can't overwrite it. You could always handle this
|
|
// with a _handle funciton. I don't think it will cause
|
|
// problems, but it could.
|
|
if (!isset($this->_data[$specific])) {
|
|
$this->_data[$specific] = $this->_payment->$generic;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return PEAR::raiseError('Invalid type field map');
|
|
}
|
|
// }}}
|
|
// {{{ setFrom($where)
|
|
/**
|
|
* Set many fields.
|
|
*
|
|
* @param array $where Associative array of data to set, in the format
|
|
* 'field' => 'value',
|
|
* @return void
|
|
*/
|
|
function setFrom($where)
|
|
{
|
|
foreach ($this->getFields() as $field) {
|
|
if (isset($where[$field])) {
|
|
$this->$field = $where[$field];
|
|
}
|
|
}
|
|
}
|
|
// }}}
|
|
// {{{ process()
|
|
/**
|
|
* Processes the transaction.
|
|
*
|
|
* This function should be overloaded by the processor.
|
|
*/
|
|
function process()
|
|
{
|
|
return PEAR::raiseError("process() is not implemented in this processor.", PAYMENT_PROCESS_ERROR_NOTIMPLEMENTED);
|
|
}
|
|
// }}}
|
|
// {{{ &processCallback()
|
|
/**
|
|
* processCallback
|
|
*
|
|
* This should be overridden in driver classes. It will be used to process
|
|
* communications from gateways to your application. For instance, the
|
|
* Authorize.net gateway will post information about pending transactions
|
|
* to a URL you specify. This function should handle such requests
|
|
*
|
|
* @return object Payment_Process_Result on success, PEAR_Error on failure
|
|
*/
|
|
function &processCallback()
|
|
{
|
|
return PEAR::raiseError('processCallback() not implemented',
|
|
PAYMENT_PROCESS_ERROR_NOTIMPLEMENTED);
|
|
}
|
|
// }}}
|
|
// {{{ validate()
|
|
/**
|
|
* validate
|
|
*
|
|
* Validates data before processing. This function may be overloaded by
|
|
* the processor.
|
|
*
|
|
* @return boolean true if validation succeeded, PEAR_Error if it failed.
|
|
*/
|
|
function validate()
|
|
{
|
|
foreach ($this->getFields() as $field) {
|
|
$func = '_validate'.ucfirst($field);
|
|
|
|
// Don't validate unset optional fields
|
|
if (! $this->isRequired($field) && !strlen($this->$field)) {
|
|
continue;
|
|
}
|
|
|
|
if (method_exists($this, $func)) {
|
|
$res = $this->$func();
|
|
if (PEAR::isError($res)) {
|
|
return $res;
|
|
} elseif (is_bool($res) && $res == false) {
|
|
return PEAR::raiseError('Validation of field "'.$field.'" failed.', PAYMENT_PROCESS_ERROR_INVALID);
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
// }}}
|
|
// {{{ set($field, $value)
|
|
/**
|
|
* Set a value.
|
|
*
|
|
* This will set a value, such as the credit card number. If the requested
|
|
* field is not part of the basic set of supported fields, it is set in
|
|
* $_options.
|
|
*
|
|
* @param string $field The field to set
|
|
* @param string $value The value to set
|
|
* @return void
|
|
*/
|
|
function set($field, $value)
|
|
{
|
|
if (!$this->fieldExists($field)) {
|
|
return PEAR::raiseError('Field "' . $field . '" does not exist.', PAYMENT_PROCESS_ERROR_INVALID);
|
|
}
|
|
$this->$field = $value;
|
|
return true;
|
|
}
|
|
// }}}
|
|
// {{{ isRequired($field)
|
|
/**
|
|
* Determine if a field is required.
|
|
*
|
|
* @param string $field Field to check
|
|
* @return boolean true if required, false if optional.
|
|
*/
|
|
function isRequired($field)
|
|
{
|
|
return (isset($this->_required[$field]));
|
|
}
|
|
// }}}
|
|
// {{{ fieldExists($field)
|
|
/**
|
|
* Determines if a field exists.
|
|
*
|
|
* @author Ian Eure <ieure@php.net>
|
|
* @param string $field Field to check
|
|
* @return boolean true if field exists, false otherwise
|
|
*/
|
|
function fieldExists($field)
|
|
{
|
|
return @in_array($field, $this->getFields());
|
|
}
|
|
// }}}
|
|
// {{{ getFields()
|
|
/**
|
|
* Get a list of fields.
|
|
*
|
|
* This function returns an array containing all the possible fields which
|
|
* may be set.
|
|
*
|
|
* @author Ian Eure <ieure@php.net>
|
|
* @access public
|
|
* @return array Array of valid fields.
|
|
*/
|
|
function getFields()
|
|
{
|
|
$vars = array_keys(get_class_vars(get_class($this)));
|
|
foreach ($vars as $idx => $field) {
|
|
if ($field[0] == '_') {
|
|
unset($vars[$idx]);
|
|
}
|
|
}
|
|
|
|
return $vars;
|
|
}
|
|
// }}}
|
|
// {{{ setOptions($options = false, $defaultOptions = false)
|
|
/**
|
|
* Set class options.
|
|
*
|
|
* @author Ian Eure <ieure@php.net>
|
|
* @param Array $options Options to set
|
|
* @param Array $defaultOptions Default options
|
|
* @return void
|
|
*/
|
|
function setOptions($options = false, $defaultOptions = false)
|
|
{
|
|
$defaultOptions = $defaultOptions ? $defaultOptions : $this->_defaultOptions; $this->_options = @array_merge($defaultOptions, $options);
|
|
}
|
|
// }}}
|
|
// {{{ getOption($option)
|
|
/**
|
|
* Get an option value.
|
|
*
|
|
* @author Ian Eure <ieure@php.net>
|
|
* @param string $option Option to get
|
|
* @return mixed Option value
|
|
*/
|
|
function getOption($option)
|
|
{
|
|
return @$this->_options[$option];
|
|
}
|
|
// }}}
|
|
// {{{ setOption($option,$value)
|
|
/**
|
|
* Set an option value
|
|
*
|
|
* @author Joe Stump <joe@joestump.net>
|
|
* @access public
|
|
* @param string $option Option name to set
|
|
* @param mixed $value Value to set
|
|
*/
|
|
function setOption($option,$value)
|
|
{
|
|
return ($this->_options[$option] = $value);
|
|
}
|
|
// }}}
|
|
// {{{ getResult()
|
|
/**
|
|
* Gets transaction result.
|
|
*
|
|
* This function should be overloaded by the processor.
|
|
*/
|
|
function getResult()
|
|
{
|
|
return PEAR::raiseError("getResult() is not implemented in this processor.", PAYMENT_PROCESS_ERROR_NOTIMPLEMENTED);
|
|
}
|
|
// }}}
|
|
// {{{ _isDefinedConstant($value, $class)
|
|
/**
|
|
* See if a value is a defined constant.
|
|
*
|
|
* This function checks to see if $value is defined in one of
|
|
* PAYMENT_PROCESS_{$class}_*. It's used to verify that e.g.
|
|
* $object->action is one of PAYMENT_PROCESS_ACTION_NORMAL,
|
|
* PAYMENT_PROCESS_ACTION_AUTHONLY etc.
|
|
*
|
|
* @access private
|
|
* @param mixed $value Value to check
|
|
* @param mixed $class Constant class to check
|
|
* @return boolean true if it is defined, false otherwise.
|
|
*/
|
|
function _isDefinedConst($value, $class)
|
|
{
|
|
$constClass = 'PAYMENT_PROCESS_'.strtoupper($class).'_';
|
|
$length = strlen($constClass);
|
|
$consts = get_defined_constants();
|
|
$found = false;
|
|
foreach ($consts as $constant => $constVal) {
|
|
if (strncmp($constClass, $constant, $length) === 0 &&
|
|
$constVal == $value) {
|
|
$found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $found;
|
|
}
|
|
// }}}
|
|
// {{{ _makeRequired()
|
|
/**
|
|
* Mark a field (or fields) as being required.
|
|
*
|
|
* @param string $field Field name
|
|
* @param string ...
|
|
* @return boolean always true.
|
|
*/
|
|
function _makeRequired()
|
|
{
|
|
foreach (func_get_args() as $field) {
|
|
$this->_required[$field] = true;
|
|
}
|
|
return true;
|
|
}
|
|
// }}}
|
|
// {{{ _makeOptional()
|
|
/**
|
|
* Mark a field as being optional.
|
|
*
|
|
* @param string $field Field name
|
|
* @param ...
|
|
* @return boolean always true.
|
|
*/
|
|
function _makeOptional()
|
|
{
|
|
foreach (func_get_args() as $field) {
|
|
unset($this->_required[$field]);
|
|
}
|
|
return true;
|
|
}
|
|
// }}}
|
|
// {{{ _validateType()
|
|
/**
|
|
* Validates transaction type.
|
|
*
|
|
* @return boolean true on success, false on failure.
|
|
* @access private
|
|
*/
|
|
function _validateType()
|
|
{
|
|
return $this->_isDefinedConst($this->type, 'type');
|
|
}
|
|
// }}}
|
|
// {{{ _validateAction()
|
|
/**
|
|
* Validates transaction action.
|
|
*
|
|
* @return boolean true on success, false on failure.
|
|
* @access private
|
|
*/
|
|
function _validateAction()
|
|
{
|
|
return (isset($GLOBALS['_Payment_Process_'.$this->_driver][$this->action]));
|
|
}
|
|
// }}}
|
|
// {{{ _validateSource()
|
|
/**
|
|
* Validates transaction source.
|
|
*
|
|
* @return boolean true on success, false on failure.
|
|
* @access private
|
|
*/
|
|
function _validateSource()
|
|
{
|
|
return $this->_isDefinedConst($this->transactionSource, 'source');
|
|
}
|
|
// }}}
|
|
// {{{ _validateAmount()
|
|
/**
|
|
* Validates the charge amount.
|
|
*
|
|
* Charge amount must be 8 characters long, double-precision.
|
|
* Current min/max are rather arbitrarily set to $0.99 and $99999.99,
|
|
* respectively.
|
|
*
|
|
* @return boolean true on success, false otherwise
|
|
*/
|
|
function _validateAmount()
|
|
{
|
|
return Validate::number($this->amount, array(
|
|
'decimal' => '.',
|
|
'dec_prec' => 2,
|
|
'min' => 0.99,
|
|
'max' => 99999.99
|
|
));
|
|
}
|
|
// }}}
|
|
// {{{ _handleAction()
|
|
/**
|
|
* Handles action
|
|
*
|
|
* Actions are defined in $GLOBALS['_Payment_Process_DriverName'] and then
|
|
* handled here. We may decide to abstract the defines in the driver.
|
|
*
|
|
* @access private
|
|
*/
|
|
function _handleAction()
|
|
{
|
|
$this->_data[$this->_fieldMap['action']] = $GLOBALS['_Payment_Process_'.$this->_driver][$this->action];
|
|
}
|
|
// }}}
|
|
// {{{ _prepare()
|
|
/**
|
|
* Prepares the POST data.
|
|
*
|
|
* This function handles translating the data set in the front-end to the
|
|
* format needed by the back-end. The prepared data is stored in
|
|
* $this->_data. If a '_handleField' method exists in this class (e.g.
|
|
* '_handleCardNumber()'), that function is called and /must/ set
|
|
* $this->_data correctly. If no field-handler function exists, the data
|
|
* from the front-end is mapped into $_data using $this->_fieldMap.
|
|
*
|
|
* @return array Data to POST
|
|
* @access private
|
|
*/
|
|
function _prepare()
|
|
{
|
|
/*
|
|
* FIXME - because this only loops through stuff in the fieldMap, we
|
|
* can't have handlers for stuff which isn't specified in there.
|
|
* But the whole point of having a _handler() is that you need
|
|
* to do something more than simple mapping.
|
|
*/
|
|
foreach ($this->_fieldMap as $generic => $specific) {
|
|
$func = '_handle'.ucfirst($generic);
|
|
if (method_exists($this, $func)) {
|
|
$result = $this->$func();
|
|
if (PEAR::isError($result)) {
|
|
return $result;
|
|
}
|
|
} else {
|
|
// TODO This may screw things up - the problem is that
|
|
// CC information is no longer member variables, so we
|
|
// can't overwrite it. You could always handle this with
|
|
// a _handle funciton. I don't think it will cause problems,
|
|
// but it could.
|
|
if (!isset($this->_data[$specific])) {
|
|
if (isset($this->$generic)) {
|
|
$this->_data[$specific] = $this->$generic;
|
|
}
|
|
|
|
// Form of payments data overrides those set in the
|
|
// Payment_Process_Common.
|
|
if (isset($this->_payment->$generic)) {
|
|
$this->_data[$specific] = $this->_payment->$generic;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
// }}}
|
|
}
|
|
|
|
?>
|