用于管理 PayPal 即时付款通知的一些简单 PHP 类






4.88/5 (5投票s)
一些用于处理 PayPal 即时付款通知的类,以便在您的端进行必要的处理。
更新
- 2014 年 10 月 29 日:采纳了 Jeremy Falcon 的善意反馈。
- 2014 年 11 月 4 日:终于在 PayPal Sandbox 中进行了测试,并修复了出现的错误。
引言
这是一篇快速撰写的文章,旨在分享一种通过 PHP 管理 PayPal 即时付款通知 (IPN) 的方法。看了网上一些例子,我被它们混乱的结构惊呆了——它们似乎都基于 PayPal 的示例代码,而 PayPal 的示例代码远非全面。此外,它们大多是整体性的,很难理解所有必要的步骤。但多亏了它们,我才得以弄清楚,本文中的代码就是成果。希望通过分享,其他人可以免受我经历的困难。
下面的类也不够全面,因为它们只处理了我对单一商品购买的需求。可能还缺少其他一些功能,但它们对我来说是有效的,并且应该为那些希望更进一步的人提供一个良好的起点。
我通过将 IPN 处理过程分解为负责逻辑子任务的对象来处理 IPN。这使得熟悉面向对象的人更容易理解一切。(如果您不熟悉,我希望这能帮助您看到它的好处,并更深入地掌握这种方法。它将为您节省未来大量的工作。)
CodeProject 上还有其他几种 IPN 付款方法,您也可以查看。我找到的是 C# 和 ASP.NET 的。截至 2013 年 7 月,AllanPolich、becker666 和 Mat Stine 的文章似乎与此任务最相关。如果您发现我遗漏了其他文章,请随时指出。(DaSpors 在评论中链接了一个令人印象深刻的 PHP/JavaScript/SQL 购物车解决方案,如果您需要额外的付款选项,它可以处理比 PayPal IPN 更多的事情。)
解决方案
为了不泄露我自己的设置中的重要细节,我将复制/粘贴下面的代码并将相关信息进行更改。这会使文章显得很长,像是一堆代码,但我也会在此添加一些注释,以便更容易理解方法。我相信代码是自解释的,这可能是一种安慰,但我仍然为不便道歉,因为您需要在自己的项目中使用它们时复制粘贴七个文件。如果将来有足够的需求,我会花时间创建一个修改后代码的 zip 文件,但现在我想尽快回到其他项目。
我的解决方案将过程分解为五个对象
payPalController
- 此类处理 PayPal 流程的非 IPN 部分的逻辑。它会检查 PayPal 发送的重复交易,并验证 IPN 交易中的产品是否确实是我网站上的产品。如果属实,它将开始将购买添加到数据库并向客户发送电子邮件。payPalIpn
- IPN 处理发生在这里。非常重要!rmwStoreDB
- 此单元负责将交易添加到我的数据库。myMailClass
- 一个基础邮件类,可以大大扩展以更好地处理 HTML 电子邮件,但它提供了基本功能。它依赖于 Swift Mailer 在后台运行,使其工作更加轻松。myLoggerClass
- 记录错误,并在出现问题时向您发送电子邮件(如果其设置中指定了此类操作)。
此外,还有两个非类文件,用于存储
- 数据库设置信息,和
- 电子邮件帐户信息
要使其正常工作,您必须执行三个步骤。首先,您必须设置数据库,这一点我不会在此赘述。如果您还没有设置过,网上有很多资源可以帮助您完成此过程。然后,您必须将五个类文件和两个密码文件复制到公共可见目录的最底层子目录中,并根据您的需求进行修改(其中“底层”指的是浏览器可视图的文件夹)。最后,您为 PayPal 指定的接收通知的网页(如果您选择逐个按钮设置,则需要这样做)必须看起来像这样
<!doctype html public '-//W3C//DTD HTML 4.01//EN' 'http://www.w3.org/TR/html4/strict.dtd'>
<html>
<head>
<title>RandomMonkeyWorks</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Generator" content="Notepad++">
<meta name="Description" content="PayPal IPN Processor">
<meta name="Keywords" content="Nothing">
</head>
<body>
<!-- The code to deal with the PalPal logic: -->
<?php
//The following is for the directory below publicly visible,
//where the processing stuff is:
$base = dirname(dirname(dirname(__FILE__)));
define('BASE_PATH', $base == DIRECTORY_SEPARATOR ? $base : $base . DIRECTORY_SEPARATOR);
require_once (BASE_PATH . "phpPayPalController.php");
$ppc = new payPalController();
$ppc->setTesting(false);
$ppc->setLogging(false);
$ppc->processPayPalIpnPayment();
?>
<!-- THINGS TO DO WHEN GOING FROM TESTING TO PRODUCTION: -->
<!-- Change 'testing' to false via the '$ppc->setTesting' line above -->
<!-- Make certain buttons are coded correctly on site to access this page -->
<!-- Make certain the phpPayPalIpnClass opens socket to proper secured server -->
</body>
</html>
如您所见,payPalController
是页面唯一需要了解的单元。控制器会自己设置其他类
<?php
//This should be placed in the subdirectory beneath the user-accessible
//one. On localhost this can't be done, so remember to do it manually
//when copying to the site.
require_once(BASE_PATH . "phpPayPalIpnClass.php");
require_once(BASE_PATH . "phpLoggerClass.php");
require_once(BASE_PATH . "phpRmwStoreDbActions.php");
require_once(BASE_PATH . "phpMyMailClass.php");
class payPalController {
private $db;
private $logger;
private $testing;
function __construct() {
$this->logger = new myLogger();
$this->logger->setLogFile("log.txt");
$this->logger->setLogging(false);
$this->db = new rmwStoreDB();
$this->db->setLogger($this->logger);
$this->testing = false;
}
function setTesting($state) {
$this->testing = $state;
$this->logger->setLogging($state);
}
function setLogging($state) { $this->logger->setLogging($state); }
function processPayPalIpnPayment() {
$processor = new payPalIpn();
$processor->setTesting($this->testing);
$processor->setLogger($this->logger);
$this->logger->log("Processing a payment." . PHP_EOL);
if (!$this->validatePostData()) return;
if (!$processor->processPost()) return;
if ($this->duplicateTransaction()) return;
if (!$this->verify()) return;
if (!$this->addOrderToDatabase()) return;
$this->sendProduct();
}
function validatePostData() {
$step = 0;
$ret = true;
if(!isset($_POST['txn_id'])) $step = 1;
if(!isset($_POST['shipping'])) $step = 2;
if(!isset($_POST['quantity'])) $step = 3;
if(!isset($_POST['mc_gross'])) $step = 4;
if(!isset($_POST['mc_gross'])) $step = 5;
if(!isset($_POST['last_name'])) $step = 6;
if(!isset($_POST['first_name'])) $step = 7;
if(!isset($_POST['address_zip'])) $step = 8;
if(!isset($_POST['mc_currency'])) $step = 9;
if(!isset($_POST['item_number'])) $step = 10;
if(!isset($_POST['payer_email'])) $step = 11;
if(!isset($_POST['address_city'])) $step = 12;
if(!isset($_POST['address_name'])) $step = 13;
if(!isset($_POST['address_state'])) $step = 14;
if(!isset($_POST['address_street'])) $step = 15;
if(!isset($_POST['receiver_email'])) $step = 16;
if(!isset($_POST['payment_status'])) $step = 17;
if(!isset($_POST['address_country'])) $step = 18;
//if(!isset($_POST['option_selection1'])) $step = 19;
if ($step != 0) $ret = false;
if ($ret == false) {
$this->logger->log("POST DATA not set: $step" . PHP_EOL);
$response = "";
foreach ($_POST as $key => $value) {
$numPosts += 1;
if($magicQuotesFuncExists == true && get_magic_quotes_gpc() == 1) {
$value = urlencode(stripslashes($value));
}
else {
$value = urlencode($value);
}
$response .= "&$key=$value" . PHP_EOL;
}
$this->logger->log($response);
}
return $ret;
}
private function duplicateTransaction() {
$ret = false;
if ($this->db->itemExists("orders", "payPalTransId", $_POST['txn_id'])) {
$this->logger->log("Transaction: " . $_POST['txn_id'] . " exists" . PHP_EOL);
$ret = true;
}
else {
$this->logger->log("Transaction: " . $_POST['txn_id'] .
" does not exist" . PHP_EOL);
}
return $ret;
}
private function verify() {
$nl = PHP_EOL;
//First, check for valid item number:
if (!$this->db->itemExists("products", "id", $_POST ['item_number'])) {
$this->logger->log("Item number: " . $_POST['item_number'] .
" doesn't exist in database$nl");
return false;
}
else {
$this->logger->log("Item number: " . $_POST['item_number'] .
" exists in database$nl");
}
//Check that we received the proper amount, or more, in the case of Texas taxes:
$this->dbPrice = $this->db->getCellValue("price", "products", "id",
$_POST['item_number']);
if ($_POST['mc_gross'] < $this->dbPrice) {
$this->logger->log("Payment received (" . $_POST ['mc_gross'] .
") less than item price. (" . $this->dbPrice . PHP_EOL);
return false;
}
else {
$this->logger->log("Adequate payment received (" . $_POST ['mc_gross'] .
").$nl");
}
if ($_POST['mc_currency'] != "USD") {
$this->logger->log("Paid in non-US funds - need to investigate.$nl");
return false;
}
else {
$this->logger->log("US Currency received - OK.$nl");
}
if ($_POST['receiver_email'] != "someone@somewhere.com"
&& $_POST['receiver_email'] != "someone@somewhere.com") {
$this->logger->log("Incorrect receiver email received (" .
$_POST['receiver_email'] . ")$nl");
return false;
}
else {
$this->logger->log("Correct email received (
" . $_POST['receiver_email'] . ")$nl");
}
//And the most important one:
if ($_POST['payment_status'] != "Completed") {
$this->logger->log("Payment incomplete from PayPal$nl");
return false;
}
return true;
}
private function addOrderToDatabase() {
//Everything will revolve around email address as of primary importance; if there is
//one in the database the record will be updated to reflect any changes to the
//account. If one doesn't exist, one will be created.
$this->logger->log("Updating database." . PHP_EOL);
$this->db->addOrUpdateUser();
$this->db->addOrder();
return true;
}
private function sendProduct() {
$nl = PHP_EOL;
$mailHandler = new myMailer();
$mailHandler->setLogger($this->logger);
if ($this->testing) {
$mailTo = 'someone@somewhere.com';
}
else {
$mailTo = $_POST['payer_email'];
}
if ($_POST['item_number'] == "something") {
doSomething(); //You get the idea...
}
}
}
?>
在上面的代码块中,为了更美观的格式,我将一些可能需要在移植到您的站点时取消换行的行进行了换行。它们很可能可以直接使用,但以防万一,值得注意。另外,请记住更改本文中使用的电子邮件地址。
这带我们来到了 payPalIpn
类。正如之前所说,它处理 IPN 处理,并将正确的响应发送回 PayPal。
<?php
require_once(BASE_PATH . "phpLoggerClass.php");
class payPalIpn {
private $logger; //This will actually be a reference; see 'setLogger'
//for mechanism which accomplishes this.
private $ipnVerifiedC;
private $testingC;
function __construct() {
$this->ipnVerifiedC = false;
$this->testingC = false;
}
function ipnVerified() { return $this->ipnVerifiedC; }
function setTesting($state) { $this->testingC = $state; }
function setLogger(myLogger &$logFile) { $this->logger = $logFile; }
function processPost() {
// Send an empty HTTP 200 OK response to acknowledge receipt of the notification
//header('HTTP/1.1 200 OK');
$nl = PHP_EOL;
//Log the contents if the logger is set to do so:
$this->logger->log("RECEIVED:$nl" . var_export($_POST, true) . PHP_EOL);
//Everything below here is originally from
//http://designertuts.com/wp-content/uploads/2007/10/paypalipnphp.txt, which was said
//to be a copy of the example code specified on the Paypal site. Of course, I modified
//formatting and necessary logic. Quite a lot, actually.
//Paypal POSTs HTML FORM variables to this page. We must return all the variables
//back to PayPal unchanged and add an extra parameter 'cmd 'with value
//'_notify-validate'
$response = 'cmd=_notify-validate';
//Check for magic quotes (this comes from a PayPal pdf on IPN usage - don't remember
//the URL):
$magicQuotesFuncExists = false;
if(function_exists('get_magic_quotes_gpc')) {
$magicQuotesFuncExists = true;
}
//The following variable is used for a quick, dummy check to keep from sending a
//response unless the POST was long, meaning it probably came from PayPal:
$numPosts = 0;
// go through each of the POSTed vars and add them to the variable
foreach ($_POST as $key => $value) {
$numPosts += 1;
if($magicQuotesFuncExists == true && get_magic_quotes_gpc() == 1) {
$value = urlencode(stripslashes($value));
}
else {
$value = urlencode($value);
}
$response .= "&$key=$value";
}
$this->logger->log("AFTER MAGIC QUOTES:$nl".var_export($_POST, true).PHP_EOL);
// post back to PayPal system to validate
$header = "POST /cgi-bin/webscr HTTP/1.1$nl";
$header .= "Host: www.sandbox.paypal.com$nl";
$header .= "Content-Type: application/x-www-form-urlencoded$nl";
$header .= "Content-Length: " . strlen($response) . PHP_EOL . PHP_EOL;
//In a live application send it back to www.paypal.com, but during development use
//the PayPal sandbox. Paypal Sandbox only seems to accept using ssl connections,
//and on port 443.
if ($this->testingC) {
$socket = fsockopen ('ssl://www.sandbox.paypal.com', 443, $socketErrNum,
$socketErrStr, 30);
}
else {
$socket = fsockopen ('ssl://www.paypal.com', 443, $socketErrNum,
$socketErrStr, 30);
}
//Oldie: $socket = fsockopen ('www.paypal.com', 80, $socketErrNum,
// $socketErrStr, 30);
if ($socket) $this->logger->log("Socket successful$nl");
else $this->logger->log("Socket failed!$nl");
if (!$socket) {
// HTTP ERROR Failed to connect. Send me an email notification:
$mail_Body = "Error from fsockopen:$nl" . $socketErrStr .
"$nl$nlOriginal PayPal Post Data (COULD BE BOGUS!)$nl$nl";
foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$mail_Body .= "&$key=$value" . PHP_EOL;
}
mail($myEmail, "IPN Error Noficiation: Failed to connect to PayPal", $mail_Body,
"someone@somewhere.com");
// The original code used "fwrite($fh, $socketErrStr)" for the following:
$this->logger->log("Socket error: " . $socketErrStr);
return;
}
//Now respond to PayPal's posting. The previous 'if' statement returned
//and terminated this if there was a socket error, so we can concentrate on what we
//need. First, send our response to the POST, and check for verification:
$receivedVerification = false;
$this->logger->log("Number of posts: $numPosts$nl");
//Only send a response if it comes from PayPal.
//The quick and dirty way to do so is see how many posts were in the original message:
if ($numPosts > 3) {
//Actually send the response:
$this->logger->log("Sending the post back:$nl");
fputs ($socket, $header . $response);
$this->logger->log("SENT:$nl$nl$header$response$nl$nl");
//And get their response. First lines will be transaction data, finally followed by
//'VERIFIED' or 'UNVERIFIED' (or something). It took a
//little work to find out that SSL had to be used for the Sandbox, and to get it
//working correctly. But the previous '$socket' initialization finally
//succeeded.
$receivedVerification = false;
$endOfStreamReached = false;
while (!feof($socket) && !$endOfStreamReached && !$receivedVerification) {
$result = fgets ($socket, 1024); //Get a line of response
$this->logger->log("RECEIVED: $result");
if (strncmp ($result, "VERIFIED", 8) == 0) {
$receivedVerification = true;
//$this->logger->log("VERIFIED! VERIFIED! VERIFIED!$nl");
}
//else {
// $this->logger->log("NOT VERIFIED HERE!$nl");
// }
if (strncmp ($result, "0", 1) == 0) $endOfStreamReached = true;
}
}
fclose ($socket);
$result = false;
if ($receivedVerification == false) {
$this->logger->log(
"$nl$nlINVALID TRANSACTION! (Improper PayPal response received)$nl");
}
else {
$this->ipnVerifiedC = true;
$this->logger->log("TRANSACTION VERIFIED!$nl");
$result = true;
}
return $result;
}
}
?>
接下来是数据库处理。第一行的 *db_config.php* 文件存储数据库用户名和密码信息。*db_config.php* 不应暴露给外部世界至关重要,这就是为什么您必须将其放在站点最顶层的公共文件夹下方。
<?php
require_once(BASE_PATH . "pp_db_config.php");
require_once(BASE_PATH . "phpLoggerClass.php");
class rmwStoreDB {
private $loggerC; //This will actually be a reference;
//see 'setloggerC' for mechanism which accomplishes this.
private $lastRowC;
function setlogger(mylogger $logFile) { $this->loggerC = $logFile; }
function tellDb($sql) {
$ret = mysql_query($sql);
if (!$ret) {
$this->loggerC->log("DATABASE ERROR:" . PHP_EOL . mysql_error() . PHP_EOL .
"Query: " . HtmlEntities($sql));
die();
}
return $ret;
}
function itemExists($table, $column, $value) {
$rows = $this->tellDb("Select * from " . $table . " where " . $column . " = '" .
$value . "'");
$lastRowC = mysql_fetch_array($rows);
if ($lastRowC) return true;
return false;
}
function getCellValue($what, $table, $column, $theId) {
//No checking will be done to ensure only one row is returned, and default value
//will be '0.00.'
$rows = $this->tellDb("Select " . $what . " from " . $table . " where " . $column .
" = " . $theId);
$row = mysql_fetch_array($rows);
if ($row) return $row['price'];
else return 0.00;
}
function addOrUpdateUser() {
//We are using the $_POST data, which is global to the application.
//These are the fields we are dealing with: 'first_name' 'last_name'
//'payer_email', and, for shipped products ONLY - 'address_name'
//'address_street' (can be 2 lines separated by PHP_EOL?) 'address_city'
//'address_state' 'address_zip' 'address_country_code' 'address_country'
//First, see if the user exists:
$rows = $this->tellDb("Select * from customers where email = '" .
$_POST['payer_email'] . "'");
//Simply use the first of the returned rows:
$row = mysql_fetch_array($rows);
if (!$row) {
$this->loggerC->log("Adding user to database");
$this->addUser();
}
else {
$this->loggerC->log("User already exists in DB." . PHP_EOL);
//See if the records match the ones we have, and if not, change it:
$this->updateUser($row);
}
}
private function addUser() {
$cmd = "Insert into customers (firstName, lastName, shippingName, email," .
"addressLine1, city, state, zipCode, country) values ('"
. $_POST['first_name'] . "', '" .
$_POST['last_name'] . "', '" .
$_POST['address_name'] ."', '" .
$_POST['payer_email'] . "', '" .
$_POST['address_street'] . "', '" .
$_POST['address_city'] . "', '" .
$_POST['address_state'] . "', '" .
$_POST['address_zip'] . "', '" .
$_POST['address_country'] . "')";
$this->tellDb($cmd);
$this->loggerC->log("Added: '" . $_POST['first_name'] . "', '" .
$_POST['last_name'] . "', '" .
$_POST['address_name'] . "', '" .
$_POST['payer_email'] . "', '" .
$_POST['address_street'] . "', '" .
$_POST['address_city'] . "', '" .
$_POST['address_state'] . "', '" .
$_POST['address_zip'] . "', '" .
$_POST['address_country'] . "')");
}
private function updateUser(array $row) {
//First, check old values:
if ($row['firstName'] != $_POST['first_name'] ||
$row['lastName'] != $_POST['last_name'] ||
$row['shippingName'] != $_POST['address_name'] ||
$row['email'] != $_POST['payer_email'] ||
$row['addressLine1'] != $_POST['address_street'] ||
$row['city'] != $_POST['address_city'] ||
$row['state'] != $_POST['address_state'] ||
$row['zipCode'] != $_POST['address_zip'] ||
$row['country'] != $_POST['address_country']) {
//Form a command string:
$cmd = "UPDATE customers SET ";
$cmd .= "firstName = '" . $_POST['first_name'] . "', ";
$cmd .= "lastName = '" . $_POST['last_name'] . "', ";
$cmd .= "shippingName = '" . $_POST['address_name'] . "', ";
$cmd .= "addressLine1 = '" . $_POST['address_street'] . "', ";
$cmd .= "city = '" . $_POST['address_city'] . "', ";
$cmd .= "state = '" . $_POST['address_state'] . "', ";
$cmd .= "zipCode = '" . $_POST['address_zip'] . "', ";
$cmd .= "country = '" . $_POST['address_country'] . "' ";
$cmd .= "WHERE email = '" . $_POST['payer_email'] . "'";
$this->loggerC->log(PHP_EOL . "Changing user with email " .
$_POST['payer_email'] . PHP_EOL);
$old = $row['firstName'] . ", " . $row['lastName'] . ", " .
$row['shippingName'] . ", " . $row['email'] . ", " .
$row['addressLine1'] . ", " . $row['city'] . ", " .
$row['state'] . ", " . $row['zipCode'] . ", " .
$row['country'] . PHP_EOL . PHP_EOL;
$this->loggerC->log($old);
$this->loggerC->log($cmd . PHP_EOL);
$this->tellDb($cmd);
}
}
function addOrder() {
$nl = PHP_EOL;
//Everything will be in the $_POST values
//First, get the customer number:
$cmd = "Select id from customers where email = '" . $_POST['payer_email'] . "'";
//We just entered this information into the database, so error checking isn't
//really needed? We will put something in just for grins.
$rows = $this->tellDb($cmd);
$row = mysql_fetch_array($rows);
if (!$row) {
$this->loggerC->log("HUGE PROBLEM! CUSTOMER ID NOT FOUND - ABORTING$nl");
die();
}
$id = $row['id'];
$theDate = date('F j, Y, g:i a');
$tz = date('T');
$ppID = $_POST['txn_id'];
$grossPay = $_POST['mc_gross'];
$shipping = $_POST['shipping'];
$cmd = "Insert into orders (customer, date, timeZone, payPalTransId, grossPmt, " .
"shipping) values ('$id', '$theDate', '$tz', '$ppID', '$grossPay', '$shipping')";
$this->tellDb($cmd);
$this->loggerC->log("Inserting order into orders table:$nl$cmd$nl$nl");
//Now we have to add the order items into the orderItems table.
//First, we need to get the order number from the record which was just entered:
$cmd = "Select id from orders where payPalTransId = '$ppID'";
$rows = $this->tellDb($cmd);
$row = mysql_fetch_array($rows);
//Should not need this, but...
if (!$row) {
$this->loggerC->log("HUGE PROBLEM! ORDER ID NOT FOUND - ABORTING$nl");
die();
}
$id = $row['id'];
//And the command to enter the item:
$itemNum = $_POST['item_number'];
$qty = $_POST['quantity'];
$info = $_POST['option_selection1'];
$cmd = "Insert into orderItems (orderNumber, item, quantity, extraInfo) " .
"values('$id', '$itemNum', '$qty', '$info')";
$this->loggerC->log("Inserting into order items:$nl$cmd$nl");
$this->tellDb($cmd);
}
}
?>
太好了!接下来的类要比前面的小得多!第一个是邮件类。当然,它的简洁可能与它还可以进一步完善有关,我应该向购买者发送比现在格式更好的 HTML 响应。一切都会在适当的时候实现的。
<?php
require_once(BASE_PATH . "pp_hiddenPasswords.php");
require_once(BASE_PATH . "phpLoggerClass.php");
require_once(BASE_PATH . "lib/swift_required.php");
class myMailer {
private $myEmail;
private $logger; //This will actually be a reference;
//see 'setLogger' for mechanism which accomplishes this.
function __construct() {
$this->myEmail = "someone@somewhere.com";
}
function setLogger(myLogger &$logFile) { $this->logger = $logFile; }
function sendEbook($ebookType, $mailTo) {
//You can either send a link to the product or a file. The choice is yours.
//Refer to swift mailer documentation, and other online resources for the appropriate
//steps to take for each option. If you want to send a file, the 'mailWithAttachments'
//routine may be useful. The usage of it is:
...
$this->mailWithAttachment($fileName, BASE_PATH, $mailTo, $this->myEmail, $from,
$replyTo, $subject, $msg);
}
private function mailWithAttachment($filename, $path, $mailTo, $from_mail, $from_name,
$replyto, $subject, $message) {
$transport = Swift_SmtpTransport::newInstance('mail.some_server.com', 465, 'ssl')
->setUsername(hiddenEmailAccount())
->setPassword(hiddenEmailPassword())
;
$mailer = Swift_Mailer::newInstance($transport);
$message = Swift_Message::newInstance()
->setSubject($subject)
->setFrom(array($from_mail => $from_name))
->setTo(array($mailTo))
->setBody($message)
//->addPart('<p>Here is the message itself</p>', 'text/html')
->attach(Swift_Attachment::fromPath($path.$filename))
;
$this->logger->forceLog(date('F jS\, Y h:i:s A') . ": Sending " . $filename .
" to " . $mailTo . ": ");
$result = $mailer->send($message);
$this->logger->forceLog("Result = " . $result . PHP_EOL);
}
}
?>
最后是日志类
<?php
class myLogger {
private $fileNameC;
private $doLoggingC;
function __construct() {
$this->fileNameC = "log.txt";
$this->doLoggingC = true;
}
function setLogFile($fileName) { $this->fileNameC = $fileName; }
function setLogging($state) { $this->doLoggingC = $state; }
function log($msg) {
if ($this->doLoggingC == true) {
file_put_contents($this->fileNameC, $msg, FILE_APPEND);
}
}
function forceLog($msg) {
file_put_contents($this->fileNameC, $msg, FILE_APPEND);
}
}
?>
但仍然需要两个文件,尽管您也可以将它们合并为一个文件,并进行相应的修改。它们用于存储数据库信息和电子邮件信息。同样,这些文件不应暴露给外部世界至关重要,并且必须放置在站点最顶层可见文件夹的下方。
db_config.php 文件的内容如下。但那些不是真实的用户名、密码和数据库!
<?php
// Connection Parameters
$db_con = mysql_connect("localhost", "theUser", "thePassword", true) or die(mysql_error());
$db_selected = mysql_select_db("theDatabase") or die(mysql_error());
?>
最后是电子邮件密码文件(上面代码中的“emailPassword.php”),同样需要注意
<?php
// Connection Parameters
function hiddenEmailAccount() {
return "someone@somewhere.com";
}
function hiddenEmailPassword() {
return "thePassword";
}
?>
我希望以上信息对您有帮助,即使您不采用这种方法。感谢您的阅读,祝您编码愉快!如果您有任何改进,请在评论中发布。