Gurus,
I didn't expect to have this much trouble with Cybercash, but I am. After 2 weeks of kicking US Internet to set up our cybercash/PHP/MySQL server, they finally got it running - on an NT box (Ouch).
I have read the PDFs at Cybercash, and Nathan's script, but I just can't seem to get it to go. I have RTFM'd as much as I could before posting, but I have a deadline and this is going to kill it.
When I test the code below, I get the following error:
"Fatal error: Call to a member function on a non-object in E:\tvseminar\test.php on line 17"
I tried declaring $test as global, but this didn't help. Reading up on functions didn't yield the answer either.
There are two scripts as follows:
test.php - A copy of the sample code.
class.cyberclass.php - Nathan's class.
After looking through class.cyberclass.php, it seems straightforward. It urlencodes, then encrypts and dumps it to a CGI at Cybercash. I just don't have the experience with arrays and member functions to find the answer easily.
Any help can save the day for me. Thanks in advance.
-Tom
Here is my code:
test.php
echo("Processing Transaction....<BR>");
include("class.cyberclass.php");
$test = new cyberclass("c:\mck-3.3.1-NT\tvpathcom-13\conf\merchant_conf"); // This is the location according to US Internet.
$response = $test->SendCC2_1Server('mauthonly',
array('Order-ID' => '11223344',
'Amount' => 'usd 11.50',
'Card-Number' => '4111111111111111',
'Card-Address' => '1600 Pennsylvania Avenue',
'Card-City' => 'Washington',
'Card-State' => 'DC',
'Card-Zip' => '20500',
'Card-Country' => 'USA',
'Card-Exp' => '12/05',
'Card-Name' => 'George W. Bush'
));
while(list($key, $val) = each($response)){
echo "$key = $val<br>\n";
}
class.cyberclass.php
/*
CyberClass - PHP CyberCash Interface (C) Nathan Cassano
Author: Nathan Cassano <nathan@cjhunter.com>
Version: 0.6
Description: CyberClass is an interface to the CyberCash Cash Register
Service for online financial transactions (such as credit card processing).
This is an adaptation to the origional CyberLib. The CyberClass API is a
duplicatation of the original CyberCash API. Please check out my article at
http://www.phpbuilder.com/columns/nathan20001225.php3
Requirements: A CyberCash Merchant Account, PHP with compiled with cybercash support (ie ./configure --with-cybercash=/mck)
Example:
$test = new cyberclass("c:\mck-3.3.1-NT\tvpathcom-13\conf\merchant_conf");
$response = $test->SendCC2_1Server('mauthonly',
array('Order-ID' => '11223344',
'Amount' => 'usd 11.50',
'Card-Number' => '4111111111111111',
'Card-Address' => '1600 Pennsylvania Avenue',
'Card-City' => 'Washington',
'Card-State' => 'DC',
'Card-Zip' => '20500',
'Card-Country' => 'USA',
'Card-Exp' => '12/05',
'Card-Name' => 'George W. Bush'
));
while(list($key, $val) = each($response)){
echo "$key = $val<br>\n";
}
*/
class cyberclass
{
/ Merchant Configuration array /
var $config;
/* Merchant identification */
var $merchant_id;
/* Private Encryption key */
var $merchant_key;
/* CyberCash Payment Service (CCPS) Host Address */
var $ccps_host;
var $host;
var $base_path;
var $port = 80;
/*
* Class Constructor
*/
function cyberclass($merchant_conf)
{
/* Read merchant_conf into array */
$fp = @fopen($merchant_conf, 'r');
if($fp == false){
/* Unable to open merchant configuration */
$this = -1;
return;
}
while(!feof($fp)){
$line = fgets($fp, 80);
if(!ereg("^#", $line)){
if(ereg('=', $line)){
list($key, $value) = split("=", $line, 2);
$key = trim($key);
$value = trim($value);
$this->config[$key] = $value;
}
}
}
/* Set class members or die*/
if(!$this->ccps_host = $this->config['CCPS_HOST']){
/* Unable to initialize 'CCPS_HOST' from configuration */
$this = -2;
return;
}
if(!$this->merchant_id = $this->config['CYBERCASH_ID']){
/* Unable to initialize 'CYBERCASH_ID' from configuration */
$this = -2;
return;
}
if(!$this->merchant_key = $this->config['MERCHANT_KEY']){
/ Unable to initialize 'MERCHANT_KEY' from configuration /
$this = -2;
return;
}
$parsed_url = parse_url($this->ccps_host);
$this->host = $parsed_url['host'];
$this->base_path = $parsed_url['path'];
}
/*function SendCC2_1Server($operation, $args)
* Desc: Wrapper Interface to the Direct Cash Register 2.1 API
* Input:
* $operation - the 2.1 Cash Register operation
* $args - attribute/value pairs that make up the argument list for that operation.
* Returns:
* ['MStatus'] - the outcome of the tranaction
* ['*'] - and many other variable pairs
*/
function SendCC2_1Server($operation, $args)
{
/* Make the url. */
// $cgi = 'cr21api.cgi/' . $operation;
//I changed the value below to the full path of the cgi at cybercash. The above was what came with the script.
$cgi = 'http://cr.cybercash.com/cgi-bin/cr21api.cgi/' . $operation;
return $this->SendCCServer($cgi, $args);
}
/*function SendCCServer($cgi, $args)
* Desc: Common Direct Interface to Cyber Cash Server
* Input:
* $cgi - the cgi filename to which to request is being sent
* $args - the attribute/value pairs that make up the argument list for that operation.
* Returns:
* ['MStatus'] - the outcome of the tranaction
* ['*'] - and many other variable pairs
*/
function SendCCServer($cgi, $args)
{
/* Make url encoded cgi arguments from $args */
$message = $this->urls_encode($args);
/* Encrypt the message */
$encrypted_message = $this->CCEncrypt($message);
return $this->CCSocketSend($cgi, $encrypted_message);
}
/*function CCEncrypt($message)
* Desc: Encrypts a HTTP url-encoded message
*/
function CCEncrypt($message)
{
$session_key = sprintf("%s #%ld", date("D M j H:i:s Y"), getmypid());
$enc_msg = cybercash_encr($this->merchant_key, $session_key, $message);
$message = cybercash_base64_encode($enc_msg['outbuff']);
$mac = cybercash_base64_encode($enc_msg['macbuff']);
/* This adds the information needed to decrypt. */
$encrypted_message = 'message=' . urlencode($message) . '&';
$encrypted_message .= 'session-key=' . urlencode($session_key) . '&';
$encrypted_message .= 'mac=' . urlencode($mac);
return $encrypted_message;
}
/*function CCSocketSend($cgi, $message)
* Desc: Sends a raw HTTP request and returns the decoded message as an array
*/
function CCSocketSend($cgi, $message)
{
/* Send message */
$fp = @fopen("http://$this->host:$this->port$this->base_path$cgi/$this->merchant_id?$message", 'r');
if($fp == false){
$response_vars['MStatus'] = 'failure-hard';
$response_vars['MErrMsg'] = 'HTTP request failed';
return $response_vars;
}
/* and get the response */
while(!feof($fp)){
$response .= fgets($fp, 256);
}
fclose($fp);
/* Decode response */
$response_vars = $this->urls_decode($response);
$response_vars['message'] = cybercash_base64_decode($response_vars['message']);
$response_vars['mac'] = cybercash_base64_decode($response_vars['mac']);
/* Decrypt response */
$deccrypted_response_vars = cybercash_decr($this->merchant_key, $response_vars['session-key'], $response_vars['message']);
/* Catch decryption errors */
if($deccrypted_response_vars['errcode']){
$response_vars['MStatus'] = 'failure-hard';
$response_vars['MErrMsg'] = 'Response non-decodable.';
$response_vars['MErrCode'] = $deccrypted_response_vars['errcode'];
return $response_vars;
}
/* Verify signitures match */
if($deccrypted_response_vars['macbuff'] != $response_vars['mac']){
$response_vars['MStatus'] = 'failure-hard';
$response_vars['MErrMsg'] = 'Signitures do not match.';
return $response_vars;
}
/* Parse again to get message */
return $this->urls_decode($deccrypted_response_vars['outbuff']);
}
/*function urls_encode($args)
* Desc: Creates url-encoded message from array of attribute/value pairs
*/
function urls_encode($args)
{
/* Make sure we're dealing with an array here */
if(is_array($args)){
/* Turn the name and value pairs form $args into a url-encoded message. */
list($key, $val) = each($args);
do{
if($more){
$message .= '&'; }
$message .= chop($key) . '=' . urlencode(chop($val));
list($key, $val) = $more = each($args);
}while($more);
}
return $message;
}
/*function urls_decode($message)
* Desc: Separates url-encoded message into array of attribute/value pairs
*/
function urls_decode($message)
{
$pairs = explode("&", $message);
while($pair = current($pairs)){
list($var, $val) = explode("=", $pair);
$args[$var] = urldecode(chop($val));
next($pairs);
}
return $args;
}
}