为你的网站使用paypal

news/2024/5/20 23:22:33/文章来源:https://blog.csdn.net/weixin_34410662/article/details/86146358

原文地址:http://www.codeproject.com/aspnet/UsePayPalPaymentInASPNET.asp

Introduction

Those who create commercial sites are faced with the question, "How should it receive payments?" One of the most popular payment systems in the world is PayPal. This system is often chosen because it is reliable, simple to use and allows an account to be easily opened. To open an account, you need only have a credit card and/or an account in an American bank. One of shortcomings of the system is its severe security policy. However, practice evinces that if you follow the rules of the system carefully, then errors are very rare. The purpose of this article is to show how payments processing can be organized to support reliability and security. The article is also aimed at providing you with an example of the development of a simple online shop, in order to demonstrate interaction with the PayPal system. You can use the code in your applications to organize interaction with the PayPal system and to process payments.

The article pays special attention to the process of automatic payment verification using IPN (Instant Payment Notification). The article is based on the experience of KB_Soft Group and the official PayPal documentation.

Types of PayPal Payments

PayPal supports several types of payments:

  • Payments for goods in the PayPal cart. PayPal is responsible for all operations supporting the cart in this case. Unfortunately, this option does not provide the maximal flexibility that is required for implementation of some projects, so the article does not consider this option.
  • "One click" shopping. Goods are not put into the cart in this case. This method is also used to pay for goods in a cart that was filled without PayPal. That's why this option provides maximal flexibility and full control of a cart.
  • Recurring billing or subscription. PayPal provides a subscription capability that means that a definite sum will be periodically transferred from the user's account to the seller's account. The user can unsubscribe anytime. The seller can specify the subscription's period and cost. He can also organize a trial period to let the user assess the quality of the services he provides. The trial period can be either paid or free.

For the reasons described above, the article will consider the second option. Subscription will not be described, in order to keep the example simple. To interact with the PayPal system, KB_Soft Group uses UserControl, which is a product internally developed for these purposes. The given example of the code that works with PayPal uses a special HTML form for requests in order to make clear the explanation of interaction with the system. PayPal also provides its own Control as a dynamic library, but unfortunately, this control functions correctly only with American locale (en-us). Besides, it does not provide full functionality to work with PayPal. Neither does it provide the flexibility required to work on some projects.

Payment Process

The payment process is very simple. A POST form is created with a set of hidden fields that contain information about an item (identifier, name, and cost) and a button to send the form. It should be noted that all prices should be expressed with two digits after the point. If an item costs $10, then its price should be expressed as "10.00". When the form is sent, the buyer goes to the PayPal site and finishes the payment process. When a real PayPal account is used, the form should be sent here. The developed example also allows you to work with the PayPal Sandbox. Use the "UseSandbox" parameter of web.config and the form will be sent here.

"One-click" Shopping

A code of the simplest form:

<form method="post" action= "https://www.paypal.com/cgi-bin/webscr"><input type="hidden" name="cmd" value="_xclick"><input type="hidden" name="business" value="my@email.com"><input type="hidden" name="item_name" value="Item name"><input type="hidden" name="item_number" value="1234"><input type="hidden" name="amount" value="19.95"><input type="hidden" name="no_shipping" value="1"><input type="submit" value="Buy Now">
</form>

Description of Main Parameters


Table 1 – Main parameters of the request form
ParameterDescription
cmdThe parameter is obligatory. It must have the "_xclick" value for an unencrypted request.
businessThe parameter is obligatory and represents the seller's e-mail.
item_numberThis parameter is an item identifier. This value will not be shown to the user; however, it will be passed to your script at the time of transaction confirmation. If you plan to use PayPal to pay for goods in a cart, then you can pass the cart's identifier in this parameter.
item_nameThis is a name of the item that will be shown to the user.
no_shippingThis parameter determines whether the delivery address should be requested. "1" means that the address will be requested; "0" means that it will not.
returnThis is the URL where user will be redirected after the payment is successfully performed. If this parameter is not passed, the buyer remains on the PayPal site.
rmThis parameter determines the way information about successful transaction will be passed to the script that is specified in the return parameter. "1" means that no parameters will be passed. "2" means that the POST method will be used. "0" means that the GET method will be used. The parameter is "0" by default.
cancel_returnThis is the URL where user will be redirected when he cancels the payment. If the parameter is not passed, the buyer remains on the PayPal site.
notify_urlThis is the URL where PayPal will pass information about the transaction (IPN). If the parameter is not passed, the value from the account settings will be used. If this value is not defined in the account settings, then IPN will not be used.
customThis field does not take part in the shopping process, it will be simply passed to IPN script at the time of transaction confirmation.
invoiceThis parameter is used to pass the invoice number. The parameter is not obligatory, but being passed it must be unique for every transaction.
amountThis parameter represents an amount of payment. If the parameter is not passed, user will be allowed to enter the amount (this is used for donations).
currency_codeThis parameter represents a currency code. Possible values are "USD","EUR","GBP","YEN","CAD" etc. It is "USD" by default.

Table 1 lists the most frequently used parameters. See the PayPal documentation for the full list of parameters, which is accessible via the references at the end of the article.

IPN

IPN (Instant Payment Notification) is a PayPal technology allowing automation of payments processing. The essence of the technology lies in a special script created on the seller's server. When an event happens related to the seller's account -- for example, a payment transfer, payment cancel, subscription creation or cancel, etc. -- the PayPal server sends a POST request with transaction information to the IPN script. The script in its turn sends a request to the PayPal server to verify the transaction.

So, the buyer has performed a payment. After a delay of up to several seconds, the PayPal server sends the request to the IPN script that is specified in the account settings or passed in the notify_url parameter. A good IPN script is the key to payments security. If you have ever heard that the sellers who use PayPal are victims of somebody's cheating, then be sure that those sellers either do not use IPN at all or have a poor IPN script.

First of all, the script must make sure that it was called by the PayPal server. For these purposes, the script generates a POST request to either here or here. It passes all of the variables it receives, without any changes, together with the cmd parameter having the _notify-validate value. As a response to the request, the script receives either VERIFIED -- meaning that the transaction was successfully verified -- or INVALID in case of an error. If the script receives INVALID, it must terminate.

Then the script must check the payment recipient since a potential intruder may change the form for the payment to be sent to his account. The payment recipient is determined by the business and receiver_email variables. Two variables are necessary because PayPal allows several e-mails to be registered for one account. The e-mail that is specified during account creation is the primary one. The receiver_email is always the primary e-mail. If a payment was sent to another additional e-mail, then the e-mail is passed in the business parameter. If business and/or receiver_email do not contain an expected value, then the script immediately terminates.

Then the script must check the amount and the currency of the payment. This verification is required since the potential intruder may change the payment amount in the form. In case subscription is used, the script should check all subscription parameters, i.e. what parameters are set, duration and cost of trial periods, duration and cost of the main subscription cycle, etc.

IPN for the same transaction can be sent more than once. For example, if a payment was delayed for some reason, the first IPN will be sent immediately after the payment. After the payment is performed or cancelled, the second IPN is sent. If the IPN script does not return the HTTP status equal to 200, then PayPal sends IPN again after some time. The first time it will be repeated in 10 seconds, then in 20 seconds if needed, then in 40, 80, etc. up to 24 hours. If the script does not respond in 4 days, then PayPal stops sending IPN. This can be used in order not to loose transaction information if an error occurs in the IPN script. For example, if the script fails to connect to the database where it stores transaction information, then the script can return the HTTP status equal to 500 and IPN will be repeated later. The repeated IPN will be sent the same way if the IPN script does not refers to the PayPal server to verify the transaction.

As you may see from description of the return, rm and notify_url parameters, IPN can be passed to two scripts specified in the return and notify_url parameters. There are 2 differences between them:

  • IPN for return will be sent only once, after the payment is performed. notify_url can be called several times (see the above paragraph).
  • The result of the return script will be shown to the user. It should be noted that if the result contains links, the links must be absolute. The result of the notify_url script is not displayed in the browser

The received POST variables contain transaction information. The most widely used variables are the following:

Table 2 – The most widely used variables
ParameterDescription
txn_idUnique transaction number.
payment_datePayment date in the "18:30:30 Jan 1, 2000 PST" format .
payer_emailbuyer's e-mail.
businessseller's e-mail.
payer_idUnique identifier of the buyer. Those who take part in payments performed with the help of PayPal are identified by an e-mail address. However, taking into consideration the possibility of changing the e-mail, payer_id should be better used for a buyer's identification.
item_numberItem identifier.
item_nameItem name.
txn_typeTransaction type. Possible values are:
"web_accept" - the payment was performed by clicking the "Buy Now" button.
"cart" - the payment was performed using the built-in PayPal cart.
"send_money" - the payment was performed using the "Send money" function.
"reversal" - money was returned to buyer on his initiative.
payment_statusPayment state. Possible values are:
"Completed" - transaction was successfully performed, money is transferred to seller's account. If txn_type="reversal", then the money is returned to buyer's account.
"Pending" - payment was delayed. The delay reason is determined in the pending_reason variable. After the payment is complete, PayPal will send another one notification.
"Failed" - payment failed. This state is possible only when the payment was performed from a bank account.
"Denied" - seller cancelled the payment. The payment is in this state when the seller cancels the payment having the Pending state before.
"Refunded" - money is returned to buyer. The payment is in this state when seller cancels the payment having the Completed state before.
pending_reasonReason of payment delay. Possible values are:
"echeck" - payment was performed with an e-check
"multi_currency" - payment was performed in the currency that is specified in settings of seller's account. The payment will be completed when the seller confirms the transaction.
"intl" - seller is not a USA dweller. The payment will be completed when the seller confirms the transaction.
"verify" - seller's account is in the "unverified" state. The payment will be completed when the seller is identified.
"address" - settings of a seller's account require the buyer to specify the delivery address, but the buyer does not specify the address. The payment will be completed after seller confirms the transaction.
"upgrade" - the payment was performed using a credit card and the seller's account has the "Personal" status. To complete the payment, the seller should upgrade the account to "Business" or "Premier."
"unilateral" - seller's e-mail is not registered in the system.
"other" - another reason. Seller needs to contact the Support to know more about the reason.
payment_typePayment type. Possible values are:
"echeck" - payment was performed with an e-check.
"instant" - payment was performed with a credit card or using a bank account or money from the buyer's PayPal account.
mc_grossPayment amount.
mc_feeCommission charges. The amount that is put on seller's account is determined as mc_gross – mc_fee.
mc_currencyPayment currency.
first_nameBuyer's name.
last_nameBuyer's last name.
address_streetStreet.
address_cityCity.
address_stateState/region.
address_zipZip Code.
address_countryCountry.
verify_signDigital signature. It is used in PayPal for transaction verification.

An Example of IPN Processing

Given below is an example of a script that uses PayPal IPN. We publish this script not to provide you with a ready script that you can copy/paste, but to illustrate the general principles of working with IPN. KB_Soft Group uses much more complicated scripts to create sites using the PayPal system. This script is rather easy, but at the same time it illustrates the main principles of IPN processing.

The given code creates a simplified version of an online shop. The buyer adds goods into the cart and pays for them. After the buyer pays, a payment report is created.

All information about goods and cart contents is stored in XML files. We chose this way of information storage only for reasons of compatibility. Any user who has downloaded the code can easily adjust and test the created online shop. As for real applications, databases should be better used to store information about goods, carts, payment requests and responses to them.

To store information about goods, we use the Goods.xml file having the following structure:

<Goods><Good id="0" name="Sample of good" price="10.99" /> 
</Goods>

Where...

  • id is a unique item identifier;
  • name is the item name;
  • price is the item price.

To make this example simple, we did not provide the created online shop with the functionality allowing new items to be added to the merchandise catalogue. Information about new items can be manually added into the XML file if needed.

To store information about carts, we use the Carts.xml file having the following structure:

<Carts><Cart rec_id="0" cart_id="1" item_id="0" price="10.99" quantity="1" /> 
</Carts>

Where...

  • rec_id is a unique record identifier;
  • cart_id is an identifier of the cart that contains this item;
  • id is an item identifier;
  • price is the item price;
  • quantity is the quantity of ordered items.

As for real online shops, information about paid carts is not stored there, but is written into the order table of DB. In order to simplify the process and to let you easily track the payment results, we did not implement this capability in the given code. Besides, real online shops should register users in order to be able to identify them and create carts that can be accessed only by their users. The given example does not use registration, so it does not control the access of different users to carts. This process is simplified since the user needs only to select his cart identifier.

To store information about payment requests, we use the PaymentRequests.xml file having the following structure:

<Requests><Request request_id="0" cart_id="1" price="10.99" request_date="5/28/2007 1:15:18 PM" /> 
</Requests>

Where...

  • request_id is a unique request identifier;
  • cart_id is an identifier of the cart being paid;
  • price is the cost of goods;
  • request_date is the date and the time when the request is created.

In real online shops, information about payment requests contains an identifier of payment details from the table of payment details. To simplify the code, we did not use this.

To store information about responses to payment requests, we use the PaymentResponses.xml file having the following structure:

<Responses><Response   payment_id="0" txn_id="3PP58082BD3079037"payment_date="5/28/2007 1:22:40 PM"payment_price="10.99"email= my@email.com first_name=""last_name=""street=""city=""state=""zip=""country=""request_id="0"is_success="True"reason_fault="" /> 
</Responses>

Where...

  • payment_id is a unique payment identifier;
  • txn_id is the unique number of the PayPal transaction;
  • payment_date is the date and time when payment is performed;
  • payment_price is the payment amount;
  • email is the buyer's e-mail;
  • first_name is the buyer's first name;
  • last_name is the buyer's last name;
  • street is the buyer's street;
  • city is the buyer's city;
  • state is the buyer's state;
  • zip is the buyer's ZIP code;
  • country is the buyer's country;
  • request_id is an identifier of payment request;
  • is_success indicates whether the payment was successfully performed;
  • reason_fault is a possible reason of payment failure.

If we use XML files to store information, we should better use the XML schema to validate the information. However, we do not perform validation in order to simplify the example.

The form of payment request that is sent to PayPal is as follows:

minus.gif Collapse
<form id="payForm" method="post" action="<%Response.Write (URL)%>"><input type="hidden" name="cmd" value="<%Response.Write (cmd)%>"><input type="hidden" name="business" value="<%Response.Write (business)%>"><input type="hidden" name="item_name" value="<%Response.Write (item_name)%>"><input type="hidden" name="amount" value="<%Response.Write (amount)%>"><input type="hidden" name="no_shipping" value="<%Response.Write (no_shipping)%>"><input type="hidden" name="return" value="<%Response.Write (return_url)%>"><input type="hidden" name="rm" value="<%Response.Write (rm)%>"><input type="hidden" name="notify_url" value="<%Response.Write (notify_url)%>"><input type="hidden" name="cancel_return" value="<%Response.Write (cancel_url)%>"><input type="hidden" name="currency_code" value="<%Response.Write (currency_code)%>"><input type="hidden" name="custom" value="<%Response.Write (request_id)%>">
</form>

Where...

  • URL is the URL to work with, depending on whether sandbox or a real PayPal account should be used;
  • cmd is a command that is sent to PayPal;
  • business is the seller's e-mail;
  • item_name is the item name -- i.e. what buyer pays for -- that will be shown to user;
  • amount is the payment amount;
  • no_shipping is a parameter that determines whether the delivery address should be requested;
  • return_url is the URL that the buyer will be redirected to when payment is successfully performed;
  • rm is a parameter that determines the way in which information about a successfully finished transaction will be sent to the script specified in the return parameter;
  • notify_url is the URL PayPal will send information about transaction (IPN) to;
  • cancel_url is the URL that the buyer is redirected to when he cancels payment;
  • currency_code is the currency code;
  • request_id is an identifier of payment request.

Values of the variables are set in the PayPal.aspx.cs or the tPayPal.aspx.vb file of the source code attached to the article. See Table 1 for a more detailed description of the fields of the form.

When request_id is passed in the custom field, it allows IPN script to restore information about the cart. If the buyer cancels payment, he is redirected to cancel_url. However, if he performs the payment, he is redirected to return_url. In the latter case, we can test interaction with PayPal, check whether the payment was performed, create a payment report and thank the buyer for the purchase. As for the given example, use the code of IPN processing in the payment_success.aspx.cs or payment_success.aspx.vb file only for testing, since real products should validate payments in the IPN script specified in the notify_url parameter for the purposes of security. The payment_success.aspx.cs or payment_success.aspx.vb code was specially written to make the testing process give as much information as possible. The code contains messages that are important only on the testing stage. This information is written into a log file. The file stores not only critical errors, but also the errors that allow site to keep on working.

In general, error messages should be properly handled, but not shown to users as exceptions. The Response.Write() construction is not a good idea too. Real sites usually create a special page where information about errors is sent. Then the information is formatted and shown to the user. For example, the user should be redirected to this page if an exception is thrown out or a page requested from the site is absent. To simplify the given example, the code writes information about most errors that occur to the log file.

The return parameter is useful because when the payment is performed, it allows the result of the verification to be shown to the user. However, the verification does not provide a 100% guarantee that the payment was really put into the seller's account. For example, if the buyer uses an e-check, then the payment will be put into seller's account only after the check is processed in a bank that also does not provide a guarantee that the money is put into the account. That's why real online shops should use IPN and work with payment, check the payment and protocol it in the code of the IPN script. Besides, the content of the form should be encrypted before it is sent in order to avoid forgery of the payment information. That means that so-called Encrypted Website Payments should be used. If you are not going to use Encrypted Website Payments (EWP) validation, you must check the price, transaction ID, PayPal receiver email address and other data sent to you by IPN to ensure that they are correct. By examining the data, you can be sure that you are not being spoofed.

KB_Soft Group uses both EWP and validation of the parameters received from PayPalin its projects. This provides the duplicated validation check and rules out any possibility of information forgery. In order to simplify the given example of an online shop and to make it work on any PayPal account, we use only IPN. This is because if we use EWP we have to create private and public keys and upload the created public key to our account on the PayPal server. Then we would need to use the obtained identifier of certificate to encrypt the form of the request. Besides, to use EWP we need to download a public key of the PayPal system itself. This article is not aimed at describing in detail the principles of work with EPW, so you can visit the PayPal site to find detailed information on this issue instead.

The IPNHandler class' Page_Load procedure code is given below. You can find detailed information in the archives associated with the source code attached to this article.

C#

minus.gif Collapse
private void Page_Load(object sender, EventArgs e){string requestUriString;CultureInfo provider = new CultureInfo("en-us");string requestsFile = this.Server.MapPath("~/App_Data/PaymentRequests.xml");requests.Clear();if (System.IO.File.Exists(requestsFile)){requests.ReadXml(requestsFile);}else{Carts.CreateXml(requestsFile, "Requests");requests.ReadXml(requestsFile);}string responseFile = this.Server.MapPath("~/App_Data/PaymentResponses.xml");responses.Clear();if (System.IO.File.Exists(responseFile)){responses.ReadXml(responseFile);}else{Carts.CreateXml(responseFile, "Responses");responses.ReadXml(responseFile);}string strFormValues = Encoding.ASCII.GetString(this.Request.BinaryRead(this.Request.ContentLength));// getting the URL to work withif (String.Compare(ConfigurationManager.AppSettings["UseSandbox"].ToString(),"true", false) == 0){requestUriString = "https://www.sandbox.paypal.com/cgi-bin/webscr";}else{requestUriString = "https://www.paypal.com/cgi-bin/webscr";}// Create the request backHttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUriString);// Set values for the request backrequest.Method = "POST";request.ContentType = "application/x-www-form-urlencoded";string obj2 = strFormValues + "&cmd=_notify-validate";request.ContentLength = obj2.Length;// Write the request back IPN stringsStreamWriter writer = new StreamWriter(request.GetRequestStream(), Encoding.ASCII);writer.Write(RuntimeHelpers.GetObjectValue(obj2));writer.Close();//send the request, read the responseHttpWebResponse response = (HttpWebResponse)request.GetResponse();Stream responseStream = response.GetResponseStream();Encoding encoding = Encoding.GetEncoding("utf-8");StreamReader reader = new StreamReader(responseStream, encoding);// Reads 256 characters at a time.char[] buffer = new char[0x101];int length = reader.Read(buffer, 0, 0x100);while (length > 0){// Dumps the 256 characters to a stringstring requestPrice;string IPNResponse = new string(buffer, 0, length);length = reader.Read(buffer, 0, 0x100);try{// getting the total cost of the goods in // cart for an identifier// of the request stored in the "custom" variablerequestPrice = GetRequestPrice(this.Request["custom"].ToString());if (String.Compare(requestPrice, "", false) == 0){Carts.WriteFile("Error in IPNHandler: amount = \");reader.Close();response.Close();return;}}catch (Exception exception){Carts.WriteFile("Error in IPNHandler: " + exception.Message);reader.Close();response.Close();return;}NumberFormatInfo info2 = new NumberFormatInfo();info2.NumberDecimalSeparator = ".";info2.NumberGroupSeparator = ",";info2.NumberGroupSizes = new int[] { 3 };// if the request is verifiedif (String.Compare(IPNResponse, "VERIFIED", false) == 0){// check the receiver's e-mail (login is user's // identifier in PayPal)// and the transaction typeif ((String.Compare(this.Request["receiver_email"], this.business, false) != 0) ||(String.Compare(this.Request["txn_type"], "web_accept", false) != 0)){try{// parameters are not correct. Write a // response from PayPal// and create a record in the Log file.this.CreatePaymentResponses(this.Request["txn_id"],Convert.ToDecimal(this.Request["mc_gross"], info2),this.Request["payer_email"], this.Request["first_name"],this.Request["last_name"], this.Request["address_street"],this.Request["address_city"], this.Request["address_state"],this.Request["address_zip"], this.Request["address_country"],Convert.ToInt32(this.Request["custom"]), false,"INVALID paymetn's parameters" + "(receiver_email or txn_type)");Carts.WriteFile("Error in IPNHandler: INVALID payment's" +" parameters(receiver_email or txn_type)");}catch (Exception exception){Carts.WriteFile("Error in IPNHandler: " + exception.Message);}reader.Close();response.Close();return;}// check whether this request was performed // earlier for its identifierif (this.IsDuplicateID(this.Request["txn_id"])){// the current request is processed. Write // a response from PayPal// and create a record in the Log file.this.CreatePaymentResponses(this.Request["txn_id"],Convert.ToDecimal(this.Request["mc_gross"], info2),this.Request["payer_email"], this.Request["first_name"],this.Request["last_name"], this.Request["address_street"],this.Request["address_city"], this.Request["address_state"],this.Request["address_zip"], this.Request["address_country"],Convert.ToInt32(this.Request["custom"]), false, "Duplicate txn_id found");Carts.WriteFile("Error in IPNHandler: Duplicate txn_id found");reader.Close();response.Close();return;}// the amount of payment, the status of the // payment, amd a possible reason of delay// The fact that Getting txn_type=web_accept or // txn_type=subscr_payment are got odes not mean that// seller will receive the payment.// That's why we check payment_status=completed. The // single exception is when the seller's account in// not American and pending_reason=intlif (((String.Compare(this.Request["mc_gross"].ToString(provider), requestPrice, false) != 0) ||(String.Compare(this.Request["mc_currency"], this.currency_code, false) != 0)) ||((String.Compare(this.Request["payment_status"], "Completed", false) != 0) &&(String.Compare(this.Request["pending_reason"], "intl", false) != 0))){// parameters are incorrect or the payment // was delayed. A response from PayPal should not be// written to DB of an XML file// because it may lead to a failure of // uniqueness check of the request identifier.// Create a record in the Log file with information // about the request.Carts.WriteFile("Error in IPNHandler: INVALID paymetn's parameters."+"Request: " + strFormValues);reader.Close();response.Close();return;}try{// write a response from PayPalthis.CreatePaymentResponses(this.Request["txn_id"],Convert.ToDecimal(this.Request["mc_gross"], info2),this.Request["payer_email"], this.Request["first_name"],this.Request["last_name"], this.Request["address_street"],this.Request["address_city"], this.Request["address_state"],this.Request["address_zip"], this.Request["address_country"],Convert.ToInt32(this.Request["custom"]), true, "");Carts.WriteFile("Success in IPNHandler: PaymentResponses created");///// Here we notify the person responsible for // goods delivery that // the payment was performed and providing // him with all needed information about// the payment. Some flags informing that // user paid for a services can be also set here.// For example, if user paid for registration // on the site, then the flag should be set // allowing the user who paid to access the site//}catch (Exception exception){Carts.WriteFile("Error in IPNHandler: " + exception.Message);}}else{Carts.WriteFile("Error in IPNHandler. IPNResponse = 'INVALID'");}}reader.Close();response.Close();}

Visual Basic

minus.gif Collapse
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.LoadDim ci As CultureInfo = New CultureInfo("en-us")Dim requestsFile As String = Server.MapPath("~/App_Data/PaymentRequests.xml")requests.Clear()If File.Exists(requestsFile) Thenrequests.ReadXml(requestsFile)ElseKBSoft.Carts.CreateXml(requestsFile, "Requests")requests.ReadXml(requestsFile)End IfDim responseFile As String = Server.MapPath("~/App_Data/PaymentResponses.xml")responses.Clear()If File.Exists(responseFile) Thenresponses.ReadXml(responseFile)ElseKBSoft.Carts.CreateXml(responseFile, "Responses")responses.ReadXml(responseFile)End IfDim strFormValues As String = Encoding.ASCII.GetString(Request.BinaryRead(Request.ContentLength))Dim strNewValue' getting the URL to work withDim URL As StringIf AppSettings("UseSandbox").ToString = "true" ThenURL = "https://www.sandbox.paypal.com/cgi-bin/webscr"ElseURL = "https://www.paypal.com/cgi-bin/webscr"End If' Create the request backDim req As HttpWebRequest = CType(WebRequest.Create(URL), HttpWebRequest)' Set values for the request backreq.Method = "POST"req.ContentType = "application/x-www-form-urlencoded"strNewValue = strFormValues + "&cmd=_notify-validate"req.ContentLength = strNewValue.Length' Write the request back IPN stringsDim stOut As StreamWriter = New StreamWriter(req.GetRequestStream(), _Encoding.ASCII)stOut.Write(strNewValue)stOut.Close()'send the request, read the responseDim strResponse As HttpWebResponse = CType(req.GetResponse(), HttpWebResponse)Dim IPNResponseStream As Stream = strResponse.GetResponseStreamDim encode As Encoding = System.Text.Encoding.GetEncoding("utf-8")Dim readStream As New StreamReader(IPNResponseStream, encode)Dim read(256) As [Char]' Reads 256 characters at a time.Dim count As Integer = readStream.Read(read, 0, 256)While count > 0' Dumps the 256 characters to a stringDim IPNResponse As New [String](read, 0, count)count = readStream.Read(read, 0, 256)Dim amount As StringTry                ' getting the total cost of the goods in cart for an ' identifier of the request stored in the "custom"' variableamount = GetRequestPrice(Request("custom").ToString)If amount = "" ThenKBSoft.Carts.WriteFile("Error in IPNHandler: amount = """)readStream.Close()strResponse.Close()ReturnEnd IfCatch ex As ExceptionKBSoft.Carts.WriteFile("Error in IPNHandler: " + ex.Message)readStream.Close()strResponse.Close()ReturnEnd TryDim provider As NumberFormatInfo = New NumberFormatInfo()provider.NumberDecimalSeparator = "."provider.NumberGroupSeparator = ","provider.NumberGroupSizes = New Integer() {3}' if the request is verifiedIf IPNResponse = "VERIFIED" Then                ' check the receiver's e-mail (login is user's ' identifier in PayPal) and the transaction typeIf Request("receiver_email") <> business Or Request("txn_type") <> "web_accept" ThenTry                        ' parameters are not correct. Write a response from ' PayPal and create a record in the Log file.CreatePaymentResponses(Request("txn_id"), Convert.ToDecimal(Request("mc_gross"), provider), _Request("payer_email"), Request("first_name"), Request("last_name"), Request("address_street"), _Request("address_city"), Request("address_state"), Request("address_zip"), Request("address_country"), _Convert.ToInt32(Request("custom")), False, "INVALID paymetn's parameters (receiver_email or txn_type)")KBSoft.Carts.WriteFile("Error in IPNHandler: INVALID paymetn's parameters"+" (receiver_email or txn_type)")Catch ex As ExceptionKBSoft.Carts.WriteFile("Error in IPNHandler: " + ex.Message)End TryreadStream.Close()strResponse.Close()ReturnEnd If                ' check whether this request was performed earlier for its ' identifierIf IsDuplicateID(Request("txn_id")) Then                    ' the current request is processed. Write a response from ' PayPal and create a record in the Log file.CreatePaymentResponses(Request("txn_id"), Convert.ToDecimal(Request("mc_gross"), provider), _Request("payer_email"), Request("first_name"), Request("last_name"), Request("address_street"), _Request("address_city"), Request("address_state"), Request("address_zip"), Request("address_country"), _Convert.ToInt32(Request("custom")), False, "Duplicate txn_id found")KBSoft.Carts.WriteFile("Error in IPNHandler: Duplicate txn_id found")readStream.Close()strResponse.Close()ReturnEnd If' the amount of payment, the status of the payment, amd a ' possible reason of delay' The fact that Getting txn_type=web_accept or ' txn_type=subscr_payment are got odes not mean that' seller will receive the payment.' That's why we check payment_status=completed. The ' single exception is when the seller's account in' not American and pending_reason=intlIf Request("mc_gross").ToString(ci) <> amount Or Request("mc_currency") <> currency_code Or _(Request("payment_status") <> "Completed" And Request("pending_reason") <> "intl") Then' parameters are incorrect or the payment was delayed. ' A response from PayPal should not be' written to DB of an XML file' because it may lead to a failure of uniqueness check of ' the request identifier.' Create a record in the Log file with information about ' the request.KBSoft.Carts.WriteFile("Error in IPNHandler: INVALID paymetn's parameters."+" Request: " + strFormValues)readStream.Close()strResponse.Close()ReturnEnd IfTry                    ' write a response from PayPalCreatePaymentResponses(Request("txn_id"), Convert.ToDecimal(Request("mc_gross"), provider), _Request("payer_email"), Request("first_name"), Request("last_name"), Request("address_street"), _Request("address_city"), Request("address_state"), Request("address_zip"), Request("address_country"), _Convert.ToInt32(Request("custom")), True, "")KBSoft.Carts.WriteFile("Success in IPNHandler: PaymentResponses created")''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Here we notify the person responsible for goods delivery' that the payment was performed and providing him with ' all needed information about the payment. Some flags ' informing that user paid for a services can be also' set here. For example, if user paid for registartion ' on the site, then the flag should be set ' allowing the user who paid to access the site''''''''''''''''''''''''''''''''''''''''''''''''''''''''''Catch ex As ExceptionKBSoft.Carts.WriteFile("Error in IPNHandler: " + ex.Message)End TryElseKBSoft.Carts.WriteFile("Error in IPNHandler. IPNResponse = 'INVALID'")End IfEnd WhilereadStream.Close()strResponse.Close()End Sub

Parameters of web.config Adjustment

To use the source code attached to this article, you need the web.config parameters to be correctly specified. While adjusting the parameters in the web.config file, you should pay a special attention to the appSettings settings:

<appSettings>        <!--  PayPay parameters--><add key="BusinessEmail" value="mymail@mail.com"/><add key="CancelPurchaseUrl" value="http://YOUR_IP/paypal/default.aspx"/><add key="ReturnUrl" value="http://YOUR_IP/paypal/payment_success.aspx"/><add key="NotifyUrl" value="http://YOUR_IP/paypal/IPNHandler.aspx"/><add key="CurrencyCode" value="USD"/><add key="UseSandbox" value="true"/><add key="SendToReturnURL" value="true"/>
</appSettings> 

Specify the e-mail of the payment recipient in the BusinessEmail parameter. This can be the e-mail that was used while creating an account on PayPal or an alternative e-mail specified in the account parameters as the alternative e-mail. The e-mail that is used as the login to the PayPal account is usually specified in this parameter. As for the CancelPurchaseUrl, ReturnUrl and NotifyUrl parameters: in YOUR_IP you need to specify your global IP address -- not your IP address in local network -- or a domain of the registered site on which the seller's site is hosted. While testing, you may simply specify "localhost" instead of YOUR_IP. It should be noted that IPN will function only if you correctly specify the global IP address or the name of a registered domain. If you specify "localhost," then only the script specified in the ReturnUrl parameter will be able to support interaction with PayPal. The script specified in the NotifyUrl parameter will not. You should keep in mind that IPN may be blocked, depending on the Firewall settings.

The above links are given for the "paypal" virtual directory. If you use another virtual directory or site, you need to specify its name instead of "paypal." To check whether your NotifyUrl is valid, enter its address into "Notification URL:" filed at Profile->Instant Payment Notification Preferences->Edit in your PayPal Business or Premier account. Check the checkbox on this page and click the "Save" button. If the URL is valid, a message about successful validation will be shown.

The CurrencyCode parameter is used to specify the code of the currency that is used for payment. The UseSandbox parameter is used to switch between PayPal SandBox and real PayPal accounts. The SendToReturnURL parameter is used to turn on/off notifications sending to return_url. SendToReturnURL is recommended to be set to true only for the purposes of testing.

Use of the Source Code

Archives with the source code of a simplified online shop are attached to this article. You can use this code in your software products to support interaction with PayPal when you need to perform payments.

To use the code supplied with the article, you need to have .NET Framework 2.0 or higher installed on your system. You also need to have a real or SandBox PayPal account. No additional requirements should be needed to open a SandBox account. However, to create a real PayPal account you need to have a credit card and/or an account in any American bank. Make sure that the standard WebClient service is running on your system. If you have Visual Studio 2005, you can run tests by opening the paypal.sln solution and executing the code. IPN will not be available in this case. An alternative option is the creation of a virtual directory on the IIS server.

Conclusion

In conclusion, I would like to give you some advice:

  • Do not ever trust the data obtained by IPN script before you receive the VERIFIED response from PayPal. Information about processed transactions should be kept. So, when the VERIFIED response is received, you can make sure that the transaction was not processed before.
  • Do not use payer_email to identify buyers, as the e-mail can be changed. Use payer_id.
  • txn_type=web_accept does not mean that the seller will receive payment. You should always check if payment_status=completed. The single exception is a seller whose account is not American and pending_reason=intl.
  • Failures are not impossible in any system and PayPal is no exception. If IPN script receives suspect data, it should be written to log and an administrator should be informed about this. It is also useful to implement a form for users to be able to inform you about errors.

References

  • PayPal Help Center.
  • This is an independent forum of PayPal developers.
  • This page contains a guide on the Buy Now Button.
  • This page contains a guide on Encrypted Website Payments.
  • This page contains recommendations on testing with the help of PayPal Sandbox.
  • This page contains variables that can be used to create HTML code for use with Website Payments Standard.
  • This page contains the latest version of this article and the C# implementation of the example described in the article.

History

  • 14 June, 2007 -- Original version posted.
  • 27 June, 2007 -- Added the C# implementation of the example described in article (see here).
  • 24 August, 2007 -- Source code download updated

About Alexandr Golovanov

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_701362.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TP5实现支付宝电脑网站支付学习笔记

这两天在公司做一个小型WEB项目,需要有支付功能。第一次做支付宝的支付&#xff0c;踩了点小坑&#xff0c;还算顺利。激动的我赶紧记下实现的流程。第一步当然是在支付宝开放平台申请公钥私钥APPID等&#xff0c;支付宝关官方文档都有详细介绍&#xff0c;这里就省略。申请完了…

视频直播网站开发千万不能忘的一个知识点

对于视频直播网站开发的技术人员来讲&#xff0c;音视频即时通讯技术是需要熟练掌握的。毕竟像直播这样重视互动和实时性的应用场景&#xff0c;即时通讯可以从中起到很大的配合作用。目前市面上有很多服务商所提供的SDK可以帮助实现这一技术&#xff0c;但是在选择哪一家服务商…

基于SSH的在线音乐点评网站-java在线音乐点评网站

基于SSH的在线音乐点评网站-java在线音乐点评网站 开发环境&#xff1a;Eclipse for J2EE,MYSQL5.1,JDK1.7,Tomcat 7首页主要展示一些最新的音乐专辑。(1)用户注册&#xff1a;用户填写注册账号、密码。(2)用户登录&#xff1a;用户注册成功后&#xff0c;使用注册账号、密码登…

PrestaShop 网站漏洞修复办法

PrestaShop网站的漏洞越来越多&#xff0c;该网站系统是很多外贸网站在使用的一个开源系统&#xff0c;从之前的1.0初始版本到现在的1.7版本&#xff0c;经历了多次的升级&#xff0c;系统使用的人也越来越多&#xff0c;国内使用该系统的外贸公司也很多&#xff0c;PrestaShop…

分享7个我常去的国外AjaxJquery网站

经常逛这些国外的网站&#xff0c;看到很不错的控件和Jquery的演示DEMO:今天拿出来和大家分享一番: Ajax Rain&#xff1a;http://www.ajaxrain.com/ AjaxRain有很多完美整合AJAX, CSS, DHTML 或 Javascript的实例&#xff0c;有一些Demo的确值得你去看一看 Ajax Daddy:http://…

jsp网站访问次数统计

JSP 点击量统计 有时候我们需要知道某个页面被访问的次数&#xff0c;这时我们就需要在页面上添加页面统计器&#xff0c;页面访问的统计一般在用户第一次载入时累加该页面的访问数上。 要实现一个计数器&#xff0c;您可以利用应用程序隐式对象和相关方法getAttribute()和setA…

如何利用竞价的思维去做seo?

网络营销分为网络优化与网络推广&#xff0c;网络优化主要是通过自然排名的方式展现在搜索引擎页面&#xff0c;网络推广主要是通过付费的方式展现在搜索引擎前面&#xff0c;基本上这两个是分开的&#xff0c;那么我们如何去利用竞价的思维去做seo? 下面[星若文化(http://www…

【原创】【推荐】《ASP.NET 3.5+SQL Server网站模块化开发全程实录》出版记

进过半年多的努力&#xff0c;《ASP.NET 3.5SQL Server网站模块化开发全程实录》一书终于得以由清华大学出版社顺利出版。 第一次出版此类图书&#xff0c;不免其中会有诸多纰漏&#xff0c;还望广大读者不吝指正、批评。本书定位的读者群为&#xff1a;初、中级网站开发人员&a…

原始数据哪里找?这些网站要用好!200个国内外经济/金融/行研/咨询数据网站大全(附链接)...

来源&#xff1a;社科方法网本文约8000字&#xff0c;建议阅读10分钟本文为你提供200个国内外经济、金融、行研、咨询数据网。来源&#xff1a;数据玩家资料搜集是个相当繁琐与累的工作&#xff0c;也是投资入门的基本&#xff0c;良好的信息资料搜集能力有利于我们快速了解投资…

如何理解“跳出率”,它对SEO有什么影响?

跳出率是搜索引擎优化专家&#xff0c;多年以来热衷讨论的话题&#xff0c;特别是在衡量企业网站相关产品转化率的时候&#xff0c;有着重要的参考价值&#xff0c;但在以往的数据分析中&#xff0c;却又是经常被SEO人员所忽略的指标。因此&#xff0c;正确的认知“跳出率”对网…

学术必备!35个国内外社会科学数据网站资源汇总(附链接)

来源&#xff1a;社科方法网本文约10000字&#xff0c;建议阅读20分钟。本文介绍了目前国内外常用的35个数据资源网站。目录UK Data ArchiveData.gov.uk nter-university Consortium for Political and Social Research&#xff08;Michigan&#xff09; National Data Archive…

[CSS]30种时尚的CSS网站导航条

【原文地址】&#xff1a;http://coolshell.cn/?p562 我想&#xff0c;大家在上网的时候一定见过很多很多种各式各样的网站导航条的设计。这些导航条基本上来说都是用CSS来做的。这里&#xff0c;我们将向你介绍几种最不错的用CSS设计的网站导航条。希望你会喜欢。 1. The Men…

原始数据哪里找?这些网站要用好!200个国内外经济/金融/行研/咨询数据网站大全(附链接)...

来源&#xff1a;社科方法网本文约8000字&#xff0c;建议阅读10分钟本文为你提供200个国内外经济、金融、行研、咨询数据网。来源&#xff1a;数据玩家资料搜集是个相当繁琐与累的工作&#xff0c;也是投资入门的基本&#xff0c;良好的信息资料搜集能力有利于我们快速了解投资…

【前端】20款国外非常漂亮的优秀网站404错误页面HTML模板

404错误页面是一个非常普遍的现象&#xff0c;该页面的目的是告诉浏览者其所请求的页面不存在或链接错误&#xff0c;同时引导用户使用网站其他页面而不是关闭窗口离开。虽然404错误页面在所难免&#xff0c;但网页设计师们却可以在该页面上做一些有趣的变动&#xff0c;引导用…

干货 | 外文文献哪里找?八大网站免费下载!

来源&#xff1a;研鹿论文本文约1300字&#xff0c;建议阅读6分钟本文为你汇总免费外文文献书籍网站。疫情期间宅在家的你们都做些什么呢&#xff1f;第一次感觉玩手机都这么无聊&#xff0c;小编不由自主地都开始写论文了可是宅在家里&#xff0c;没有谷歌学术&#xff0c;没有…

独家 | 为你的数据科学项目提供有力支撑——3个寻找数据集的最佳网站

作者&#xff1a;Angelia Toh&#xff0c;Self Learn Data Science联合创始人翻译&#xff1a;李海明校对&#xff1a;冯羽本文约1000字&#xff0c;建议阅读5分钟本文为你介绍3个寻找数据集的最佳网站。标签&#xff1a;冠状病毒&#xff0c;数据&#xff0c;数据科学&#xf…

多家IT企业通过CNNIC“可信网站”验证

据中国互联网络信息中心(CNNIC)联合国家互联网应急中心(CNCERT)发布的《2009年中国网民网络信息安全状况调查报告》显示&#xff0c;2009年有4500万网民遭受网络欺诈,占网民总数的11.9%&#xff0c;损失金额达76亿元&#xff0c;若按8788万的活跃网购用户来计算&#xff0c;平均…

阿里云一键建站产品,阿里云自营建站-中小企业建站首选...

阿里云推出的自营建站服务&#xff0c;这对于中小企业来说简直是福利了&#xff0c;现在一般的公司都开始有了自己的官网&#xff0c;有可能就是因为你的官网设计的标准&#xff0c;大气&#xff0c;客户就会对你的信任度增加&#xff0c;从而促进一笔不小的订单&#xff0c;这…

分享一些好用的网站

前言 这两年收藏了不少网站&#xff0c;特地整理一下&#xff0c;把一些大家都可能用得上的分享出来&#xff0c;希望能对你有用。 考虑到有一些网站大多数人都知道&#xff0c;所以我就不列出来了。 我把这些网站分为了几大类&#xff1a; 工具类素材类社区类工具类 1、start.…

CTO 写的低级 Bug 再致网站被黑,CEO 的号都被盗了!

‍‍整理 | 郑丽媛出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;上周&#xff0c;美国开源社交网络服务平台 Gab &#xff0c;因其 CTO 写的低级 Bug 受到黑客攻击&#xff0c;导致约 70GB 的数据被窃取。可该公司开发者还没完全修复其易受攻击的代码&#xff0c…