Payment_Process
[ class tree: Payment_Process ] [ index: Payment_Process ] [ all elements ]

Source for file Dpilink.php

Documentation is available at Dpilink.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2003 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 3.0 of the PHP license,       |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available through the world-wide-web at                              |
  11. // | http://www.php.net/license/3_0.txt.                                  |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Ian Eure <ieure@php.net>                                    |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // $Id: Dpilink.php,v 1.19 2004/03/23 20:30:03 ieure Exp $
  20.  
  21. require_once 'Payment/Process/Common.php';
  22. //require_once 'HTTP/Request.php';
  23. require_once 'Net/Curl.php';
  24.  
  25. // DPILink transaction types
  26. // Request authorization only - no funds are transferred.
  27. define('PAYMENT_PROCESS_ACTION_DPILINK_AUTH'30);
  28. // Transfer funds from a previous authorization.
  29. define('PAYMENT_PROCESS_ACTION_DPILINK_SETTLE'40);
  30. // Authorize & transfer funds
  31. define('PAYMENT_PROCESS_ACTION_DPILINK_AUTHSETTLE'32);
  32. // Debit the indicated amount to a previously-charged card.
  33. define('PAYMENT_PROCESS_ACTION_DPILINK_CREDIT'20);
  34. // Cancel authorization
  35. define('PAYMENT_PROCESS_ACTION_DPILINK_VOID'61);
  36.  
  37. define('PAYMENT_PROCESS_RESULT_DPILINK_APPROVAL'00);
  38. define('PAYMENT_PROCESS_RESULT_DPILINK_DECLINE'05);
  39. define('PAYMENT_PROCESS_RESULT_DPILINK_INVALIDAMOUNT'13);
  40. define('PAYMENT_PROCESS_RESULT_DPILINK_INVALIDCARDNO'14);
  41. define('PAYMENT_PROCESS_RESULT_DPILINK_REENTER'19);
  42.  
  43. // Map actions
  44. $GLOBALS['_Payment_Process_Dpilink'= array(
  45. );
  46.  
  47. /**
  48.  * Payment_Process_Dpilink
  49.  *
  50.  * This is a processor for TransFirst's DPILink merchant payment gateway.
  51.  * (http://www.dpicorp.com/)
  52.  *
  53.  * *** WARNING ***
  54.  * This is BETA code. While I have tested it and it appears to work for me, I
  55.  * strongly recommend that you do additional testing before using it in
  56.  * production systems.
  57.  *
  58.  * @package Payment_Process
  59.  * @author Ian Eure <ieure@php.net>
  60.  * @version @version@
  61.  */
  62.     /**
  63.      * Front-end -> back-end field map.
  64.      *
  65.      * This array contains the mapping from front-end fields (defined in
  66.      * the Payment_Process class) to the field names DPILink requires.
  67.      *
  68.      * @see _prepare()
  69.      * @access private
  70.      */
  71.     var $_fieldMap = array(
  72.         // Required
  73.         'login'             => "DPIAccountNum",
  74.         'password'          => "password",
  75.         'action'            => "transactionCode",
  76.         'invoiceNumber'     => "orderNum",
  77.         'customerId'        => "customerNum",
  78.         'amount'            => "transactionAmount",
  79.         'transactionSource' => "ECommerce",
  80.         // Credit Card Type
  81.         'cardNumber'        => "cardAccountNum",
  82.         'expDate'           => "expirationDate",
  83.         'zip'               => "cardHolderZip",
  84.         // Common Type
  85.         'name'              => "cardHolderName",
  86.         'address'           => "cardHolderAddress",
  87.         'city'              => "cardHolderCity",
  88.         'state'             => "cardHolderState",
  89.         'phone'             => "cardHolderPhone",
  90.         'email'             => "cardHolderEmail"
  91.     );
  92.  
  93.     /**
  94.      * Default options for this processor.
  95.      *
  96.      * @see Payment_Process::setOptions()
  97.      * @access private
  98.      */
  99.     var $_defaultOptions = array(
  100.         'authorizeUri' => "https://www.dpisecure.com/dpilink/authpd.asp"
  101.     );
  102.  
  103.     /**
  104.      * Has the transaction been processed?
  105.      *
  106.      * @type boolean
  107.      * @access private
  108.      */
  109.     var $_processed = false;
  110.  
  111.     /**
  112.      * The response body sent back from the gateway.
  113.      *
  114.      * @access private
  115.      */
  116.     var $_responseBody '';
  117.  
  118.     /**
  119.      * Constructor.
  120.      *
  121.      * @param  array  $options  Class options to set.
  122.      * @see Payment_Process::setOptions()
  123.      * @return void 
  124.      */
  125.     function Payment_Process_Dpilink($options = false)
  126.     {
  127.         $this->setOptions($options);
  128.         $this->_makeRequired('login''password''action''invoiceNumber''customerId''amount''cardNumber''expDate');
  129.     }
  130.     
  131.     /**
  132.      * Prepare the data.
  133.      *
  134.      * This function handles the 'testTransaction' option, which is specific to
  135.      * this processor.
  136.      */
  137.     function _prepare()
  138.     {
  139.         if ($this->_options['testTransaction']{
  140.             $this->_data['testTransaction'$this->_options['testTransaction'];
  141.         }
  142.         return parent::_prepare();
  143.     }
  144.  
  145.     /**
  146.      * Process the transaction.
  147.      *
  148.      * @return mixed Payment_Process_Result on success, PEAR_Error on failure
  149.      */
  150.     function &process()
  151.     {
  152.         // Sanity check
  153.         if(PEAR::isError($res $this->validate())) {
  154.             return($res);
  155.         }
  156.  
  157.         // Prepare the data
  158.         $this->_prepare();
  159.  
  160.         // Don't die partway through
  161.         PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  162.  
  163.         $req &new Net_Curl($this->_options['authorizeUri']);
  164.         if (PEAR::isError($req)) {
  165.             PEAR::popErrorHandling();
  166.             return $req;
  167.         }
  168.         $req->type = 'POST';
  169.         $req->fields = $this->_prepareQueryString();
  170.         $req->userAgent = 'PEAR Payment_Process_Dpilink 0.1';
  171.         $res &$req->execute();
  172.         $req->close();
  173.         if (PEAR::isError($res)) {
  174.             PEAR::popErrorHandling();
  175.             return $res;
  176.         }
  177.         
  178.         $this->_processed = true;
  179.  
  180.         // Restore error handling
  181.         PEAR::popErrorHandling();
  182.  
  183.         $response trim($res);
  184.         print "Response: {$response}\n";
  185.         $result &Payment_Process_Result::factory('Dpilink'$response);
  186.         $result->_request = &$this;
  187.         $this->_result &$result;
  188.  
  189.         return $result;
  190.  
  191.         /*
  192.          * HTTP_Request doesn't do SSL until PHP 4.3.0, but it
  193.          * might be useful later...
  194.         $req = &new HTTP_Request($this->_authUri);
  195.         $this->_setPostData();
  196.         $req->sendRequest();
  197.         */
  198.     }
  199.  
  200.     /**
  201.      * Get (completed) transaction status.
  202.      *
  203.      * @return string Two-digit status returned from gateway.
  204.      */
  205.     function getStatus()
  206.     {
  207.         if (!$this->_processed{
  208.             return PEAR::raiseError('The transaction has not been processed yet.'PAYMENT_PROCESS_ERROR_INCOMPLETE);
  209.         }
  210.         return $this->_result->code;
  211.     }
  212.  
  213.     /**
  214.      * Get transaction sequence.
  215.      *
  216.      * 'Sequence' is what DPILink calls their transaction ID/approval code. This
  217.      * function returns that code from a processed transaction.
  218.      *
  219.      * @return mixed  Sequence ID, or PEAR_Error if the transaction hasn't been
  220.      *                 processed.
  221.      */
  222.     function getSequence()
  223.     {
  224.         if (!$this->_processed{
  225.             return PEAR::raiseError('The transaction has not been processed yet.'PAYMENT_PROCESS_ERROR_INCOMPLETE);
  226.         }
  227.         return $this->_result->_sequenceNumber;
  228.     }
  229.  
  230.     /**
  231.      * Prepare the POST query string.
  232.      *
  233.      * @access private
  234.      * @return string The query string
  235.      */
  236.     function _prepareQueryString()
  237.     {
  238.         foreach($this->_data as $var => $value{
  239.             if (strlen($value))
  240.                 $tmp[urlencode($var).'='.urlencode($value);
  241.         }
  242.         return @implode('&'$tmp);
  243.     }
  244.  
  245.     /*
  246.     function _setPostData(&$req)
  247.     {
  248.         foreach($this->_data as $var => $value) {
  249.             $req->addPostData($var, $value);
  250.         }
  251.     }
  252.     */
  253.  
  254.     /**
  255.      * Handle transaction source.
  256.      *
  257.      * @access private
  258.      */
  259.     function _handleTransactionSource()
  260.     {
  261.         $specific $this->_fieldMap['transactionSource'];
  262.         if ($this->transactionSource == PAYMENT_PROCESS_SOURCE_ONLINE{
  263.             $this->_data[$specific'Y';
  264.         else {
  265.             $this->_data[$specific'N';
  266.         }
  267.     }
  268.  
  269.     /**
  270.      * Handle card expiration date.
  271.      *
  272.      * The gateway wants the date in the format MMYY, with no other chars.
  273.      *
  274.      * @access private
  275.      */
  276.     function _handleExpDate()
  277.     {
  278.         $specific $this->_fieldMap['expDate'];
  279.         if (isset($this->_data[$specific])) {
  280.             $this->_data[$specificstr_replace('/'''$this->_data[$specific]);
  281.         else {
  282.             $this->_data[$specificstr_replace('/'''$this->expDate);
  283.         }
  284.     }
  285.  
  286.     /**
  287.      * Validate the merchant account login.
  288.      *
  289.      * The DPILink docs specify that the login is exactly eight digits.
  290.      *
  291.      * @access private
  292.      * @return boolean true if valid, false otherwise
  293.      */
  294.     function _validateLogin()
  295.     {
  296.         return Validate::string($this->loginarray(
  297.             'format' => VALIDATE_NUM,
  298.             'max_length' => 8,
  299.             'min_length' => 8
  300.         ));
  301.     }
  302.  
  303.     /**
  304.      * Validate the merchant account password.
  305.      *
  306.      * The DPILink docs specify that the password is a string between 6 and 10
  307.      * characters in length.
  308.      *
  309.      * @access private
  310.      * @return boolean true if valid, false otherwise
  311.      */
  312.     function _validatePassword()
  313.     {
  314.         return Validate::string($this->passwordarray(
  315.             'format' => VALIDATE_ALPHA . VALIDATE_NUM,
  316.             'min_length' => 6,
  317.             'max_length' => 10
  318.         ));
  319.     }
  320.  
  321.     /**
  322.      * Validate the invoice number.
  323.      *
  324.      * Invoice number must be a 5-character long alphanumeric string.
  325.      *
  326.      * @return boolean true on success, false otherwise
  327.      */
  328.     function _validateInvoiceNumber()
  329.     {
  330.         return Validate::string($this->invoiceNumberarray(
  331.             'format' => VALIDATE_NUM . VALIDATE_ALPHA,
  332.             'min_length' => 5,
  333.             'max_length' => 5
  334.         ));
  335.     }
  336.  
  337.     /**
  338.      * Validate the invoice number.
  339.      *
  340.      * Invoice no. must be a 15-character long alphanumeric string.
  341.      *
  342.      * @return boolean true on success, false otherwise
  343.      */
  344.     function _validateCustomerId()
  345.     {
  346.         return Validate::string($this->customerIdarray(
  347.             'format' => VALIDATE_NUM . VALIDATE_ALPHA,
  348.             'min_length' => 15,
  349.             'max_length' => 15
  350.         ));
  351.     }
  352.     
  353.     /**
  354.      * Validate the zip code.
  355.      *
  356.      * Zip is only required if AVS is enabled.
  357.      *
  358.      * @return boolean true on success, false otherwise.
  359.      */
  360.     function _validateZip()
  361.     {
  362.         if(strlen($this->zip|| $this->performAvs{
  363.             return parent::_validateZip();
  364.         }
  365.         return true;
  366.     }
  367. }
  368.  
  369.  
  370.     /**
  371.      * DPILink status codes.
  372.      *
  373.      * This array holds every possible status returned by the DPILink gateway.
  374.      *
  375.      * See the DPILink documentation for more details on each response.
  376.      *
  377.      * @see getStatusText()
  378.      * @access private
  379.      */
  380.     var $_statusCodeMessages = array(
  381.         '00' => "Approved",
  382.         '01' => "Refer to issuer",
  383.         '02' => "Refer to issuer - Special condition",
  384.         '03' => "Invalid merchant ID",
  385.         '04' => "Pick up card",
  386.         '05' => "Declined",
  387.         '06' => "General error",
  388.         '07' => "Pick up card - Special condition",
  389.         '13' => "Invalid amount",
  390.         '14' => "Invalid card number",
  391.         '15' => "No such issuer",
  392.         '19' => "Re-enter transaction",
  393.         '21' => "Unable to back out transaction",
  394.         '28' => "File is temporarily unavailable",
  395.         '39' => "No credit account",
  396.         '41' => "Pick up card - Lost",
  397.         '43' => "Pick up card - Stolen",
  398.         '51' => "Insufficient funds",
  399.         '54' => "Expired card",
  400.         '57' => "Transaction not permitted - Card",
  401.         '61' => "Amount exceeds withdrawal limit",
  402.         '62' => "Invalid service code, restricted",
  403.         '65' => "Activity limit exceeded",
  404.         '76' => "Unable to locate, no match",
  405.         '77' => "Inconsistent data, rev. or repeat",
  406.         '78' => "No account",
  407.         '80' => "Invalid date",
  408.         '85' => "Card OK",
  409.         '91' => "Issuer or switch is unavailable",
  410.         '93' => "Violation, cannot complete",
  411.         '96' => "System malfunction",
  412.         '98' => "No matching transaction to void",
  413.         '99' => "System timeout",
  414.         'L0' => "General System Error - Contact DPI Account Exec.",
  415.         'L1' => "Invalid or missing account number",
  416.         'L2' => "Invalid or missing password",
  417.         'L3' => "Expiration Date is not formatted correctly",
  418.         'L4' => "Reference number not found",
  419.         'L6' => "Order number is required but missing",
  420.         'L7' => "Wrong transaction code",
  421.         'L8' => "Network timeout",
  422.         'L14' => "Invalid card number",
  423.         'S5' => "Already settled",
  424.         'S6' => "Not authorized",
  425.         'S7' => "Declined",
  426.         'V6' => "Invalid transaction type",
  427.         'V7' => "Declined",
  428.         'V8' => "Already voided",
  429.         'V9' => "Already posted"
  430.     );
  431.  
  432.     var $_avsCodeMap = array(
  433.         'A' => "Address match",
  434.         'E' => "Ineligible",
  435.         'N' => "No match",
  436.         'R' => "Retry",
  437.         'S' => "Service unavailable",
  438.         'U' => "Address information unavailable",
  439.         'W' => "9-digit zip match",
  440.         'X' => "Address and 9-digit zip match",
  441.         'Y' => "Address and 5-digit zip match",
  442.         'Z' => "5-digit zip match"
  443.     );
  444.     
  445.     /**
  446.      * Status code map
  447.      *
  448.      * This contains a map from the Processor-specific result codes to the generic
  449.      * P_P codes. Anything not defined here is treated as a DECLINED result by
  450.      * validate()
  451.      *
  452.      * @type array
  453.      * @access private
  454.      */
  455.     var $_statusCodeMap = array(
  456.         '00' => PAYMENT_PROCESS_RESULT_APPROVED,
  457.         '05' => PAYMENT_PROCESS_RESULT_DECLINED,
  458.         'V7' => PAYMENT_PROCESS_RESULT_DECLINED
  459.     );
  460.  
  461.     var $_aciCodes = array(
  462.         'A' => "CPS Qualified",
  463.         'E' => "CPS Qualified  -  Card Acceptor Data was submitted in the authorization  request.",
  464.         'M' => "Reserved - The card was not present and no AVS request for International transactions",
  465.         'N' => "Not CPS Qualified",
  466.         'V' => "CPS Qualified ? Included an address verification request in the authorization request."
  467.     );
  468.  
  469.     var $_authSourceCodes = array(
  470.         ' ' => "Terminal doesn't support",
  471.         '0' => "Exception File",
  472.         '1' => "Stand in Processing, time-out response",
  473.         '2' => "Loss Control System (LCS) response provided",
  474.         '3' => "STIP, response provided, issuer suppress inquiry mode",
  475.         '4' => "STIP, response provided, issuer is down",
  476.         '5' => "Response provided by issuer",
  477.         '9' => "Automated referral service (ARS) stand-in"
  478.     );
  479.     
  480.     var $_fieldMap = array(
  481.         0  => '_null',                    // DPI Internal Message Format
  482.         1  => '_acctNo',                  // DPI Account number
  483.         2  => '_transactionCode',         // The transaction code from the request message passed by the original request.
  484.         3  => 'transactionId',            // Assigned by DPI used to uniquely identify transaction.
  485.         4  => '_mailOrder',               // Mail Order Identifier
  486.         5  => '_ccAcctNo',                // The credit card account number passed by the original request.
  487.         6  => '_ccExpDate',               // The Expiration Date passed by the original request. The field is formatted YYMM (Year, Month)
  488.         7  => '_authAmount',              // An eight-digit value, which denotes the dollar amount passed to DPI, without a decimal. ( DDDDDDCC )
  489.         8  => '_authDate',                // A six-digit value, which denotes the date the authorization, was attempted.  The field is formatted YYMMDD. (Year, Month, Date)
  490.         9  => '_authTime',                // A six-digit value, which denotes the time the authorization, was attempted.  The field is formatted HHMMSS.  (Hour, Minute, Second)
  491.         10 => 'messageCode',              // A two-digit value, which indicates the result of the authorization request.  Used to determine if the card was authorized, declined or timed out.
  492.         11 => 'customerId',               // The Customer Number passed by the original request
  493.         12 => 'invoiceNumber',            // The Order Number passed by the original request.
  494.         13 => '_urn',                     // A number that uniquely identifies an individual transaction.  Assigned by DPI and can be used when referencing a specific transaction.
  495.         14 => '_authResponse',            
  496.         15 => '_authSource',              // A code that defines the source where an authorization was captured.
  497.         16 => '_authCharacteristic',      // A code that defines the qualification level for the authorized transaction.
  498.         17 => 'approvalCode',             // Assigned by Visa or MasterCard, used to uniquely identify and link together all related information and used to authorize and clear a transaction.
  499.         18 => '_validationCode',          // Assigned by V.I.P. System that is used to determine the accuracy of the authorization data.
  500.         19 => '_sicCatCode',              
  501.         20 => '_currencyCode',            // 840 indicate US Currency to date this is the only valid value.
  502.         21 => 'avsCode',                  // A value that indicates the level of Address Verification that was validated.
  503.         22 => '_merchantStoreNo',         
  504.         23 => 'cvvCode'                   // A two-digit value, indicating the result of the card verification based on the CVV2 code provided by the cardholder.
  505.     );
  506.  
  507.     /**
  508.      * Constructor.
  509.      *
  510.      * @param  string  $rawResponse  The raw response from the gateway
  511.      * @return mixed boolean true on success, PEAR_Error on failure
  512.      */
  513.     function Payment_Process_Result_Dpilink($rawResponse)
  514.     {
  515.         $res $this->_validateResponse($rawResponse);
  516.         if (!$res || PEAR::isError($res)) {
  517.             if (!$res{
  518.                 $res = PEAR::raiseError("Unable to validate response body");
  519.             }
  520.             return $res;
  521.         }
  522.  
  523.         $this->_rawResponse = $rawResponse;
  524.         $res $this->_parseResponse();
  525.     }
  526.  
  527.     function getAuthSource()
  528.     {
  529.         return @$this->_authSourceCodes[$this->_authSource];
  530.     }
  531.  
  532.     function getAuthCharacteristic()
  533.     {
  534.         return @$this->_aciCodes[$this->_authChar];
  535.     }
  536.  
  537.     function getCode()
  538.     {
  539.         return $this->_statusCodeMap[$this->messageCode];
  540.     }
  541.  
  542.     /**
  543.      * Parse DPILink R1 response string.
  544.      *
  545.      * This function parses the response the gateway sends back, which is in
  546.      * pipe-delimited format.
  547.      *
  548.      * @return void 
  549.      */
  550.     function _parseResponse()
  551.     {
  552.         $this->_mapFields(explode('|'$this->_rawResponse));
  553.     }
  554.  
  555.     /**
  556.      * Validate a R1 response.
  557.      *
  558.      * @return boolean 
  559.      */
  560.     function _validateResponse($resp)
  561.     {
  562.         if (strlen($resp> 160)
  563.             return false;
  564.  
  565.         // FIXME - add more tests
  566.  
  567.         return true;
  568.     }
  569. }
  570.  
  571. ?>

Documentation generated on Mon, 11 Mar 2019 13:51:27 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.