This requires a new checkout.result.php (just about rewritten) in .../administrator/components/com_virtuemart/html
<?php
if( !defined( '_VALID_MOS' ) && !defined( '_JEXEC' ) ) die( 'Direct Access to '.basename(__FILE__).' is not allowed.' );
/**
* PayPal IPN Result Checker
*
* @version $Id: checkout.result.php 1394 2008-05-04 19:05:15Z soeren_nb $
* @package VirtueMart
* @subpackage html
* @copyright Copyright (C) 2004-2007 soeren - All rights reserved.
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL, see LICENSE.php
* VirtueMart is free software. This version may have been modified pursuant
* to the GNU General Public License, and as distributed it includes or
* is derivative of works licensed under the GNU General Public License or
* other free or open source software licenses.
* See /administrator/components/com_virtuemart/COPYRIGHT.php for copyright notices and details.
*
* http://virtuemart.net
*/
mm_showMyFileName( __FILE__ );
global $db, $vmLogger, $VM_LANG;
function preg ($m) {
return '/{'.$m.'}/ix';
}
$valid=true;
if( !isset( $_REQUEST["order_id"] ) || empty( $_REQUEST["order_id"] )) {
echo $VM_LANG->_('VM_CHECKOUT_ORDERIDNOTSET');
$valid=false;
} else
{
// order_id is set - this is a paypal transaction...
// validate the order_id...
include( CLASSPATH. "payment/ps_paypal.cfg.php" );
$values=array();
$values['order_id']= intval( vmGet( $_REQUEST, "order_id" ));
$values['user_id']=$auth["user_id"];
$sql =<<<HEREDOC
SELECT order_status,order_total,order_currency
FROM #__{vm}_orders
WHERE #__{vm}_orders.user_id={user_id}
AND #__{vm}_orders.order_id={order_id}
HEREDOC;
$sql=preg_replace(array_map("preg",array_keys($values)),array_map("mysql_escape_string",$values),$sql);
$db->query($sql);
if ($db->next_record()){
$values['order_status'] = $db->f("order_status");
if($values['order_status'] == PAYPAL_VERIFIED_STATUS || $values['order_status'] == PAYPAL_PENDING_STATUS) {
printf(' <img src="%simages/button_ok.png" align="middle" alt="%s" border="0" />',
VM_THEMEURL,$VM_LANG->_('VM_CHECKOUT_SUCCESS'));
printf(' <h2>%s</h2>',$VM_LANG->_('PHPSHOP_PAYPAL_THANKYOU'));
// echo('<pre> $_GET <br/>');
// print_r($_GET);
// echo("</pre>");
// check we've got PDT switched on...
if( !isset( $_GET['tx'] ) || empty( $_GET['tx'] )) {
//PDT is not switched on...
//Are we expecting it to be on?
if(PAYPAL_PDT_AUTH!=""){$vmLogger->err("Paypal Data Transfer unavailable.",false);$valid=false;}
} else
{
// PDT is switched on...
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-synch';
$tx_token = vmGet($_GET,'tx');
$req .= "&tx=$tx_token&at=".PAYPAL_PDT_AUTH;
// post back to PayPal system to validate
$header .= "POST /cgi-bin/webscr HTTP/1.0\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
$fp = fsockopen (PAYPAL_URL, 80, $errno, $errstr, 30);
// If possible, securely post back to paypal using HTTPS
// Your PHP server will need to be SSL enabled
// $fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);
if (!$fp) {
$vmLogger->err("Paypal Data Transfer Http error.",false);
$valid=false;
// HTTP ERROR
} else {
fputs ($fp, $header . $req);
// read the body data
$res = '';
$headerdone = false;
while (!feof($fp)) {
$line = fgets ($fp, 1024);
if (strcmp($line, "\r\n") == 0) {
// read the header
$headerdone = true;
}
else if ($headerdone)
{
// header has been read. now read the contents
$res .= $line;
}
}
// parse the data
$lines = explode("\n", $res);
$keyarray = array();
if (strcmp ($lines[0], "SUCCESS") == 0) {
for ($i=1; $i<count($lines);$i++){
list($key,$val) = explode("=", $lines[$i]);
$keyarray[urldecode($key)] = urldecode($val);
}
// echo('<pre> $keyarray <br/>');
// print_r($keyarray);
// echo("</pre>");
$fraud_state=false;
if (PAYPAL_EMAIL!=$keyarray['receiver_email']){$fraud_state=true;$vmLogger->err("Fraud? receiver_email corrupt : ".$values['txn_id']);}
if ($db->f("order_total")!=$keyarray['mc_gross']){$fraud_state=true;$vmLogger->err("Fraud? payment_amount corrupt : ".$values['txn_id']." ".$db->f("order_total")." != ".$keyarray['mc_gross']);}
if ($db->f("order_currency")!=$keyarray['mc_currency']){$fraud_state=true;$vmLogger->err("Fraud? payment_currency corrupt : ".$values['txn_id']." ".$db->f("order_currency")." != ".$keyarray['mc_currency']);}
//bung this lot into the database....
##
## Table structure for table `#__{vm}_paypal`
##
$db->query( "CREATE TABLE IF NOT EXISTS `#__{vm}_paypal` (
type char(3) NOT NULL,
txn_id char(20) NOT NULL,
txn_type char(39),
created_date timestamp,
payment_date timestamp,
user_id int(11),
order_id int(11),
order_status char(1),
payment_status char(50),
mc_gross decimal(10,2),
mc_fee decimal(10,2),
mc_currency char(3),
tax decimal(10,2),
shipping decimal(10,2),
handling_amount decimal(10,2),
payment_type char(30),
payer_email char(127),
protection_eligibility char(20),
payer_status char(20),
first_name char(64),
last_name char(64),
address_name char(128),
address_status char(10),
address_street char(200),
address_city char(40),
address_state char(40),
address_zip char(20),
address_country char(64),
address_country_code char(2),
payer_business_name char(127),
pending_reason char(64),
transaction_subject char(64),
item_name char(64),
item_number char(64),
quantity int(11),
residence_country char(64),
business char(64),
receiver_email char(127),
receiver_id char(64),
payer_id char(64),
invoice char(64),
charset char(64),
custom char(64),
payment_gross int(11),
payment_fee int(11),
PRIMARY KEY (`txn_id`,created_date),
KEY `idx_paypal_txn_id` (`txn_id`),
KEY `idx_paypal_order_id` (`order_id`)
) TYPE=MyISAM COMMENT='Paypal transactions are stored here'; ");
$sql_insert=<<<HEREDOC
INSERT INTO `#__{vm}_paypal`
(`type`,
`txn_id`,
`txn_type`,
`created_date`,
`payment_date`,
`user_id`,
`order_id`,
`order_status`,
`payment_status`,
`mc_gross`,
`mc_fee`,
`mc_currency`,
`tax`,
`shipping`,
`handling_amount`,
`payment_type`,
`payer_email`,
`protection_eligibility`,
`payer_status`,
`first_name`,
`last_name`,
`address_name`,
`address_status`,
`address_street`,
`address_city`,
`address_state`,
`address_zip`,
`address_country`,
`address_country_code`,
`payer_business_name`,
`pending_reason`,
`transaction_subject`,
`item_name`,
`item_number`,
`quantity`,
`residence_country`,
`business`,
`receiver_email`,
`receiver_id`,
`payer_id`,
`invoice`,
`charset`,
`custom`,
`payment_gross`,
`payment_fee`)
VALUES
(
"{type}",
"{txn_id}",
"{txn_type}",
current_timestamp,
"{payment_date}",
"{user_id}",
"{order_id}",
"{order_status}",
"{payment_status}",
"{mc_gross}",
"{mc_fee}",
"{mc_currency}",
"{tax}",
"{shipping}",
"{handling_amount}",
"{payment_type}",
"{payer_email}",
"{protection_eligibility}",
"{payer_status}",
"{first_name}",
"{last_name}",
"{address_name}",
"{address_status}",
"{address_street}",
"{address_city}",
"{address_state}",
"{address_zip}",
"{address_country}",
"{address_country_code}",
"{payer_business_name}",
"{pending_reason}",
"{transaction_subject}",
"{item_name}",
"{item_number}",
"{quantity}",
"{residence_country}",
"{business}",
"{receiver_email}",
"{receiver_id}",
"{payer_id}",
"{invoice}",
"{charset}",
"{custom}",
"{payment_gross}",
"{payment_fee}"
);
HEREDOC;
$sql_check=<<<HEREDOC
SELECT count(*) as check_count from #__{vm}_paypal
WHERE type="PDT" AND txn_id ="{txn_id}";
HEREDOC;
$values=array_merge($values,$keyarray);
$values['payment_date']=strtotime($values['payment_date']);
$values['type']="PDT";
$sql=preg_replace(array_map("preg",array_keys($values)),array_map("mysql_escape_string",$values),$sql_insert);
$db->query($sql);
$sql=preg_replace(array_map("preg",array_keys($values)),array_map("mysql_escape_string",$values),$sql_check);
$db->query($sql);
$db->next_record();
if(intval($db->f("check_count"))<>1){
$fraud_state=true;
$vmLogger->err("Fraud? Same txn_id as a previous PDT transaction : ".$values['txn_id']);
}
if ($keyarray['payment_status']=="Completed"||$keyarray['payment_status']=="Pending"){
// Pending could be an echeck or any delayed transaction -- but this is our one chance to report it to google...
if ($fraud_state){
$valid=false;
}else{
// there is no need to update the order_status here as the IPN notify script will do that asynchronously and more reliably...
require_once( CLASSPATH. "ps_google.php" );
ps_google::process_conversion( $values['order_id'] );
}
}else{
$valid=false;
}
}
else if (strcmp ($lines[0], "FAIL") == 0) {
// log for manual investigation
$vmLogger->err("PDT FAIL ".join("\r\n",$lines),false);
$valid=false;
}else {
$vmLogger->err("PDT unrecognised return ".join("\r\n",$lines),false);
$valid=false;
}
}
}
fclose ($fp);
} else {
$vmLogger->err("Paypal PDT not checked as Order Status corrupt? :".$db->f("order_status"),false);
$valid=false;
printf(' <img src="%simages/button_cancel.png" align="middle" alt="%s" border="0" />',
VM_THEMEURL,$VM_LANG->_('VM_CHECKOUT_FAILURE'));
printf(' <h2>%s</h2>',$VM_LANG->_('PHPSHOP_PAYPAL_ERROR'));
}
printf('<br /><p><a href="index.php?option=com_virtuemart&page=account.order_details&order_id=%s">%s</a></p>',
$values['order_id'], $VM_LANG->_('PHPSHOP_ORDER_LINK'));
} else {
$vmLogger->err("Order not found :". $values['order_id']. " for user ".$values["user_id"] . " ",false);
echo $VM_LANG->_('VM_CHECKOUT_ORDERNOTFOUND') . '!';
$valid=false;
}
If($valid){
$firstname = $keyarray['first_name'];
$lastname = $keyarray['last_name'];
$itemname = $keyarray['item_name'];
$amount = $keyarray['mc_gross'];
echo ("<h3>Thank you for your purchase!</h3>\n");
echo ("<b>Payment Details</b><br>\n");
echo ("<ul><li>Name: $firstname $lastname</li>\n");
echo ("<li>Item: $itemname</li>\n");
echo ("<li>Amount: $amount</li></ul>\n");
echo ("");
echo "Your transaction has been completed, and a receipt for your purchase has been emailed to you.<br>";
}
echo "You may log into your account at <a href='https://www.paypal.com'>www.paypal.com</a> to view details of this transaction.<br>";
}
?>
which uses a new ps_google.php and ps_google.cfg.php and some new values in ps_paypal.cfg.php
new values in ps_paypal.cfg.php in .../administrator/components/com_virtuemart/classes/payment
define ('PAYPAL_URL', 'www.paypal.com'); // just to make it easier switching in and out of the sandbox...
// this token is available from Profile - Website Payment Preferences
define ('PAYPAL_PDT_AUTH',"5KK_UpU_qwertyuiopgfghjkfghjkjke_etc");
ps_google.cfg.php in .../administrator/components/com_virtuemart/classes
<?php
if( !defined( '_VALID_MOS' ) && !defined( '_JEXEC' ) ) die( 'Direct Access to '.basename(__FILE__).' is not allowed.' );
define ('GOOGLE_ID', 'UA-123456-1');
?>
ps_google.php in .../administrator/components/com_virtuemart/classes
<?php
if( !defined( '_VALID_MOS' ) && !defined( '_JEXEC' ) ) die( 'Direct Access to '.basename(__FILE__).' is not allowed.' );
/**
* Post conversion to google using ga.js
*
* @version $Id: ps_google.php 1394 2008-05-04 19:05:15Z soeren_nb $
* @package VirtueMart
* @subpackage html
* @copyright Copyright (C) 2004-2007 soeren - All rights reserved.
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL, see LICENSE.php
* VirtueMart is free software. This version may have been modified pursuant
* to the GNU General Public License, and as distributed it includes or
* is derivative of works licensed under the GNU General Public License or
* other free or open source software licenses.
* See /administrator/components/com_virtuemart/COPYRIGHT.php for copyright notices and details.
*
* http://virtuemart.net
*/
class ps_google {
function preg ($m) {return '/{'.$m.'}/ix';}
function process_conversion($order_id) {
global $VM_LANG, $vmLogger;
/* init the database */
$google_db =& new ps_DB;
include(CLASSPATH."ps_google.cfg.php");
$valid = true;
$google_order=<<<HEREDOC
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol ) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
try{
var pageTracker = _gat._getTracker("{GOOGLE_ID}");
pageTracker._addTrans(
"{order_id}", // order ID - required
"{vendor_name}", // affiliation or store name
"{order_total}", // total - required
"{order_tax}", // tax
"{order_shipping}", // shipping
"{city}", // city
"{state}", // state or province
"{country}" // country
);
{google_lines}
pageTracker._trackTrans(); //submits transaction to the Analytics servers
} catch(err) {}
</script>
HEREDOC;
$google_lines=array();
// add item might be called for every item in the shopping cart
// where your ecommerce engine loops through each item in the cart and
// prints out _addItem for each
$google_line=<<<HEREDOC
pageTracker._addItem(
"{order_id}", // order ID - necessary to associate item with transaction
"{order_item_sku}", // SKU/code - required
"{order_item_name}", // product name
"{product_attribute}", // category or variation
"{product_item_price}", // unit price - required
"{product_quantity}" // quantity - required
);
HEREDOC;
$sql_order =<<<HEREDOC
SELECT o.order_total,
o.order_tax,
o.order_shipping,
u.city,
u.state,
u.country,
(select vendor_name from #__{vm}_vendor v where v.vendor_id=o.vendor_id LIMIT 1) as vendor_name
FROM #__{vm}_orders o
LEFT OUTER JOIN #__{vm}_order_user_info u
ON o.order_id=u.order_id
WHERE o.order_id="{order_id}";
HEREDOC;
$sql_lines =<<<HEREDOC
SELECT
`#__{vm}_order_item`.`order_item_sku`,
`#__{vm}_order_item`.`order_item_name`,
`#__{vm}_order_item`.`product_quantity`,
`#__{vm}_order_item`.`product_item_price`,
`#__{vm}_order_item`.`product_attribute`
FROM `#__{vm}_order_item`
WHERE `#__{vm}_order_item`.`order_id` ="{order_id}"
ORDER BY `#__{vm}_order_item`.`order_item_id`;
HEREDOC;
$values=array();
$values['GOOGLE_ID']=GOOGLE_ID;
$values['order_id']=$order_id;
$config=$values;
$sql=preg_replace(array_map(array("ps_google","preg"),array_keys($values)),array_map("mysql_escape_string",$values),$sql_order);
$google_db->query($sql);
if (!$google_db->next_record()) {
$vmLogger->err( "ORDER NOT FOUND :".$order_id );
$valid=false;
}else{
$values=array_merge($values,(array) $google_db->getCurrentRow());
$google_order=preg_replace(array_map(array("ps_google","preg"),array_keys($values)),$values,$google_order);
$sql=preg_replace(array_map(array("ps_google","preg"),array_keys($values)),array_map("mysql_escape_string",$values),$sql_lines);
$google_db->query($sql);
while ($google_db->next_record()){
$values=array_merge($config,(array) $google_db->getCurrentRow());
$google_lines[]=preg_replace(array_map(array("ps_google","preg"),array_keys($values)),array_map("mysql_escape_string",$values),$google_line);
}
$values=$config;
$values['google_lines']=join("\r\n",$google_lines);
$google_order=preg_replace(array_map(array("ps_google","preg"),array_keys($values)),$values,$google_order);
echo $google_order;
}
return $valid;
}
}