home *** CD-ROM | disk | FTP | other *** search
/ PC World 2001 August / PCWorld_2001-08_cd.bin / Komunikace / phptriad / phptriadsetup2-11.exe / php / pear / Payment / Verisign.php
PHP Script  |  2001-01-10  |  17KB  |  543 lines

  1. <?php /* -*- C++ -*- */
  2. /*
  3.    +----------------------------------------------------------------------+
  4.    | PHP version 4.0                                                      |
  5.    +----------------------------------------------------------------------+
  6.    | Copyright (c) 1997-2001 The PHP Group                                |
  7.    +----------------------------------------------------------------------+
  8.    | This source file is subject to version 2.02 of the PHP license,      |
  9.    | that is bundled with this package in the file LICENSE, and is        |
  10.    | available at through the world-wide-web at                           |
  11.    | http://www.php.net/license/2_02.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.    | Author: David Croft: <david@infotrek.co.uk>                          |
  17.    +----------------------------------------------------------------------+
  18. */
  19.  
  20. /* $Id: Verisign.php,v 1.3 2001/01/10 01:01:58 ssb Exp $ */
  21.  
  22. /*                 ******** NOTICE ********
  23.  *
  24.  *   This code is completely untested. Do not use it!
  25.  *   It is here for peer review. It will undergo revision, bugfixes
  26.  *   and probably API changes. It must not be used yet!
  27.  */
  28.  
  29. /* Verisign Payment Processing class.
  30.  *
  31.  * Some test cards:
  32.  * Amex:       378282246310005
  33.  * Discover:   6011111111111117
  34.  * Mastercard: 5105105105105100 or 5555555555551111
  35.  * Visa:       4242424242424242 or 4111111111111111
  36. */
  37.  
  38. require_once 'PEAR.php';
  39.  
  40.  
  41. /* Symbolic names for decoded response codes */
  42. /* We want as few of these as possible so calling code has fewer branches */
  43.  
  44. define("VERISIGN_SUCCESS",                 0);
  45.  
  46. /* 10+ - user errors */
  47.  
  48. define("VERISIGN_BAD_CARD",               10);
  49. define("VERISIGN_INVALID_EXPIRY",         11);
  50. define("VERSIGIN_BAD_CARD_TYPE",          12);
  51.  
  52. /* 20+ - our errors */
  53.  
  54. define("VERISIGN_CONFIG_ERROR",           20);
  55. define("VERISIGN_UNRECOGNISED_RESPONSE",  21);
  56.  
  57. /* 30+ - temporary errors, try again later */
  58.  
  59. define("VERISIGN_TEMPORARY_ERROR",        30);
  60. define("VERISIGN_REFERRAL",               31);
  61.  
  62.  
  63. class Payment_Verisign
  64. {
  65.   /* These are all private variables. DO NOT ACCESS THEM DIRECTLY. */
  66.   /* There are specific functions to set each of these */
  67.  
  68.   var $hostaddress = 'test.signio.com';
  69.   var $hostport = 443;
  70.  
  71.   var $timeout = 30;
  72.  
  73.   var $proxyaddress;
  74.   var $proxyport;
  75.   var $proxylogon;
  76.   var $proxypassword;
  77.  
  78.   var $username;
  79.   var $password;
  80.  
  81.   var $cardnumber;
  82.   var $expiredate;
  83.  
  84.   var $params = array();
  85.  
  86.   function Payment_Verisign()
  87.   {
  88.     /* can you return stuff from a constructor? */
  89.  
  90.     if (!extension_loaded('pfpro')) {
  91.       return new VerisignException('Payflow Pro module is not compiled into PHP. Compile PHP using --with-pfpro.');
  92.     }
  93.   }
  94.  
  95.   function set_host($hostaddress, $hostport = 443)
  96.   {
  97.     if (!$hostaddress or !strlen($hostaddress)) {
  98.       return new VerisignException('Invalid host address');
  99.     }
  100.  
  101.     if (!$hostport or $hostport < 1) {
  102.       return new VerisignException('Invalid host port');
  103.     }
  104.  
  105.     $this->hostaddress = $hostaddress;
  106.     $this->hostport = $hostport;
  107.   }
  108.  
  109.   function set_timeout($timeout)
  110.   {
  111.     if ($timeout < 1 or $timeout > 3600) {
  112.       return new VerisignException('Invalid timeout value');
  113.     }
  114.  
  115.     $this->timeout = $timeout;
  116.   }
  117.  
  118.   function set_logon($username, $password)
  119.   {
  120.     if (!$username or !strlen($username)) {
  121.       return new VerisignException('Invalid user name');
  122.     }
  123.  
  124.     if (!$password or !strlen($password)) {
  125.       return new VerisignException('Invalid password');
  126.     }
  127.  
  128.     $this->username = $username;
  129.     $this->password = $password;
  130.   }
  131.  
  132.   function set_proxy($proxyaddress, $proxyport = 443, $proxylogon = '', $proxypassword = '')
  133.   {
  134.     if (!$proxyaddress or !strlen($proxyaddress)) {
  135.       return new VerisignException('Invalid proxy address');
  136.     }
  137.  
  138.     if (!$proxyport or $proxyport < 1) {
  139.       return new VerisignException('Invalid proxy port');
  140.     }
  141.     
  142.     $this->proxyaddress = $proxyaddress;
  143.     $this->proxyport = $proxyport;
  144.  
  145.     if ($proxylogon and strlen($proxylogon)) {
  146.       $this->proxypassword = $proxylogon;
  147.     }
  148.  
  149.     if ($proxylogon and strlen($proxypassword)) {
  150.       $this->proxypassword = $proxypassword;
  151.     }
  152.   }
  153.  
  154.   function set_card($cardnumber, $expiremonth, $expireyear)
  155.   {
  156.     $this->cardnumber = $cardnumber;
  157.  
  158.     if ($expiremonth < 1 or $expiremonth > 12) {
  159.       return new VerisignException('Invalid expiry month');
  160.     }
  161.  
  162.     if (($expireyear > 99 and $expireyear < 2000) or $expireyear > 2100) {
  163.       return new VerisignException('Invalid expiry year');
  164.     }
  165.  
  166.     $this->expiredate = sprintf("%02d%02d", $expiremonth, ($expireyear > 100) ? ($expireyear % 100) : $expireyear);
  167.  
  168.   }
  169.  
  170.   function set_avs($street, $zip)
  171.   {
  172.     if (!$street or !is_string($street) or !strlen($street)) {
  173.       return new VerisignException('AVS Street was not specified or was not a string');
  174.     }
  175.     if (!$zip or !is_string($zip) or !strlen($zip)) {
  176.       return new VerisignException('AVS Zip was not specified or was not a string');
  177.     }
  178.  
  179.     $this->params['STREET'] = $street;
  180.     $this->params['ZIP'] = $zip;
  181.   }
  182.  
  183.   function add_parameter($key, $value)
  184.   {
  185.     if (!$key or !is_string($key) or !strlen($key)) {
  186.       return new VerisignException('Key must be a string');
  187.     }
  188.  
  189.     $this->params[$key] = $value;
  190.   }
  191.  
  192.   function add_parameters($newparams)
  193.   {
  194.     foreach ($newparams as $key => $value) {
  195.       if (!$key or !is_string($key) or !strlen($key)) {
  196.     return new VerisignException('Keys must be strings');
  197.       }
  198.     }
  199.  
  200.     $this->params = array_merge($this->params, $newparams);
  201.   }
  202.  
  203.   function reset_parameters()
  204.   {
  205.     $this->params = array();
  206.   }
  207.  
  208.   function set_comment1($comment)
  209.   {
  210.     $this->params['COMMENT1'] = $comment;
  211.   }
  212.  
  213.   function set_comment2($comment)
  214.   {
  215.     $this->params['COMMENT2'] = $comment;
  216.   }
  217.  
  218.   /* Functions to process transactions */
  219.  
  220.   /* sale: authorise and immediate capture */
  221.  
  222.   function sale($amount)
  223.   {
  224.     if (!$amount or $amount <= 0) {
  225.       return new VerisignException('You cannot perform a sale on a negative or zero amount');
  226.     }
  227.  
  228.     $this->params['AMT'] = number_format($amount, 2, '.', '');
  229.  
  230.     return $this->process('S');
  231.   }
  232.  
  233.   /* authorise: authorise only for capture later with capture() */
  234.  
  235.   function authorize($amount)
  236.   {
  237.     /* for the yanks */
  238.     return $this->authorise($amount);
  239.   }
  240.  
  241.   function authorise($amount)
  242.   {
  243.     if (!$amount or $amount <= 0) {
  244.       return new VerisignException('You cannot perform an authorisation on a negative or zero amount');
  245.     }
  246.  
  247.     $this->params['AMT'] = number_format($amount, 2, '.', '');
  248.  
  249.     return $this->process('A');
  250.   }
  251.  
  252.   /* capture: capture an authorised transaction */
  253.  
  254.   function capture($origid)
  255.   {
  256.     if (!$origid or !strlen($origid)) {
  257.       return new VerisignException('You must provide the original PNREF id for a delayed capture');
  258.     }
  259.  
  260.     $this->params['ORIGID'] = $origid;
  261.  
  262.     return $this->process('D');
  263.   }
  264.  
  265.   /* refund: give money back (ouch) */
  266.  
  267.   function refund($amount)
  268.   {
  269.     if (!$amount or $amount <= 0) {
  270.       return new VerisignException('You cannot perform an authorisation on a negative or zero amount');
  271.     }
  272.  
  273.     $this->params['AMT'] = number_format($amount, 2, '.', '');
  274.  
  275.     return $this->process('C');
  276.   }
  277.  
  278.   /* refund_transaction: refund a specific earlier transaction - no card required */
  279.  
  280.   function refund_transaction($origid)
  281.   {
  282.     if (!$origid or !strlen($origid)) {
  283.       return new VerisignException('You must provide the original PNREF id for a transaction refund');
  284.     }
  285.  
  286.     $this->params['ORIGID'] = $origid;
  287.  
  288.     return $this->process('C');
  289.   }
  290.  
  291.   /* voice_auth: voice authorised transaction */
  292.  
  293.   function voice_auth($amount, $authcode)
  294.   {
  295.     if (!$amount or $amount <= 0) {
  296.       return new VerisignException('You cannot perform an authorisation on a negative or zero amount');
  297.     }
  298.  
  299.     if (!$authcode or !strlen($authcode)) {
  300.       return new VerisignException('You must provide an authcode for a voice authorisation');
  301.     }
  302.  
  303.     $this->params['AMT'] = number_format($amount, 2, '.', '');
  304.  
  305.     $this->params['AUTHCODE'] = $authcode;
  306.  
  307.     return $this->process('F');
  308.   }
  309.  
  310.   function void($origid)
  311.   {
  312.     if (!$origid or !strlen($origid)) {
  313.       return new VerisignException('You must provide the original PNREF id for a transaction refund');
  314.     }
  315.  
  316.     $this->params['ORIGID'] = $origid;
  317.  
  318.     return $this->process('V');
  319.   }
  320.  
  321.   /* Central processing function */
  322.  
  323.   function process($trxtype, $tender = 'C')
  324.   {
  325.     if (!extension_loaded('pfpro')) {
  326.       return new VerisignException('Payflow Pro module is not compiled into PHP. Compile PHP using --with-pfpro.');
  327.     }
  328.  
  329.     if (!$this->params['USER']) {
  330.       if ($this->username and strlen($this->username)) {
  331.     $this->params['USER'] = $this->username;
  332.       }
  333.       else {
  334.     return new VerisignException('You have not specified the Verisign user name');
  335.       }
  336.     }
  337.  
  338.     if (!$this->params['PWD']) {
  339.       if ($this->password and strlen($this->password)) {
  340.     $this->params['PWD'] = $this->username;
  341.       }
  342.       else {
  343.     return new VerisignException('You have not specified the Verisign password');
  344.       }
  345.     }
  346.  
  347.     if (!$this->params['ACCT']) {
  348.       if ($this->cardnumber and strlen($this->cardnumer)) {
  349.     $this->params['ACCT'] = $this->cardnumber;
  350.       }
  351.       else if ($this->params['ORIGID'] and
  352.            ($trxtype == 'C' or $trxtype == 'D' or $trxtype == 'V')) {
  353.     /* don't need card number if we're crediting or capturing
  354.      * or voiding a specific transaction */
  355.       }
  356.       else {
  357.     return new VerisignException('You have not specified the card number');
  358.       }
  359.     }
  360.  
  361.     if (!$this->params['EXPDATE']) {
  362.       if ($this->expiredate and strlen($this->expiredate)) {
  363.     $this->params['EXPDATE'] = $this->expiredate;
  364.       }
  365.       else if ($this->params['ORIGID'] and
  366.            ($trxtype == 'C' or $trxtype == 'D' or $trxtype == 'V')) {
  367.     /* don't need expiry date if we're crediting or capturing
  368.      * or voiding a specific transaction */
  369.       }
  370.       else {
  371.     return new VerisignException('You have not specified the expiry date');
  372.       }
  373.     }
  374.  
  375.     if (!$trxtype or !strlen($trxtype)) {
  376.       return new VerisignException('Invalid transaction type');
  377.     }
  378.  
  379.     $this->params['TRXTYPE'] = $trxtype;
  380.  
  381.     if (!$tender or !strlen($tender)) {
  382.       return new VerisignException('Invalid tender');
  383.     }
  384.  
  385.     $this->params['TENDER'] = $tender;
  386.  
  387.     /* Some final validation of our member variables */
  388.  
  389.     if (!$this->hostaddress or !strlen($this->hostaddress)) {
  390.       return new VerisignException('No host address specified');
  391.     }
  392.  
  393.     if (!$this->hostport or $this->hostport < 1) {
  394.       return new VerisignException('No host port specified');
  395.     }
  396.  
  397.     /* Now process it */
  398.  
  399.     if ($this->proxypassword and strlen($this->proxypassword)) {
  400.       $response = pfpro_process($this->params, $this->hostaddress, $this->hostport, $this->timeout, $this->proxyaddress, $this->proxyport, $this->proxylogon, $this->proxypassword);
  401.     }
  402.     else if ($this->proxylogon and strlen($this->proxylogon)) {
  403.       $response = pfpro_process($this->params, $this->hostaddress, $this->hostport, $this->timeout, $this->proxyaddress, $this->proxyport, $this->proxylogon);
  404.     }
  405.     else if ($this->proxyport and $this->proxyport > 0) {
  406.       $response = pfpro_process($this->params, $this->hostaddress, $this->hostport, $this->timeout, $this->proxyaddress, $this->proxyport);
  407.     }
  408.     else if ($this->proxyaddress and strlen($this->proxyaddress)) {
  409.       $response = pfpro_process($this->params, $this->hostaddress, $this->hostport, $this->timeout, $this->proxyaddress);
  410.     }
  411.     else if ($this->timeout and $this->timeout > 0) {
  412.       $response = pfpro_process($this->params, $this->hostaddress, $this->hostport, $this->timeout);
  413.     }
  414.     else if ($this->hostport and $this->hostport > 0) {
  415.       $response = pfpro_process($this->params, $this->hostaddress, $this->hostport);
  416.     }
  417.     else if ($this->hostaddress and ($this->hostaddress)) {
  418.       $response = pfpro_process($this->params, $this->hostaddress);
  419.     }
  420.     else {
  421.       $response = pfpro_process($this->params);
  422.     }
  423.  
  424.     if (!$response) {
  425.       return new VerisignException('No response received from Payflow Pro!');
  426.     }
  427.  
  428.     if (!$response['RESULT']) {
  429.       $response['RESULT'] = -999;
  430.     }
  431.  
  432.     return $response;
  433.   }
  434.  
  435.   /* Decode the myriad of Verisign response codes into a meaningful few */
  436.  
  437.  
  438.  
  439.   function decode_response($code)
  440.   {
  441.     if (is_array($code)) {
  442.       $code = $code['RESULT'];
  443.     }
  444.     else if (!is_integer($code)) {
  445.       return new VerisignException('Result code must be an integer');
  446.     }
  447.  
  448.     switch ($code) {
  449.  
  450.     case 0:    /* Approved                                  */
  451.       return VERISIGN_SUCCESS;
  452.  
  453.     case 12:   /* Declined                                  */
  454.     case 23:   /* Invalid account number                    */
  455.     case 50:   /* Insufficient funds available              */
  456.     case 112:  /* Failed AVS check                          */
  457.       return VERISIGN_BAD_CARD;
  458.  
  459.     case 24:   /* Invalid expiry date                       */
  460.       return VERISIGN_INVALID_EXPIRY;
  461.  
  462.     case 2:    /* Invalid tender                            */
  463.     return VERISIGN_BAD_CARD_TYPE;
  464.  
  465.     case 1:    /* User authentication failed                */
  466.     case 3:    /* Invalid transaction type                  */
  467.     case 4:    /* Invalid amount                            */
  468.     case 5:    /* Invalid merchant information              */
  469.     case 7:    /* Field format error                        */
  470.     case 19:   /* Original transaction ID not found         */
  471.     case 20:   /* Cannot find the customer reference number */
  472.     case 22:   /* Invalid ABA number                        */
  473.     case 25:   /* Transaction type not mapped to this host  */
  474.     case 100:  /* Invalid transaction returned from host    */
  475.     case 105:  /* Credit error                              */
  476.     case 108:  /* Void error                                */
  477.     case 111:  /* Capture error                             */
  478.     case 113:  /* Cannot exceed sales cap                   */
  479.       return VERISIGN_CONFIG_ERROR;
  480.  
  481.     case 11:   /* Client timeout waiting for response       */
  482.     case 101:  /* Timeout value too small                   */
  483.     case 102:  /* Host unavailable                          */
  484.     case 103:  /* Error reading response from host          */
  485.     case 104:  /* Tiemout waiting for host response         */
  486.     case -1:   /* Server socket unavailable                 */
  487.     case -2:   /* Hostname lookup failed                    */
  488.     case -3:   /* Client time out                           */
  489.     case -4:   /* Socket initialisation error               */
  490.     case -5:   /* SSL context initialisation failed         */
  491.     case -6:   /* SSL verification policy error             */
  492.     case -7:   /* SSL verify location error                 */
  493.     case -8:   /* X509 certification verification error     */
  494.     case -99:  /* Internal error to the library             */
  495.     case -999: /* Error from this class, no result found    */
  496.       return VERISIGN_TEMPORARY_ERROR;
  497.  
  498.     case 13:   /* Referral                                  */
  499.       return VERISIGN_REFERRAL;
  500.     }
  501.  
  502.     /* 99: General error */
  503.     /* 1000: Generic host error */
  504.     /* and any others */
  505.  
  506.     return VERISIGN_UNRECOGNISED_RESPONSE;
  507.   }
  508.  
  509.  
  510.   /*
  511.    * bool isError ($var)
  512.    *  Determine whether or not a variable is a PEAR exception
  513.    */
  514.   function isError ($var)
  515.   {
  516.     return (is_object ($var) and
  517.         substr (get_class ($var), -9) == 'Exception');
  518.   }
  519.     
  520.   /*
  521.    *    double Payment_Verisign_version(void)
  522.    *      Returns the current Payment_Verisign version.
  523.    */
  524.   function Payment_Verisign_version()
  525.   {
  526.     return (0.1);
  527.   }
  528.  
  529. }
  530.  
  531. class VerisignException extends PEAR_Error
  532. {
  533.   var $classname             = 'VerisignException';
  534.   var $error_message_prepend = 'Error in Payment_Verisign';
  535.  
  536.   function VerisignException($message)
  537.   {
  538.     $this->PEAR_Error($message);
  539.   }
  540. }
  541.  
  542. ?>
  543.