Dynamic PayPal button generation - isn't it very insecure?
You should use the PayPal Button API such as below:
$sendPayData = array(
"METHOD" => "BMCreateButton",
"VERSION" => "65.2",
"USER" => "username",
"PWD" => "password",
"SIGNATURE" => "abcdefg",
"BUTTONCODE" => "ENCRYPTED",
"BUTTONTYPE" => "BUYNOW",
"BUTTONSUBTYPE" => "SERVICES",
"BUTTONCOUNTRY" => "GB",
"BUTTONIMAGE" => "reg",
"BUYNOWTEXT" => "BUYNOW",
"L_BUTTONVAR1" => "item_number=$invoiceNumber",
"L_BUTTONVAR2" => "item_name=$invoiceType",
"L_BUTTONVAR3" => "amount=$invoiceTotal",
"L_BUTTONVAR4" => "currency_code=GBP",
"L_BUTTONVAR5" => "no_shipping=1",
"L_BUTTONVAR6" => "no_note=1",
"L_BUTTONVAR7" => "notify_url=http://www.abc.co.uk/paypal/ipn.php",
"L_BUTTONVAR8" => "cancel_return=http://www.abc.co.uk/paypal/thanks",
"L_BUTTONVAR9" => "return=http://www.abc.co.uk/paypal/return.php"
);
You can then send that with cURL to their API
$curl = curl_init();
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_URL, 'https://api-3t.paypal.com/nvp?'.http_build_query($sendPayData));
$nvpPayReturn = curl_exec($curl);
curl_close($curl);
To then generate a encrypted HTML button that cannot be edited
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----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-----END PKCS7-----
">
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_paynow_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online.">
<img alt="Sample Image" border="0" src="https://www.paypal.com/en_GB/i/scr/pixel.gif" width="1" height="1">
These links should help you with the button options:
https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_nvp_BMCreateButton
https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_ButtonMgrAPIIntro
Dynamic Paypal button encryption
maybe you could try putting those variables in a temporary table with a unique id. then use that id for the buttons. querying the variables from the table whenever the customer clicks the paypal buttons. I just hope i understood your statement right xD
Dynamically generating PayPal buttons
Doing it that way isn't very secure because people can still view source and see the end-result on your page. Then they could take that, make changes to it, load it in their own browser and pay you for an item at a much lower price.
You can utilize IPN to help flag orders that don't look accurate by cross-references your pricing, but this can be a hassle.
You could use the Button Manager API to generate your buttons as hosted buttons on PayPal. This way people can't see the details in the source code and wouldn't be able to make changes.
Alternatively, you could use the Express Checkout API which is what I prefer and recommend if you know how to work with web service API's.
Dynamically generating PayPal buttons
Doing it that way isn't very secure because people can still view source and see the end-result on your page. Then they could take that, make changes to it, load it in their own browser and pay you for an item at a much lower price.
You can utilize IPN to help flag orders that don't look accurate by cross-references your pricing, but this can be a hassle.
You could use the Button Manager API to generate your buttons as hosted buttons on PayPal. This way people can't see the details in the source code and wouldn't be able to make changes.
Alternatively, you could use the Express Checkout API which is what I prefer and recommend if you know how to work with web service API's.
Setting dynamic amounts securely with Paypal payments with a redirection and not button?
Ok, I finally found out that not only does the response from the BMUpdateButton API return the HTML
to create a form, it also returns other data as well within the returned array.
Once you make the request it will return an array with three keys as per the BMUpdateButton Response section on the API page linked above.
These are:
WEBSITECODE
HTML code for web pages
- EMAILLINK
This is what I was looking for; a plain link you can redirect users to
- HOSTEDBUTTONID
The id of the button.
Be advised when altering the contents of a hosted button you need to pass all the details of the button to it as when you created it; so as an example, if you leave out passing it an item name the item name will be blank and Paypal will allow the user to set it.
Also, an important note is that when you update the button details, it isn't just updated for that users session, it updates it within your paypal account - so the new name/price etc will affect all users that attempt to use it.
If you still would like to update the details of the button you can do that with the below:
I personally started with this class:
<?php
class Paypal
{
/**
* Last error message(s)
* @var array
*/
protected $_errors = array();
/**
* API Credentials
* Use the correct credentials for the environment in use (Live / Sandbox)
* @var array
*/
protected $_credentials = array(
'USER' => 'seller_1297608781_biz_api1.lionite.com',
'PWD' => '1297608792',
'SIGNATURE' => 'A3g66.FS3NAf4mkHn3BDQdpo6JD.ACcPc4wMrInvUEqO3Uapovity47p',
);
/**
* API endpoint
* Live - https://api-3t.paypal.com/nvp
* Sandbox - https://api-3t.sandbox.paypal.com/nvp
* @var string
*/
protected $_endPoint = 'https://api-3t.sandbox.paypal.com/nvp';
/**
* API Version
* @var string
*/
protected $_version = '74.0';
/**
* Make API request
*
* @param string $method string API method to request
* @param array $params Additional request parameters
* @return array / boolean Response array / boolean false on failure
*/
public function request($method, $params = array())
{
$this->_errors = array();
if (empty($method)) { //Check if API method is not empty
$this->_errors = array('API method is missing');
return false;
}
//Our request parameters
$requestParams = array(
'METHOD' => $method,
'VERSION' => $this->_version
) + $this->_credentials;
//Building our NVP string
$request = http_build_query($requestParams + $params);
//cURL settings
$curlOptions = array(
CURLOPT_URL => $this->_endPoint,
CURLOPT_VERBOSE => 1,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_CAINFO => dirname(__FILE__) . '/cacert.pem', //CA cert file
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => $request
);
$ch = curl_init();
curl_setopt_array($ch, $curlOptions);
//Sending our request - $response will hold the API response
$response = curl_exec($ch);
//Checking for cURL errors
if (curl_errno($ch)) {
$this->_errors = curl_error($ch);
curl_close($ch);
return false;
//Handle errors
} else {
curl_close($ch);
$responseArray = array();
parse_str($response, $responseArray); // Break the NVP string to an array
return $responseArray;
}
}
}
?>
Credit: https://www.smashingmagazine.com/2011/09/getting-started-with-the-paypal-api/
Then I did the below:
include(dirname(__FILE__) . '/includes/paypal.class.php');
$paypal = new Paypal();
// Set our method
$method = 'BMUpdateButton';
// Set our params
$params = array(
'HOSTEDBUTTONID' => 'your_button_id',
'BUTTONTYPE' => 'BUYNOW',
'BUTTONSUBTYPE' => 'SERVICES',
'L_BUTTONVAR0' => 'item_name=Your Description',
'L_BUTTONVAR1' => 'amount=999.00',
'L_BUTTONVAR2' => 'currency_code=AUD',
'L_BUTTONVAR3' => 'cancel_return=http://www.example.com/cancel.html',
'L_BUTTONVAR4' => 'return=http://www.example.com/success.html'
);
// Make request to change button details
$result = $paypal->request($method, $params);
Note that while Paypal say that BUTTONSUBTYPE
is optional, you will likely get an error if you don't include it.
Paypal dynamic button and Linking with IPN
I'm just going to answer my OWN question. The solution is to just compare the "item_name" and "amount" variables and make sure they are exactly the same if say I generated using a database. And if someone tampers it and pays me $1.00 instead of $100.00 then thats a free donation and bad luck for them :P
What I will be doing is this:
- Create a database to store item name, amount, currency etc.
- On the shopping page I will dynamically generate it using the item_name and amount
- Set up my paypal to send transactions made to the IPN listener that I will make
- Using the database to compare the item_name and amount, it will validate whether it is a valid form submission or not.
Simple! I like it! WOO!
Related Topics
What Is Null Coalescing Assignment = Operator in PHP 7.4
Round to Max Thousand, Hundred etc in PHP
Calendar Using JavaScript/ PHP/ MySQL
What Does the B in Front of String Literals Do
Return Multiple Response Data in One Response
Is PHP's 'Include' a Function or a Statement
Dynamically Changing Image Colours
How to Install Pdo_Sqlsrv on My Windows 2008 Server 2008 R2
Change Date Format (In Db or Output) to Dd/Mm/Yyyy - PHP MySQL
How to Access a PHP Object Attribute Having a Dollar Sign
Generating Random Numbers from Skewed Normal Distribution
Protection Against Xss Exploits
(Mysql, PHP) How to Get Auto_Increment Field Value Before Inserting Data
Using PHP as a Template Engine
Using Sprockets as a Standalone Service for a PHP Application
How to Display an Blob Image Stored in MySQL Database
PHP to Clean-Up Pasted Microsoft Input
Bad Request. Connecting to Sites via Curl on Host and System