Advertisement
Guest User

SecurePay Class

a guest
Aug 31st, 2018
118
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 43.21 KB | None | 0 0
  1. <?php
  2. define('SECUREPAY_CURRENCIES','USD,AUD,CAD,CHF,DEM,EUR,FRF,GBP,GRD,HKD,ITL,JPY,NZD,SGD'); // CSV of valid SecurePay currencies
  3. define('SECUREPAY_STATUS_UNKNOWN', 0);
  4. define('SECUREPAY_STATUS_OK', 1);
  5. define('SECUREPAY_STATUS_INVALID_USER', 2);
  6. define('SECUREPAY_STATUS_INVALID_PASS', 3);
  7. define('SECUREPAY_STATUS_INVALID_URL', 4);
  8. define('SECUREPAY_STATUS_SERVER_DOWN', 5);
  9. define('SECUREPAY_STATUS_TIMEOUT', 6);
  10. define('SECUREPAY_STATUS_SERVER_ERR', 7);
  11. define('SECUREPAY_STATUS_XML_ERR', 8);
  12. define('SECUREPAY_STATUS_CONNECTION_ERR', 9);
  13. define('SECUREPAY_STATUS_APPROVED', 100);
  14. define('SECUREPAY_STATUS_DECLINED', 101);
  15.  
  16. define('SECUREPAY_REPEAT_NEVER',-1);
  17. define('SECUREPAY_REPEAT_DAILY',0);
  18. define('SECUREPAY_REPEAT_WEEKLY',1);
  19. define('SECUREPAY_REPEAT_FORTNIGHTLY',2);
  20. define('SECUREPAY_REPEAT_MONTHLY',3);
  21. define('SECUREPAY_REPEAT_QUARTERLY',4);
  22. define('SECUREPAY_REPEAT_HALF_YEARLY',5);
  23. define('SECUREPAY_REPEAT_YEARLY',6);
  24.  
  25. /**
  26. * SecurePay Credit-Card charging, pre-auth and periodic charging class
  27. * @access public
  28. * @author Matt Carter <m@ttcarter.com>
  29. */
  30. class SecurePay {
  31.     // Variable Declarations {{{
  32.  
  33.     /**
  34.     * The account name registed with Securepay.com.au
  35.     * @see Login()
  36.     * @access public
  37.     * @var string
  38.     */
  39.     public $AccountName;
  40.  
  41.     /**
  42.     * The account password for the $AccountName
  43.     * @see Login()
  44.     * @see $AccountName
  45.     * @access public
  46.     * @var string
  47.     */
  48.     public $AccountPassword;
  49.  
  50.     /**
  51.     * The seperate account password for the $AccountName when in test mode
  52.     * If this is blank and we are in test mode the $AccountPassword is assumed instead
  53.     * @see Login()
  54.     * @see $AccountName
  55.     * @access public
  56.     * @var string
  57.     */
  58.     public $TestAccountPassword;
  59.  
  60.     /**
  61.     * The last status code returned by Process()
  62.     * This code (since its a copy of the return of the Process() function)
  63.     * @see Process()
  64.     * @access Public
  65.     * @var int
  66.     */
  67.     public $Status;
  68.  
  69.     /**
  70.     * The last error to occur.
  71.     * This can be:
  72.     * * A validation error (e.g. 'Your Credit Card Number is Invalid')
  73.     * * Processing error (e.g. 'You're credit card details were declined')
  74.     *
  75.     * Use this variable as the error message if Valid() or Process() fails
  76.     * @access Public
  77.     * @var string
  78.     */
  79.     Public $Error;
  80.  
  81.     /**
  82.     * The merchant name for web logins
  83.     * @see WebLogin()
  84.     * @access Public
  85.     * @var string
  86.     */
  87.     public $WebMerchantName;
  88.  
  89.     /**
  90.     * The merchant username for web logins
  91.     * @see WebLogin()
  92.     * @access Public
  93.     * @var string
  94.     */
  95.     public $WebUserName;
  96.  
  97.     /**
  98.     * The merchant password for web logins
  99.     * @see WebLogin()
  100.     * @access Public
  101.     * @var string
  102.     */
  103.     public $WebUserPassword;
  104.  
  105.     /**
  106.     * The cookie jar used while using the web interface
  107.     * If this is null it can be assumed that we have not yet logged in
  108.     * @access public
  109.     * @see WebSignin()
  110.     * @var string
  111.     */
  112.     public $WebCookieJar;
  113.  
  114.     /**
  115.     * The web based merchant ID. Retrieved when requesting reports for the first time.
  116.     * @access public
  117.     * @var string
  118.     */
  119.     public $WebMerchantId;
  120.  
  121.     /**
  122.     * Indicates that the class should operate in test mode
  123.     * @access public
  124.     * @var bool
  125.     */
  126.     public $TestMode;
  127.  
  128.  
  129.     /**
  130.     * Indicates if the transaction to be processed is actually a PreAuth rather than a normal charge
  131.     * @access public
  132.     * @var bool
  133.     */
  134.     public $PreAuth;
  135.  
  136.     /**
  137.     * The credit card number to work with
  138.     * @access public
  139.     * @var int|string
  140.     */
  141.     public $Cc;
  142.  
  143.     /**
  144.     * Short string to denote the expiry date of the credit card
  145.     * This is in the form: 'mm/yy' where the first two are a zero padded month and zero padded year
  146.     * @access public
  147.     * @var char(5)
  148.     */
  149.     public $ExpiryDate;
  150.     public $cardHolderName;
  151.     /**
  152.     * The Credit Card Verification number / CV2
  153.     * This is optional as to whether the card type supports it
  154.     * @var char(3)
  155.     * @access public
  156.     */
  157.     public $Cvv;
  158.  
  159.     /**
  160.     * The amount (as a float) that should be charged to the card
  161.     * This is listed in the currency specified in the $ChargeCurrency Variable
  162.     * @access public
  163.     * @var float
  164.     * @see $ChargeCurrency
  165.     */
  166.     public $ChargeAmount;
  167.  
  168.     /**
  169.     * The currency code relevent to the $ChargeAmount
  170.     * @access public
  171.     * @see $ChargeAmount
  172.     * @var char(3)
  173.     */
  174.     public $ChargeCurrency;
  175.  
  176.     /**
  177.     * Unique order number to identify this transaction.
  178.     * This is typically an invoice number
  179.     * Must be at least 1 characters
  180.     * Must be at most 60 characters
  181.     * @access public
  182.     * @var string
  183.     */
  184.     public $OrderId;
  185.  
  186.     /**
  187.     * Last message ID requested
  188.     * This code is only really useful for debugging with Securepay.com.au who track these codes
  189.     * @access public
  190.     * @var string
  191.     */
  192.     public $LastMesageId;
  193.  
  194.     /**
  195.     * Preauth ID if we are putting though a PreAuth payment (i.e. last call to Process() had $this->PreAuth == True)
  196.     * If a pre-auth is sent though before an actual transaction the preauth code is stored here to reserve the transaction for the next payment
  197.     * @access public
  198.     * @var string
  199.     */
  200.     public $PreAuthId;
  201.  
  202.     /**
  203.      * Last Transaction ID if successful
  204.      * If a transaction is successful, the transaction ID will be stored here for you to easily retrieve
  205.      * @access public
  206.      * @var int
  207.      * @since 2014-02-13
  208.      */
  209.     public $TransactionId;
  210.  
  211.     /**
  212.     * The last dispatched request
  213.     * @access public
  214.     * @var string
  215.     */
  216.     public $RequestXml;
  217.  
  218.     /**
  219.     * The XML returned by the server in response to RequestXml
  220.     * @access public
  221.     * @see RequestXml
  222.     * @var array
  223.     */
  224.     public $ResponseXml;
  225.  
  226.     /**
  227.     * The XML tree provided from the last transaction
  228.     * @access public
  229.     * @var array
  230.     */
  231.     public $ResponseTree;
  232.  
  233.     /**
  234.     * Securepay status code from the last transaction
  235.     * @access public
  236.     * @var int
  237.     */
  238.     public $StatusCode;
  239.  
  240.     /**
  241.     * Securepay status code text from the last transaction
  242.     * This is the english equivelent to the above $StatusCode value
  243.     * @access public
  244.     * @var string
  245.     * @see StatusCode
  246.     */
  247.     public $StatusCodeText;
  248.  
  249.     /**
  250.     * Securepay response code from the last transaction
  251.     * @access public
  252.     * @var int
  253.     */
  254.     public $ResponseCode;
  255.  
  256.     /**
  257.     * Securepay response code text from the last transaction
  258.     * This is the english equivelent to the above $ResponseCode value
  259.     * @access public
  260.     * @var string
  261.     * @see ResponseCode
  262.     */
  263.     public $ResponseCodeText;
  264.  
  265.     /**
  266.     * Whether to repeat the transaction as a periodic or once-off payment
  267.     * See the 'SECUREPAY_REPEAT_*' constants for a list of values
  268.     * Default value is SECUREPAY_REPEAT_NEVER
  269.     * @access public
  270.     * @var bool
  271.     */
  272.     public $Repeat;
  273.  
  274.     /**
  275.     * If $Repeat=SECUREPAY_REPEAT_DAILY this represents how many days should elapase before the next charge
  276.     * @access public
  277.     * @var int
  278.     */
  279.     public $RepeatInterval;
  280.  
  281.     /**
  282.     * Epoc timstamp on when to start the repeat payments
  283.     * @access public
  284.     * @var int
  285.     */
  286.     public $RepeatStart;
  287.  
  288.     /**
  289.     * Number of repeating payments to max out on
  290.     * Set to 'zero' for never ending periodic charge
  291.     * @access public
  292.     * @var int
  293.     */
  294.     public $RepeatCount;
  295.  
  296.     /**
  297.     * Automatically trigger the repeat payment after processing.
  298.     * The default is TRUE
  299.     * If this is disabled a manual trigger request will need to be made when putting though a repeat payment request
  300.     * @access public
  301.     * @var bool
  302.     */
  303.     public $RepeatTrigger;
  304.  
  305.     // End of Variable Declarations }}}
  306.  
  307.     // General use functionality {{{
  308.  
  309.     /**
  310.     * Constructor function.
  311.     * This can optionally be passed the account_name and account_password variables.
  312.     * @see Login()
  313.     * @return void
  314.     */
  315.     function SecurePay($AccountName = null, $AccountPassword = null, $TestMode = FALSE) {
  316.         if ($AccountName && $AccountPassword)
  317.             $this->Login($AccountName, $AccountPassword, $TestMode);
  318.         $this->ChargeCurrency = 'AUD'; // Default currency to USD
  319.         $this->Repeat = SECUREPAY_REPEAT_NEVER;
  320.         $this->RepeatTrigger = TRUE;
  321.     }
  322.  
  323.     /**
  324.     * Shorthand function to set the account_name and account_password variables
  325.     * @param string $AccountName The account name to use for payments (provided by SecurePay)
  326.     * @param string $AccountPassword The account password to use for payments (provided by SecurePay)
  327.     * @param bool $TestMode Whether to use TestMode with all transactions
  328.     * @see SecurePay()
  329.     * @see $AccountName
  330.     * @see $AccountPassword
  331.     * @return void
  332.     */
  333.     function Login($AccountName, $AccountPassword, $TestMode = FALSE) {
  334.         $this->AccountName = $AccountName;
  335.         $this->AccountPassword = $AccountPassword;
  336.         $this->TestMode = $TestMode;
  337.     }
  338.  
  339.     /**
  340.     * Login to the main website login page. This is used when retrieving periodic payment information
  341.     */
  342.     function WebLogin($WebMerchantName, $WebUserName, $WebUserPassword) {
  343.         $this->WebMerchantName = $WebMerchantName;
  344.         $this->WebUserName = $WebUserName;
  345.         $this->WebUserPassword = $WebUserPassword;
  346.     }
  347.  
  348.     /**
  349.     * Enable or disable the testing suite
  350.     * When TestMode is enabled all functionality uses the test SecureXML API servers instead
  351.     * @param bool $TestMode Optional indicator as to whether test mode is enabled or not. If omitted TestMode is enabled
  352.     */
  353.     function TestMode($TestMode = TRUE) {
  354.         $this->TestMode = $TestMode;
  355.     }
  356.  
  357.     /**
  358.     * Shorthand function to set all relevent fields and process a payment
  359.     * If any field is supplied it overrides the existing model function if not or no parameters are specified the transaction is just dispatched
  360.     * @param float $ChargeAmount Optional amount that is to be deducted from the given Credit Card (e.g. '4.12' => '$4.12')
  361.     * @param string $ChargeCurrency Optional currency that the above $ChargeAmount is specified in (e.g. 'USD')
  362.     * @param string $Cc Optional Credit Card number to use
  363.     * @param string $ExpiryDate Optional expiry date of the Credit Card (e.g. '07/09' => 'July 2009')
  364.     * @param string $Cvv Optional CVV code (if the card has one)
  365.     * @param string $OrderId Optional local order ID reference to use for this transaction. This must be unique
  366.     * @param bool $PreAuth Indicate that this transaction is a preauth
  367.     * @return int Returns the corresponding SECUREPAY_STATUS_* code
  368.     */
  369.     function Process($ChargeAmount = null, $ChargeCurrency = null, $Cc = null, $ExpiryDate = null, $Cvv = null, $cardHolderName = null, $OrderId = null, $PreAuth = FALSE) {
  370.         // Set class variables from function call for later use {{{
  371.         if ($ChargeAmount) $this->ChargeAmount = $ChargeAmount;
  372.         if ($ChargeCurrency) $this->ChargeCurrency = $ChargeCurrency;
  373.         if ($Cc) $this->Cc = $Cc;
  374.         if ($ExpiryDate) $this->ExpiryDate = $ExpiryDate;
  375.         if ($Cvv) $this->Cvv = $Cvv;       
  376.         if ($cardHolderName) $this->cardHolderName = $cardHolderName;      
  377.         if ($OrderId) $this->OrderId = $OrderId;
  378.         if ($PreAuth) $this->PreAuth = $PreAuth;
  379.         // }}}
  380.         $this->ValidExpiryDate(); // Reformat the expiry date if necessary
  381.         if ($this->Cc)
  382.             $this->Cvv = str_pad($this->Cvv, 3, '0', STR_PAD_LEFT);
  383.         $this->RequestXml = $this->_ComposePayment();
  384.         $this->ResponseXml = $this->_Dispatch($this->RequestXml);
  385.        
  386.        
  387.         $this->ResponseTree = simplexml_load_string($this->ResponseXml);
  388.         $this->StatusCode = $this->ResponseTree->Status->statusCode;
  389.         $this->StatusCodeText = $this->ResponseTree->Status->statusDescription;
  390.         $server_code = $this->_TranslateServerCode($this->StatusCode);
  391.         if (isset($this->ResponseTree->Payment->TxnList->Txn->responseCode)) { // Has a response code
  392.             $this->ResponseCode = $this->ResponseTree->Payment->TxnList->Txn->responseCode;
  393.             $this->ResponseCodeText = $this->ResponseTree->Payment->TxnList->Txn->responseText;
  394.             if ($this->PreAuth) // Was requesting a PreAuth...
  395.                 $this->PreAuthId = $this->ResponseTree->Payment->TxnList->Txn->preauthID; // Store the PreAuth return code in $this->PreAuth
  396.             $result = $this->_TranslateResponseCode($this->ResponseCode);
  397.             if ($result == SECUREPAY_STATUS_APPROVED && !empty($this->ResponseTree->Payment->TxnList->Txn->txnID))
  398.                 $this->TransactionId = (string) $this->ResponseTree->Payment->TxnList->Txn->txnID;
  399.  
  400.         } else if(isset($this->ResponseTree->Periodic->PeriodicList->PeriodicItem->responseCode)) { // Has a response code - periodic style
  401.             $this->ResponseCode = $this->ResponseTree->Periodic->PeriodicList->PeriodicItem->responseCode;
  402.             $this->ResponseCodeText = $this->ResponseTree->Periodic->PeriodicList->PeriodicItem->responseText;
  403.             if ($this->PreAuth) // Was requesting a PreAuth...
  404.                 $this->PreAuthId = $this->ResponseTree->Payment->TxnList->Txn->preauthID; // Store the PreAuth return code in $this->PreAuth
  405.             $result = $this->_TranslateResponseCode($this->ResponseCode);
  406.  
  407.         } else { // No success with the response code - return the server code error
  408.             $result = $server_code;
  409.         }
  410.         if ($this->IsRepeat() && $this->RepeatTrigger) // Automatically trigger the response
  411.             $this->Trigger();
  412.         return $this->Status = $result;
  413.     }
  414.  
  415.     /**
  416.      * Refunds a Transaction on Secure Pay
  417.      * If any field is supplied it overrides the existing model function if not or no parameters are specified the transaction is just dispatched
  418.      * @param string $TransactionId The TransactionId as provided by SecurePay
  419.      * @param string $OrderId       The order ID you have this transaction. Must match the original transaction
  420.      * @param float  $ChargeAmount  The amount to refund, up-to the total original transaction amount
  421.      * @return int   Returns the corresponding SECUREPAY_STATUS_* code
  422.      * @author Phil Hawthorne <me@philhawthorne.com>
  423.      * @since  2014-02-13
  424.      */
  425.     function Refund($TransactionId = null,$OrderId = null,$ChargeAmount=null){
  426.         // Set class variables from function call for later use {{{
  427.         if ($TransactionId) $this->TransactionId = $TransactionId;
  428.         if ($ChargeAmount) $this->ChargeAmount = $ChargeAmount;
  429.         if ($OrderId) $this->OrderId = $OrderId;
  430.         // }}}
  431.  
  432.         $this->RequestXml = $this->_ComposeRefund();
  433.         $this->ResponseXml = $this->_Dispatch($this->RequestXml);
  434.         $this->ResponseTree = simplexml_load_string($this->ResponseXml);
  435.         $this->StatusCode = $this->ResponseTree->Status->statusCode;
  436.         $this->StatusCodeText = $this->ResponseTree->Status->statusDescription;
  437.         $server_code = $this->_TranslateServerCode($this->StatusCode);
  438.         if (isset($this->ResponseTree->Payment->TxnList->Txn->responseCode)) { // Has a response code
  439.             $this->ResponseCode = $this->ResponseTree->Payment->TxnList->Txn->responseCode;
  440.             $this->ResponseCodeText = $this->ResponseTree->Payment->TxnList->Txn->responseText;
  441.             if ($this->PreAuth) // Was requesting a PreAuth...
  442.                 $this->PreAuthId = $this->ResponseTree->Payment->TxnList->Txn->preauthID; // Store the PreAuth return code in $this->PreAuth
  443.             $result = $this->_TranslateResponseCode($this->ResponseCode);
  444.             if ($result == SECUREPAY_STATUS_APPROVED && !empty($this->ResponseTree->Payment->TxnList->Txn->txnID))
  445.                 $this->TransactionId = (string) $this->ResponseTree->Payment->TxnList->Txn->txnID;
  446.  
  447.         } else { // No success with the response code - return the server code error
  448.             $result = $server_code;
  449.         }
  450.  
  451.         return $this->Status = $result;
  452.     }
  453.  
  454.     /**
  455.     * Trigger (start) a repeating payment.
  456.     * This function is automatically invoked if $RepeatTrigger is boolean TRUE
  457.     * @param string $OrderID Optional order ID to use for the trigger. If unspecified the OrderID from the previous transaction is used instead
  458.     * @return int Returns the corresponding SECUREPAY_STATUS_* code
  459.     * @see RepeatTrigger
  460.     */
  461.     function Trigger($OrderId = null) {
  462.         if ($OrderId) $this->OrderId = $OrderId;
  463.         $this->RequestXml = $this->_ComposeTrigger();
  464.         $this->ResponseXml = $this->_Dispatch($this->RequestXml);
  465.         $this->ResponseTree = simplexml_load_string($this->ResponseXml);
  466.         $server_code = $this->_TranslateServerCode($this->ResponseTree->Status->statusCode);
  467.         if (isset($this->ResponseTree->Payment->TxnList->Txn->responseCode)) { // Has a response code
  468.             return $this->_TranslateResponseCode($this->ResponseCode = $this->ResponseTree->Payment->TxnList->Txn->responseCode);
  469.         } else { // No success with the response code - return the server code error
  470.             return $server_code;
  471.         }
  472.     }
  473.  
  474.     /**
  475.     * Preforms a simple test connection to the Securepay server and returns a boolean on success
  476.     * @return bool TRUE if the server connection and login information returned a correct result
  477.     */
  478.     function TestConnection() {
  479.         $this->RequestXml = $this->_ComposeEcho();
  480.         $this->ResponseXml = $this->_Dispatch($this->RequestXml);
  481.         $this->ResponseTree = simplexml_load_string($this->ResponseXml);       
  482.         return ($this->_TranslateServerCode($this->ResponseTree->Status->statusCode) == SECUREPAY_STATUS_OK);
  483.     }
  484.  
  485.     /**
  486.     * Signs into the web interface. This should only be done once to prevent unnecessay overhead
  487.     * This function can be called multiple times but will only actually do something the first time round.
  488.     * Thus all methods that use the web interface should start by calling this function
  489.     */
  490.     function WebSignin() {
  491.         if (!empty($this->WebCookieJar))
  492.             return TRUE;
  493.         if (!function_exists('curl_init'))
  494.             trigger_error('You do not have Curl installed on this server', E_ERROR);
  495.         $tempdir = (function_exists('sys_get_temp_dir')) ? sys_get_temp_dir() : '/tmp'; // Attempt to figure out a temporary directory
  496.         $this->WebCookieJar = tempnam('/tmp', 'securepay-cookie-jar-');
  497.         touch($this->WebCookieJar);
  498.         $this->_WebRetrieve('https://login.securepay.com.au/login/verify.jsp', "merchantId={$this->WebMerchantName}&userName={$this->WebUserName}&password={$this->WebUserPassword}&loginType=M");
  499.         return TRUE; // FIXME: Query if the above succeded and return error if not
  500.     }
  501.  
  502.     /**
  503.     * Retreieves all transaction information between two optional dates.
  504.     * If no dates are supplied. Today is assumed.
  505.     * The first parameter 'datefrom' also accepts the convenience value 'yesterday' to retrieve information from the previous day (NOTE: Not the previous working day)
  506.     * @param int|string $datefrom Optional date range to work from. This is a Unix Epoc. Also accepts 'yesterday' as a value. Today is assumed if omitted
  507.     * @param int $dateto Optional date range to. Today is assumed if omitted.
  508.     * @return array The transaction history matching the above criteria
  509.     */
  510.     function GetTransactions($datefrom = null, $dateto = null) {
  511.         $this->WebSignin();
  512.         $output = array();
  513.  
  514.         $post = 'view_type=screen&card_type=-2&search_when=date_range';
  515.         if ($datefrom == 'yesterday') {
  516.             $datefrom = mktime(0,0,0,0,-1);
  517.             $dateto = mktime(23,59,0,0,-1);
  518.         } elseif (!$datefrom && !$dateto) { // Nulls, assume today
  519.             $datefrom = mktime(0,0,0);
  520.             $dateto = mktime(23,59,59);
  521.         }
  522.         $post .= "&date_from=" . urlencode(date('j M Y', $datefrom)) . "&hours_from_val=" . date('H', $datefrom) . "&minutes_from_val=" . date('i', $datefrom);
  523.         $post .= "&date_to=" . urlencode(date('j M Y', $dateto)) . "&hours_to_val=" . date('H', $dateto) . "&minutes_to_val=" . date('i', $dateto);
  524.  
  525.         $response = $this->_WebRetrieve('https://login.securepay.com.au/login/login.jsp?id=ntxnlist', $post);
  526.         preg_match_all('!<tr class="listing_payment" ><td >(.+?)</td><td ><a href="login.jsp\?id=txndetail&txn=(.+?)">(.+?)</a></td><td class="centered_col" >(.+?)</td><td class="centered_col" >(.+?)<img src="common/images/newlogos/.+?" height="17" /></td><td class="amount_col" >(.+?)</td><td class="centered_col" >(.+?)</td><td class=".+?" ><span class=".+?" >(.+?)</span><span class=".+?" > (.+?)</span></td><td class="txn_type" >(.+?)</td></tr>!', $response, $matches, PREG_SET_ORDER);
  527.         foreach ($matches as $match) {
  528.             $output[$match[2]] = array(
  529.                 'merchantid' => $match[1],
  530.                 'transactionid' => $match[2],
  531.                 'transactionref' => $match[3],
  532.                 'date' => strtotime($match[4]),
  533.                 'cc' => $match[5],
  534.                 'amount' => $match[6],
  535.                 'currency' => $match[7],
  536.                 'code' => $match[8],
  537.                 'result' => $match[9],
  538.                 'type' => $match[10],
  539.             );
  540.         }
  541.         return $output;
  542.     }
  543.  
  544.     /**
  545.     * Retrieves the client status information from SecurePay
  546.     * If given a specific client id (usually the username) this will return just that relevent hash of information
  547.     * @param int|string $clientid Optional single client ID that should be retrieved
  548.     * @return array Either all client Id's discovered as keys for information or the single client information hash
  549.     */
  550.     function GetClientInfo($clientid = null) {
  551.         $this->WebSignin();
  552.         if (empty($this->WebMerchantId)) { // Not yet calculated the merchant ID
  553.             $page = $this->_WebRetrieve('https://login.securepay.com.au/login/login.jsp?id=perreport');
  554.             if (preg_match('/<input type="hidden" name="merchid" value="(.+)">/', $page, $matches)) {
  555.                 $this->WebMerchantId = $matches[1];
  556.             } else {
  557.                 trigger_error('Did not recieve a merchant ID from the periodic billing page. Perhaps SecurePay have changed their API?', E_ERROR);
  558.             }
  559.         }
  560.         $csvdef = array(); // CSV definition holder
  561.         $output = array();
  562.  
  563.         foreach (explode("\n", $this->_WebRetrieve('https://login.securepay.com.au/login/merchant/periodic/report.jsp', "id=perview&merchid={$this->WebMerchantId}" . (($clientid) ? "&clientid={$clientid}" : '') )) as $line) {
  564.             if (($line = trim($line)) == '') continue; // Ignore blank lines
  565.             $bits = explode(",", $line);
  566.             $set = array();
  567.             if (empty($csvdef)) { // Not yet defined CSV fields
  568.                 $csvdef = array_map('strtolower',$bits);
  569.             } else { // Already defined CSV fields
  570.                 for ($b = 0; $b < count($bits); $b++)
  571.                     $set[$csvdef[$b]] = trim($bits[$b],'"');
  572.                 $output[$set['clientid']] = $set;
  573.             }
  574.         }
  575.         return ($clientid) ? current($output) : $output; // If it was a specific request just return that branch
  576.     }
  577.  
  578.     /**
  579.     * Setup a recurring payment with error checking
  580.     * @param string|int $when The name of the recurring type (i.e. the constants SECUREPAY_REPEAT_* or a simple word e.g. 'weekly')
  581.     * @param int $interval The spacing between the payments (e.g. if 'when'='monthly' and 'interval'=2 - the payment will occur every two weeks).
  582.     * @param int $count The count of the payments to apply (i.e. '3 repeating payments'). Set to zero (the default) for continuous
  583.     */
  584.     function SetupRepeat($when, $count = 0) {
  585.         if (is_string($when)) { // Translate $when to constant if supported
  586.             $translate = array(
  587.                 'daily' => SECUREPAY_REPEAT_DAILY,
  588.                 'weekly' => SECUREPAY_REPEAT_WEEKLY,
  589.                 'fortnightly' => SECUREPAY_REPEAT_FORTNIGHTLY,
  590.                 'monthly' => SECUREPAY_REPEAT_MONTHLY,
  591.                 'quarterly' => SECUREPAY_REPEAT_QUARTERLY,
  592.                 'half_yearly' => SECUREPAY_REPEAT_HALF_YEARLY,
  593.                 'yearly' => SECUREPAY_REPEAT_YEARLY
  594.             );
  595.             if (isset($translate[$when])) {
  596.                 $when = $translate[$when];
  597.             } else
  598.                 trigger_error("Unknown repeat period '$when'. See the SECUREPAY_REPEAT_* constants for a list of supported time periods", E_USER_ERROR);
  599.         } elseif ($when < 0) {
  600.             trigger_error("Repeat period (\$when) must be above zero", E_USER_ERROR);
  601.         } elseif ($when > 6) {
  602.             trigger_error("Repeat period (\$when) must be below 6 (yearly)", E_USER_ERROR);
  603.         }
  604.         $this->Repeat = $when;
  605.         $this->RepeatCount = $count;
  606.     }
  607.  
  608.     /**
  609.     * Quick boolean return for if the pending transaction is a repeat transaction
  610.     * @return bool TRUE if the pending transaction is a repeat transaction
  611.     */
  612.     function IsRepeat() {
  613.         return ($this->Repeat > SECUREPAY_REPEAT_NEVER);
  614.     }
  615.  
  616.     // End of General use functionality }}}
  617.  
  618.     // Validation tests {{{
  619.     /**
  620.     * Global validation test that checks all other child validation tests
  621.     * @see Valid*
  622.     * @return bool FALSE if ANY validation test fails, TRUE if all pass successfully
  623.     */
  624.     function Valid() {
  625.         return (
  626.             $this->ValidCC()
  627.             && $this->ValidExpiryDate()
  628.             && $this->ValidCvv()
  629.             && $this->ValidChargeAmount()
  630.             && $this->ValidChargeCurrency()
  631.             && $this->ValidOrderId()
  632.         );
  633.        
  634.     }
  635.  
  636.     /**
  637.     * Validates Credit Card number and returns a bool indicating its validity
  638.     * @param string|int $Cc Optional credit card number to validate. If none is specified the objects Credit Card number is used instead
  639.     * @return bool TRUE if the CC number passes validation
  640.     */
  641.     function ValidCc($Cc = null) {
  642.         $test_cc = ($Cc) ? $Cc : $this->Cc;
  643.         if (preg_match('/[0-9]{12,16}/',$test_cc) > 0) {
  644.             return TRUE;
  645.         } else {
  646.             $this->Error = 'Invalid Credit Card Number';
  647.             return FALSE;
  648.         }
  649.     }
  650.  
  651.     /**
  652.     * Validates an expiry date and ensures that it confirms to the SecurePay standards
  653.     * @param string $ExpiryDate Optional expiry date to test. If none is specified the objects expiry date is used instead
  654.     * @return bool TRUE if the expiry date passes validation
  655.     */
  656.     function ValidExpiryDate($ExpiryDate = null) {
  657.         $test_expiry = ($ExpiryDate) ? $ExpiryDate : $this->ExpiryDate;
  658.         if (preg_match('!([0-9]{1,2})/([0-9]{2,4})!',$test_expiry, $matches)) {
  659.             if (strlen($matches[1]) == 1)
  660.                 $matches[1] = "0{$matches[1]}";
  661.             if (strlen($matches[2]) == 4)
  662.                 $matches[2] = substr($matches[2],-2);
  663.             $this->ExpiryDate = "{$matches[1]}/{$matches[2]}";
  664.  
  665.             return ( ($matches[1] > 0) && ($matches[1] < 13) && ($matches[2] >= date('y')) && ($matches[2] < date('y') + 30) ); // Check that month and years are valid
  666.         } else {
  667.             $this->Error = 'Invalid Expiry Date';
  668.             return FALSE; // Failed RegExp checks
  669.         }
  670.     }
  671.  
  672.     /**
  673.     * Validates a CVV code and ensures that it confirms to the SecurePay standards
  674.     * @param string|int $CVV Optional CVV to test. If none is specified the objects CVV is used instead
  675.     * @param bool $ForceValue Optional value indicating that the Cvv HAS to contain a value
  676.     * @return bool TRUE if the CVV passes validation
  677.     */
  678.     function ValidCvv($Cvv = null, $ForceValue = FALSE) {
  679.         $test_cvv = ($Cvv) ? $Cvv : $this->Cvv;
  680.         if ($test_cvv) {
  681.             return (preg_match('/[0-9]{3,4}/',$test_cvv, $matches));
  682.         } elseif ($ForceValue) { // Has to contain a value but doesn't
  683.             $this->Error = 'Invalid CVV code';
  684.             return FALSE;
  685.         } else // Does not have to contain and value and doesn't
  686.             return TRUE;
  687.     }
  688.  
  689.     /**
  690.     * Validates a Charge Amount and ensures that it confirms to the SecurePay standards
  691.     * @param float $Amount Optional Charge Amount to test. If none is specified the objects Charge Amount is used instead
  692.     * @return bool TRUE if the Charge Amount passes validation
  693.     */
  694.     function ValidChargeAmount($ChargeAmount = null) {
  695.         $test_amount = ($ChargeAmount) ? $ChargeAmount : $this->ChargeAmount;
  696.         if ($test_amount > 0) {
  697.             return TRUE;
  698.         } else {
  699.             $this->Error = 'Invalid charge amount';
  700.             return FALSE;
  701.         }
  702.     }
  703.  
  704.     /**
  705.     * Validates a Charge Currency and ensures that it confirms to the SecurePay standards
  706.     * @param string $ChargeCurrency Optional Charge Currency to test. If none is specified the objects Charge Currency is used instead
  707.     * @return bool TRUE if the Charge Currency passes validation
  708.     */
  709.     function ValidChargeCurrency($ChargeCurrency = null) {
  710.         $test_currency = ($ChargeCurrency) ? $ChargeCurrency : $this->ChargeCurrency;
  711.         $valid_currencies = explode(',',SECUREPAY_CURRENCIES);
  712.         if (in_array($test_currency, $valid_currencies)) {
  713.             return TRUE;
  714.         } else {
  715.             $this->Error = 'Invalid charge currency';
  716.             return FALSE;
  717.         }
  718.     }
  719.  
  720.     /**
  721.     * Validates a Order ID and ensures that it confirms to the SecurePay standards
  722.     * @param string|int $Amount Optional Order ID to test. If none is specified the objects Order ID is used instead
  723.     * @return bool TRUE if the Order Id Amount passes validation
  724.     */
  725.     function ValidOrderId($OrderId = null) {
  726.         $test_order = ($OrderId) ? $OrderId : $this->OrderId;
  727.         if ( (strlen($test_order) > 0) && (strlen($test_order) <= 60) ) {
  728.             return TRUE;
  729.         } else {
  730.             $this->Error = 'Invalid Order ID';
  731.             return FALSE;
  732.         }
  733.     }
  734.  
  735.  
  736.     // End of Validation tests }}}
  737.  
  738.     // Private functions {{{
  739.     /**
  740.     * Generates a new message ID
  741.     * @return string A string of 30 random hex characters
  742.     */
  743.     function _GetMessageId() {
  744.         $code = '';
  745.         foreach (range(1,30) as $offset)
  746.             $code .= dechex(rand(0,15));
  747.         return $code;
  748.     }
  749.  
  750.     /**
  751.     * Translates a given SecurePay server status code into a constant equivelent
  752.     * @param int $SpCode The SecurePay status integer code
  753.     * @return const A constant of the SECUREPAY_STATUS_* types
  754.     */
  755.     function _TranslateServerCode($SpCode) {
  756.         switch($SpCode) {
  757.             case 000:
  758.                 $this->Error = '';
  759.                 return SECUREPAY_STATUS_OK;
  760.             case 504:
  761.                 $this->Error = 'We are currently experiencing technical difficulties (Error: Credential failure with merchant ID). Please try again later';
  762.                 return SECUREPAY_STATUS_INVALID_USER;
  763.             case 505:
  764.                 $this->Error = 'We are currently experiencing technical difficulties (Error: Invalid SecurePay URL). Please try again later';
  765.                 return SECUREPAY_STATUS_INVALID_URL;
  766.             case 510:
  767.                 $this->Error = 'The credit card processor is currently experiencing difficulties. Please try again later';
  768.                 return SECUREPAY_STATUS_SERVER_DOWN;
  769.             case 512:
  770.                 $this->Error = 'The credit card processor is currently experiencing difficulties. Please try again later';
  771.                 return SECUREPAY_STATUS_TIMEOUT;
  772.             case 513:
  773.             case 514:
  774.             case 515:
  775.             case 545:
  776.                 $this->Error = 'The credit card processor is currently experiencing difficulties. Please try again later';
  777.                 return SECUREPAY_STATUS_SERVER_ERR;
  778.             case 516:
  779.             case 517:
  780.             case 518:
  781.             case 575:
  782.             case 577:
  783.             case 580:
  784.                 $this->Error = 'We are currently experiencing technical difficulties (Error: XML Processing Fault). Please try again later';
  785.                 return SECUREPAY_STATUS_XML_ERR;
  786.             case 524:
  787.                 $this->Error = 'We are currently experiencing technical difficulties (Error: Connection fault). Please try again later';
  788.                 return SECUREPAY_STATUS_CONNECTION_ERR;
  789.             case 550:
  790.                 $this->Error = 'We are currently experiencing technical difficulties (Error: Credential failure with password). Please try again later';
  791.                 return SECUREPAY_STATUS_INVALID_PASS;
  792.             case 595:
  793.                 $this->Error = 'Credit card declined';
  794.                 return SECUREPAY_STATUS_DENIED;
  795.         }
  796.     }
  797.  
  798.     /**
  799.     * Translates a SecurePay server reposnse code into a constant equivelent
  800.     * @param int $SpCode The SecurePay response integer code
  801.     * @return const A constant of the SECUREPAY_STATUS_* types
  802.     */
  803.     function _TranslateResponseCode($SpCode) {
  804.         if ( ($SpCode == 0) || ($SpCode == 8) || ($SpCode == 77) ) {
  805.             return SECUREPAY_STATUS_APPROVED;
  806.         } else {
  807.             $this->Error = 'Your credit card details were declined';
  808.             return SECUREPAY_STATUS_DECLINED;
  809.         }
  810.     }
  811.  
  812.  
  813.     /**
  814.     * Send the request to SecurePay.com.au via SSL
  815.     * Requires CURL to be installed
  816.     * @param string $Xml The XML request to be sent. This is composed by one of the _Compose* functions
  817.     * @access private
  818.     */
  819.     function _Dispatch($xml) {
  820.         if (!function_exists('curl_init'))
  821.             trigger_error('You do not have Curl installed on this server', E_USER_ERROR);
  822.         $curl = curl_init();
  823.         if ($this->IsRepeat()) { // Periodic payment
  824.             $url = ($this->TestMode) ? 'https://www.securepay.com.au/test/periodic' : 'https://www.securepay.com.au/xmlapi/periodic';
  825.         } else // Once-off payment
  826.             $url = ($this->TestMode) ? 'https://test.securepay.com.au/xmlapi/payment' : 'https://api.securepay.com.au/xmlapi/payment';
  827.  
  828.         curl_setopt($curl, CURLOPT_URL, $url);
  829.         curl_setopt($curl, CURLOPT_FOLLOWLOCATION, TRUE); // Follow redirects
  830.         curl_setopt($curl, CURLOPT_POST, TRUE);
  831.         curl_setopt($curl, CURLOPT_POSTFIELDS, $xml);
  832.         curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE); // Return the HTTP response from the curl_exec function
  833.        
  834.         if (defined('CURL_SSLVERSION_TLSv1_0')) { // TLSv1_0 supported (PHP5.5+)
  835.             // Switch to SSLv3 due to the OpenSSL + Poodle fiascos
  836.             // thanks to cleathley for pointing this out and to beitsafedaniel for fixing the fix
  837.             // @url https://github.com/hash-bang/PHP-SecurePay/issues/6
  838.             curl_setopt($curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_0);
  839.             curl_setopt($curl, CURLOPT_SSL_CIPHER_LIST, 'TLSv1');
  840.         } else if (defined('CURL_SSLVERSION_TLSv1')) { // Covers all TLSv1 minor versions
  841.             curl_setopt($curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
  842.         } // else - rely on PHP figuring out the best option for CURLOPT_SSLVERSION as per note at http://php.net/manual/en/function.curl-setopt.php
  843.         $response = curl_exec($curl);
  844.         curl_close($curl);
  845.         return $response;
  846.     }
  847.  
  848.     /**
  849.     * Creates the XML request for a SecurePay Echo
  850.     * @return string The XML string for a SecurePay Echo request
  851.     * @access private
  852.     */
  853.     function _ComposeEcho() {
  854.         $this->LastMessageId = $this->_GetMessageId();
  855.         $timestamp = date('YdmHis000+Z'); // See Appendix E of the SecureXML standard for more details on this date format
  856.         $password = ($this->TestMode && $this->TestAccountPassword) ? $this->TestAccountPassword : $this->AccountPassword;
  857.         $message = "<?xml version=\"1.0\" encoding=\"UTF-8\"?" . ">\n";
  858.         $message .= "<SecurePayMessage>\n";
  859.         $message .= "\t<MessageInfo>\n";
  860.         $message .= "\t\t<messageID>{$this->LastMessageId}</messageID>\n";
  861.         $message .= "\t\t<messageTimestamp>$timestamp</messageTimestamp>\n";
  862.         $message .= "\t\t<timeoutValue>60</timeoutValue>\n";
  863.         $message .= "\t\t<apiVersion>xml-4.2</apiVersion>\n";
  864.         $message .= "\t</MessageInfo>\n";
  865.         $message .= "\t<MerchantInfo>\n";
  866.         $message .= "\t<merchantID>{$this->AccountName}</merchantID>\n";
  867.         $message .= "\t<password>{$password}</password>\n";
  868.         $message .= "\t</MerchantInfo>\n";
  869.         $message .= "\t<RequestType>Echo</RequestType>\n";
  870.         $message .= "</SecurePayMessage>";
  871.         return $message;
  872.     }
  873.  
  874.     /**
  875.     * Creates the XML request for a SecurePay trigger
  876.     * @return string The XML string for a SecurePay trigger request
  877.     * @access private
  878.     */
  879.     function _ComposeTrigger() {
  880.         $this->LastMessageId = $this->_GetMessageId();
  881.         $cents = round($this->ChargeAmount * 100); // Convert to cents
  882.         $timestamp = date('YdmHis000+Z'); // See Appendix E of the SecureXML standard for more details on this date format
  883.         $message = "<?xml version=\"1.0\" encoding=\"UTF-8\"?" . ">\n";
  884.         $password = ($this->TestMode && $this->TestAccountPassword) ? $this->TestAccountPassword : $this->AccountPassword;
  885.  
  886.         $message .= "<SecurePayMessage>\n";
  887.         $message .= "\t<MessageInfo>\n";
  888.         $message .= "\t\t<messageID>{$this->LastMessageId}</messageID>\n";
  889.         $message .= "\t\t<messageTimestamp>$timestamp</messageTimestamp>\n";
  890.         $message .= "\t\t<timeoutValue>60</timeoutValue>\n";
  891.         $message .= "\t\t<apiVersion>spxml-3.0</apiVersion>\n";
  892.         $message .= "\t</MessageInfo>\n";
  893.         $message .= "\t<MerchantInfo>\n";
  894.         $message .= "\t\t<merchantID>{$this->AccountName}</merchantID>\n";
  895.         $message .= "\t\t<password>{$password}</password>\n";
  896.         $message .= "\t</MerchantInfo>\n";
  897.         $message .= "\t<RequestType>Periodic</RequestType>\n";
  898.         $message .= "\t<Periodic>\n";
  899.         $message .= "\t\t<PeriodicList count=\"1\">\n";
  900.         $message .= "\t\t\t<PeriodicItem ID=\"1\">\n";
  901.         $message .= "\t\t\t\t<actionType>trigger</actionType>\n";
  902.         $message .= "\t\t\t\t<clientID>{$this->OrderId}</clientID>\n"; // FIXME
  903.         $message .= "\t\t\t\t<amount>$cents</amount>\n";
  904.         $message .= "\t\t\t</PeriodicItem>\n";
  905.         $message .= "\t\t</PeriodicList>\n";
  906.         $message .= "\t</Periodic>\n";
  907.         $message .= "</SecurePayMessage>";
  908.         return $message;
  909.     }
  910.  
  911.     /**
  912.     * Creates the XML request for a SecurePay Echo
  913.     * This function reads $this->PreAuth to determine whether the transaction is a PreAuth rather than a standard payment. If FALSE (the default) a standard payment is produced
  914.     * @return string The XML string for a SecurePay Echo request
  915.     * @access private
  916.     */
  917.     function _ComposePayment() {
  918.         $this->LastMessageId = $this->_GetMessageId();
  919.         $cents = round($this->ChargeAmount * 100); // Convert to cents
  920.         $timestamp = date('YdmHis000+Z'); // See Appendix E of the SecureXML standard for more details on this date format
  921.         $message = "<?xml version=\"1.0\" encoding=\"UTF-8\"?" . ">\n";
  922.         $password = ($this->TestMode && $this->TestAccountPassword) ? $this->TestAccountPassword : $this->AccountPassword;
  923.  
  924.         if ($this->IsRepeat()) {
  925.             $message .= "<SecurePayMessage>\n";
  926.             $message .= "\t<MessageInfo>\n";
  927.             $message .= "\t\t<messageID>{$this->LastMessageId}</messageID>\n";
  928.             $message .= "\t\t<messageTimestamp>$timestamp</messageTimestamp>\n";
  929.             $message .= "\t\t<timeoutValue>60</timeoutValue>\n";
  930.             $message .= "\t\t<apiVersion>spxml-3.0</apiVersion>\n";
  931.             $message .= "\t</MessageInfo>\n";
  932.             $message .= "\t<MerchantInfo>\n";
  933.             $message .= "\t\t<merchantID>{$this->AccountName}</merchantID>\n";
  934.             $message .= "\t\t<password>{$password}</password>\n";
  935.             $message .= "\t</MerchantInfo>\n";
  936.             $message .= "\t<RequestType>Periodic</RequestType>\n";
  937.             $message .= "\t<Periodic>\n";
  938.             $message .= "\t\t<PeriodicList count=\"1\">\n";
  939.             $message .= "\t\t\t<PeriodicItem ID=\"1\">\n";
  940.             $message .= "\t\t\t\t<actionType>add</actionType>\n";
  941.             $message .= "\t\t\t\t<clientID>{$this->OrderId}</clientID>\n"; // FIXME
  942.             $message .= "\t\t\t\t<CreditCardInfo>\n";
  943.             $message .= "\t\t\t\t\t<cardNumber>{$this->Cc}</cardNumber>\n";
  944.             $message .= "\t\t\t\t\t<cardHolderName>{$this->cardHolderName}</cardHolderName>\n";
  945.             $message .= "\t\t\t\t\t<expiryDate>{$this->ExpiryDate}</expiryDate>\n";
  946.             echo 'CVV in compose: ' . $this->Cvv;
  947.             if ($this->Cvv) // Provided with CVV/CV2 number
  948.                 $message .= "\t\t\t\t\t<cvv>{$this->Cvv}</cvv>\n";
  949.             $message .= "\t\t\t\t</CreditCardInfo>\n";
  950.             $message .= "\t\t\t\t<amount>$cents</amount>\n";
  951.             $message .= "\t\t\t\t<currency>{$this->ChargeCurrency}</currency>\n";
  952.             if ($this->Repeat == SECUREPAY_REPEAT_DAILY) {
  953.                 $message .= "\t\t\t\t<periodicType>2</periodicType>\n";
  954.                 if ($this->RepeatInterval)
  955.                     $message .= "\t\t\t\t<paymentInterval>{$this->RepeatInterval}</paymentInterval>\n";
  956.             } else {
  957.                 $message .= "\t\t\t\t<periodicType>3</periodicType>\n";
  958.                 $message .= "\t\t\t\t<paymentInterval>{$this->Repeat}</paymentInterval>\n";
  959.             }
  960.             $message .= "\t\t\t\t<startDate>" . date('Ymd',($this->RepeatStart > 0) ? $this->RepeatStart : mktime()) . "</startDate>\n";
  961.             $message .= "\t\t\t\t<numberOfPayments>" . (($this->RepeatCount > 0) ? $this->RepeatCount : 999) . "</numberOfPayments>\n";
  962.             $message .= "\t\t\t</PeriodicItem>\n";
  963.             $message .= "\t\t</PeriodicList>\n";
  964.             $message .= "\t</Periodic>\n";
  965.             $message .= "</SecurePayMessage>";
  966.         } else { // Once-off payment
  967.             $message .= "<SecurePayMessage>\n";
  968.             $message .= "\t<MessageInfo>\n";
  969.             $message .= "\t\t<messageID>{$this->LastMessageId}</messageID>\n";
  970.             $message .= "\t\t<messageTimestamp>$timestamp</messageTimestamp>\n";
  971.             $message .= "\t\t<timeoutValue>60</timeoutValue>\n";
  972.             $message .= "\t\t<apiVersion>xml-4.2</apiVersion>\n";
  973.             $message .= "\t</MessageInfo>\n";
  974.             $message .= "\t<MerchantInfo>\n";
  975.             $message .= "\t\t<merchantID>{$this->AccountName}</merchantID>\n";
  976.             $message .= "\t\t<password>{$password}</password>\n";
  977.             $message .= "\t</MerchantInfo>\n";
  978.             $message .= "\t<RequestType>Payment</RequestType>\n";
  979.             $message .= "\t<Payment>\n";
  980.             $message .= "\t\t<TxnList count=\"1\">\n"; // In the current API this can only ever be 1
  981.             $message .= "\t\t\t<Txn ID=\"1\">\n"; // Likewise limited to 1
  982.             $message .= "\t\t\t\t<txnType>" . ($this->PreAuth ? ($this->PreAuthId ? '11' : '10') : '0') . "</txnType>\n"; // 0 = Standard payment, 10 = Pre-Auth, 11 - Charge Pre-Auth
  983.             $message .= "\t\t\t\t<txnSource>23</txnSource>\n"; // SecurePay API always demands the value 23
  984.             $message .= "\t\t\t\t<amount>$cents</amount>\n";
  985.             $message .= "\t\t\t\t<currency>{$this->ChargeCurrency}</currency>\n";
  986.             $message .= "\t\t\t\t<purchaseOrderNo>{$this->OrderId}</purchaseOrderNo>\n";
  987.             if ($this->PreAuthId) // Processing a standard payment and the previous transaction reserved a PreAuth code
  988.                 $message .= "\t\t\t\t<preauthID>{$this->PreAuthId}</preauthID>\n";
  989.             $message .= "\t\t\t\t<CreditCardInfo>\n";
  990.             if (!$this->PreAuthId) { // Completing a preauth - dont need to send CC details again
  991.                 $message .= "\t\t\t\t\t<cardNumber>{$this->Cc}</cardNumber>\n";
  992.                 $message .= "\t\t\t\t\t<cardHolderName>{$this->cardHolderName}</cardHolderName>\n";
  993.                 $message .= "\t\t\t\t\t<expiryDate>{$this->ExpiryDate}</expiryDate>\n";
  994.                 if ($this->Cvv) // Provided with CVV/CV2 number
  995.                     $message .= "\t\t\t\t\t<cvv>{$this->Cvv}</cvv>\n";
  996.             }
  997.             $message .= "\t\t\t\t</CreditCardInfo>\n";
  998.             $message .= "\t\t\t</Txn>\n";
  999.             $message .= "\t\t</TxnList>\n";
  1000.             $message .= "\t</Payment>\n";
  1001.             $message .= "</SecurePayMessage>";
  1002.         }
  1003.         return $message;
  1004.     }
  1005.  
  1006.     /**
  1007.     * Creates the XML request for a SecurePay Refund Echo
  1008.     * Similar to {@see _ComposePayment}, except it also requires a transaction ID
  1009.     * @return string The XML string for a SecurePay Echo request
  1010.     * @access private
  1011.     * @author Phil Hawthorne <me@philhawthorne.com>
  1012.     * @since  2014-02-13
  1013.     */
  1014.     function _ComposeRefund() {
  1015.         $this->LastMessageId = $this->_GetMessageId();
  1016.         $cents = round($this->ChargeAmount * 100); // Convert to cents
  1017.         $timestamp = date('YdmHis000+Z'); // See Appendix E of the SecureXML standard for more details on this date format
  1018.         $message = "<?xml version=\"1.0\" encoding=\"UTF-8\"?" . ">\n";
  1019.         $password = ($this->TestMode && $this->TestAccountPassword) ? $this->TestAccountPassword : $this->AccountPassword;
  1020.  
  1021.         $message .= "<SecurePayMessage>\n";
  1022.         $message .= "\t<MessageInfo>\n";
  1023.         $message .= "\t\t<messageID>{$this->LastMessageId}</messageID>\n";
  1024.         $message .= "\t\t<messageTimestamp>$timestamp</messageTimestamp>\n";
  1025.         $message .= "\t\t<timeoutValue>60</timeoutValue>\n";
  1026.         $message .= "\t\t<apiVersion>xml-4.2</apiVersion>\n";
  1027.         $message .= "\t</MessageInfo>\n";
  1028.         $message .= "\t<MerchantInfo>\n";
  1029.         $message .= "\t\t<merchantID>{$this->AccountName}</merchantID>\n";
  1030.         $message .= "\t\t<password>{$password}</password>\n";
  1031.         $message .= "\t</MerchantInfo>\n";
  1032.         $message .= "\t<RequestType>Payment</RequestType>\n";
  1033.         $message .= "\t<Payment>\n";
  1034.         $message .= "\t\t<TxnList count=\"1\">\n"; // In the current API this can only ever be 1
  1035.         $message .= "\t\t\t<Txn ID=\"1\">\n"; // Likewise limited to 1
  1036.         $message .= "\t\t\t\t<txnType>4</txnType>\n"; // 0 = Standard payment, 10 = Pre-Auth, 11 - Charge Pre-Auth
  1037.         $message .= "\t\t\t\t<txnSource>23</txnSource>\n"; // SecurePay API always demands the value 23
  1038.         $message .= "\t\t\t\t<amount>$cents</amount>\n";
  1039.         $message .= "\t\t\t\t<currency>{$this->ChargeCurrency}</currency>\n";
  1040.         $message .= "\t\t\t\t<purchaseOrderNo>{$this->OrderId}</purchaseOrderNo>\n";
  1041.         $message .= "\t\t\t\t<txnID>{$this->TransactionId}</txnID>\n";
  1042.         if ($this->PreAuthId) // Processing a standard payment and the previous transaction reserved a PreAuth code
  1043.             $message .= "\t\t\t\t<preauthID>{$this->PreAuthId}</preauthID>\n";
  1044.  
  1045.         $message .= "\t\t\t</Txn>\n";
  1046.         $message .= "\t\t</TxnList>\n";
  1047.         $message .= "\t</Payment>\n";
  1048.         $message .= "</SecurePayMessage>";
  1049.  
  1050.         return $message;
  1051.     }
  1052.  
  1053.     /**
  1054.     * Makes a POST request to the web interface using CURL
  1055.     * This function uses the main objects Cookie Jar
  1056.     * @access private
  1057.     * @param string $url The URL that should be retrieved
  1058.     * @param string $post Optional POST string that should be retrieved
  1059.     */
  1060.     function _WebRetrieve($url, $post = null) {
  1061.         $curl = curl_init();
  1062.         curl_setopt($curl, CURLOPT_URL, $url);
  1063.         curl_setopt($curl, CURLOPT_AUTOREFERER, 'https://login.securepay.com.au');
  1064.         curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 6.0)');
  1065.         curl_setopt($curl, CURLOPT_FOLLOWLOCATION, TRUE); // Follow redirects
  1066.         curl_setopt($curl, CURLOPT_AUTOREFERER, TRUE); // Auto carry referer urls
  1067.         curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE); // Return the HTTP response from the curl_exec function
  1068.         curl_setopt($curl, CURLOPT_COOKIEFILE, $this->WebCookieJar);
  1069.         curl_setopt($curl, CURLOPT_COOKIEJAR, $this->WebCookieJar);
  1070.         if ($post) {
  1071.             curl_setopt($curl, CURLOPT_POST, 1);
  1072.             curl_setopt($curl, CURLOPT_POSTFIELDS, $post);
  1073.         }
  1074.         $response = curl_exec($curl); // Sign-in
  1075.         curl_close($curl);
  1076.         return $response;
  1077.     }
  1078.  
  1079.     // End of Private functions }}}
  1080. }
  1081. ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement