我有一个PHPMailer表单,我正在使用.ajax使用这个SO答案jquery-ajax-post-example-with-php
它成功发送或不发送,所以我知道Mailer和验证码正在工作。现在,如果我可以获得成功的不同行为并且失败,那将是很好的,但我不会以某种方式得到这个权利。
首选行为
成功 - >重新加载屏幕并显示bootstrap模态并成功msg
失败 - >重新加载屏幕并显示带有失败消息的引导模式
我有很多代码,所以,尽可能将模态视为vanilla,而PHPMailer实际上也是发送的。我遇到的问题应该在下面的代码中,但是如果你还有别的东西,那就问问吧。尽量将问题尽可能地整理
<script type="text/javascript">
$(document).ready(function() {
var request;
$("#contactForm").submit(function(event){
event.preventDefault();
// Abort any pending request
if (request) {
request.abort();
}
// setup some local variables
var $form = $(this);
// Let's select and cache all the fields
var $inputs = $form.find("input, select, button, textarea");
// Serialize the data in the form
var serializedData = $form.serialize();
// Let's disable the inputs for the duration of the Ajax request.
// Note: we disable elements AFTER the form data has been serialized.
// Disabled form elements will not be serialized.
$inputs.prop("disabled", true);
request = $.ajax({
url: "processLogin.php",
type: "post",
data: serializedData
});
// Callback handler that will be called on success
request.done(function (response, textStatus, jqXHR){
if (response == true ) {
top.location.reload();
// top.location.href="/";
// $('#successEmail').modal('show');
} else {
// top.location.reload();
$('#failEmail').modal('show');
}
});
// Callback handler that will be called on failure
request.fail(function (jqXHR, textStatus, errorThrown){
// Log the error to the console
// console.error(
// "The following error occurred: "+
// textStatus, errorThrown
// );
// top.location.reload();
});
// Callback handler that will be called regardless
// if the request failed or succeeded
request.always(function () {
// Reenable the inputs
$inputs.prop("disabled", false);
});
});
});
</script>
PHPMailer表单
<?php
session_start();
?>
<?php
/**
* This example shows how to handle a simple contact form.
*/
$msg = '';
use PHPMailer\PHPMailer\PHPMailer;
require './mail/PHPMailer.php';
require './mail/Exception.php';
require './mail/SMTP.php';
require './mail/PHPMailerAutoload.php';
include_once $_SERVER['DOCUMENT_ROOT'] . '/securimage/securimage.php';
$securimage = new Securimage();
//Don't run this unless we're handling a form submission
if (array_key_exists('email', $_POST)) {
date_default_timezone_set('Etc/UTC');
//Create a new PHPMailer instance
$mail = new PHPMailer;
$mail->SMTPDebug = 0;
$mail->isSMTP();
$mail->Host = 'smtp.live.com';
$mail->SMTPAuth = true;
$mail->Username = 'email@outlook.com';
$mail->Password = 'password';
$mail->SMTPSecure = 'tls';
$mail->Port = 587;
$mail->setFrom('email@outlook.com', 'Mailer');
$mail->addAddress('email@outlook.com', 'First Last');
$email = isset($_POST['email']) ? $_POST['email'] : null;
$name = isset($_POST['name']) ? $_POST['name'] : null;
$phone = isset($_POST['phone']) ? $_POST['phone'] : null;
$message = isset($_POST['message']) ? $_POST['message'] : null;
if ($mail->addReplyTo($_POST['email'], $_POST['name'])) {
$mail->Subject = 'Contact request';
$mail->isHTML(true);
$mail->Body = <<<EOT
<div style="width:100%">
<div><label style="color: #044F69; font-weight:bold">Email:</label> <span>{$_POST['email']}</span></div>
<div><label style="color: #044F69; font-weight:bold">Name:</label> <span>{$_POST['name']}</span></div>
<div><label style="color: #044F69; font-weight:bold">Phone:</label> <span>{$_POST['phone']}</span></div>
<div><label style="color: #044F69; font-weight:bold">Message:</label> <span>{$_POST['message']}</span></div>
</div>
EOT;
if ($securimage->check($_POST['captcha_code']) == false) {
// echo "<meta http-equiv='refresh' content='0'>";
exit;
}
//Send the message, check for errors
if (!$mail->send()) {
$msg = 'Sorry, something went wrong. Please try again later.';
} else {
header("Location: /");
exit;
}
} else {
$msg = 'Invalid email address, message ignored.';
}
}
?>
P.S。我拥有的代码(见上文)显示了失败模式,无论是否通过都没有重新加载。
提前致谢!
答案 0 :(得分:2)
你选择了一个相对困难的例子来学习。成功/失败后重新加载意味着您需要引入会话或cookie或URL参数来跟踪请求之间的状态。您需要有几个移动部件才能正确运行。你必须有理由这样做,但如果你能在没有重新加载的情况下逃脱,它可以简化事情并且可能会提供更好的用户体验。我在下面列出了两个选项的信息。
首先,PHP。您有几种可能的退出状态,具体取决于电子邮件是否已成功发送等,但处理方式不一致。在一种情况下,它会进行重定向,在某些情况下会以静默方式退出。所有案件都应保持一致;对PHP页面的请求应该生成一个响应,无论发生什么,并且理想地将该响应传递回您的调用Javascript,以便它可以对发生的任何事情采取行动。
看起来你已经开始设置了它,但没有完成它 - 你准备了一个$msg
,其中包含有关发生的事情的信息,但是从未显示过,$msg
完全从几个退出案例(特别是成功案例和看起来像CAPTCHA失败的事件)。
除了$msg
之外,我还会添加一个status
标记,以便JS可以轻松判断请求是否成功;既然你在JS中读到了这个响应,我会把它变成JSON。
请注意,由于您希望在成功/失败两种情况下重新加载页面,严格来说JSON响应并不是必需的,但我认为这是一种很好的做法,有助于在开发过程中进行调试。
为确保每个退出条件生成标准响应,我必须将实际邮件发送代码嵌套在CAPTCHA测试中。这个IMO有点混乱,我个人会重构一下returning early,以便更简单地测试各种条件,因此最终不会有3-4个嵌套测试。例如,不是将所有内容嵌套在array_key_exists('email', $_POST)
测试中,而是测试反向(如果没有电子邮件值),如果失败则立即退出。
// Don't run this unless we're handling a form submission
if (!array_key_exists('email', $_POST)) {
// Generate response and bail out!
echo $some_response_or_whatever;
die();
}
我还建议重新考虑一下流程,例如,如果CAPTCHA失败,你真的想重新加载只是为了表明错误吗?你正在破坏使用AJAX的一个细节 - 无需重新加载即可获得响应。也许如果某些内容失败,您只需在用户点击提交的表单上显示错误消息?如果成功,你打开你的模态,如果真的有必要重新加载。
我在下面所做的更改摘要:
将$mail->send()
嵌套在CAPTCHA条件中;
为CAPTCHA失败创建一个包含相应消息的$response
;
为成功案例创建$response
;
为所有回复添加status
标记;
将$response
添加到会话中,以便在页面重新加载后可用;
最后,将响应作为JSON回应,以便调用AJAX可以判断发生了什么。
这是更新的,缩写的(我删除了大块未更改的代码)代码:
<?php
session_start();
// ... your code
//Don't run this unless we're handling a form submission
if (array_key_exists('email', $_POST)) {
// ... your code
if ($mail->addReplyTo($_POST['email'], $_POST['name'])) {
// ... your code
if ($securimage->check($_POST['captcha_code']) == false) {
// Generate a response in this failure case, including a message and a status flag
$response = [
'status'=> 1,
'msg' => 'CAPTCHA test failed!'
];
} else {
//Send the message, check for errors
if (!$mail->send()) {
// Generate a response in this failure case, including a message and a status flag
$response = [
'status'=> 1,
'msg' => 'Sorry, something went wrong. Please try again later.'
];
} else {
// Generate a response in the success case, including a message and a status flag
$response = [
'status'=> 0,
'msg' => 'Success!'
];
}
}
} else {
// Generate a response in this failure case, including a message and a status flag
$response = [
'status'=> 1,
'msg' => 'Invalid email address, message ignored.'
];
}
}
// Add the response to the session, so that it will be available after reload
$_SESSION['response'] = $response;
// Finally display the response as JSON so calling JS can see what happened
header('Content-Type: application/json');
echo json_encode($response);
?>
接下来,你的Javascript。由于您希望在成功和失败的情况下重新加载页面,因此您不需要测试响应。
request.done(function (response, textStatus, jqXHR){
// You could test the response here, but since both success and failure
// should reload, there is no point.
window.location.reload();
// If you did want to test response and act on it, here's how to do that:
/*
if (response.status == 0) {
// Success! Do something successful, like show success modal
$('#successEmail').modal('show');
} else {
// Oh no, failure - notify the user
$('.message').html(response.msg);
}
*/
});
您在说明中没有提及fail
案例中会发生什么。请注意,当请求失败时会触发fail
回调,例如404或超时或类似情况,而不会触发您的某个故障情况(如无效电子邮件)。在这种情况下,我只是在前端生成一个msg,而不重新加载:
request.fail(function (jqXHR, textStatus, errorThrown){
// Say you have a <div class="message"></div> somewhere, maybe under your form
$('.message').html('Error: ' + textStatus + ', ' + errorThrown)
});
所以,现在你的PHP已经触发,设置一个会话变量并返回,你的JS重新加载了页面。您需要测试会话变量的内容,并相应地触发一些JS。在您的前端页面上,在现有$(document).ready( ...
内:
<script>
$(document).ready(function() {
var request;
// ... your code
<?php
// New PHP/JS to handle what happens when the page reloads
if (isset($_SESSION['response'])) {
if ($_SESSION['response']['status'] == 0) { ?>
// Success!
$('#successEmail').modal('show');
<?php } else { ?>
$('#failEmail').modal('show');
<?php }
// In both cases we need to clear the response so next reload does not
// fire a modal again
unset($_SESSION['response']);
} ?>
});
</script>
您可以使用$_SESSION['response']['msg']
访问模式中的成功/失败消息的内容。
另一个建议 - 如果您的成功和失败模式类似,您只能使用一个,并使用Javascript更新其内容。
<script>
<?php if (isset($_SESSION['response'])) { ?>
// First add the message to the modal, assuming you have a
// <div class="message"></div> in your modal
$('#modal .message').html('<?php echo $_SESSION['response']['msg']; ?>');
// Now open the one modal to rule them all
$('#modal').modal('show');
<?php
unset($_SESSION['response']);
} ?>
</script>
旁注 - 我不确定你的Abort any pending request
是否真的按照自己的意愿行事。 request
在文档就绪时声明,因此它总是存在,AFAICT?
答案 1 :(得分:0)
您完成的回调函数应仅反映成功条件,而失败应反映替代方案。
// Callback handler that will be called on success
request.done(function(response, textStatus, jqXHR) {
$('#successEmail').modal('show');
});
// Callback handler that will be called on failure
request.fail(function(jqXHR, textStatus, errorThrown) {
// Log the error to the console
// console.error(
// "The following error occurred: "+
// textStatus, errorThrown
// );
$("#failEmail").modal("show");
});
正如你的问题所提供/描述的那样,重新加载页面会阻止脚本显示模态 - 如果你需要重新加载,你应该存储一个localStorage变量或cookie并在页面加载时测试它的值以显示模态为必要的。
答案 2 :(得分:0)
我在相当长一段时间内没有完成PHP,但我相信下面的代码可以解决您的问题。以下是我将您的PHP代码更改为:
<?php
$messageSent = true;
try {
$mail -> send();
}
catch (Exception $e) {
$messageSent = false
}
$response = array('success' => $messageSent);
echo json_encode($response)
现在在你的jQuery代码中,使用$ .always()回调而不是成功:
request.always(function (data) {
if (data.success) {
// success handler
} else {
// error handler
}
});
在您的代码中,您有以下PHP:
if (!$mail->send()) {}
我不认为该行会执行。您假设$ mail-&gt; send()如果消息未发送则返回false。我不认为是这种情况。如果您查看PHP邮件程序主页上使用的示例:https://github.com/PHPMailer/PHPMailer作者使用try / catch。这告诉我,如果消息无法发送,PHPMailer会抛出异常,如果未捕获将传播500错误。我相信你的PHPMailer设置没有抛出任何异常(还),这就是为什么总是调用你的Ajax成功处理程序。但是,在javascript的以下行中:if (response == true ) {
您错误地认为发送到成功处理程序的第一个参数是boolean(true或false)。它不是(尽管我们可以这样做)。因此,(response == true)
永远不会评估为真。
我在代码中所做的是使用像PHPMailer示例那样的try / catch。这样,如果PHPMailer失败,你的后端不会抛出500错误。但是,如果执行catch子句,我将布尔标志设置为false。这使我们能够知道在没有实际发生后端崩溃的情况下发生了故障。现在我们只需使用名为success的键创建一个JSON对象。如果消息已成功发送,则为true;如果不成功,则为false。现在我们可以将它返回到前端。
由于我们在后端捕获任何可能的异常,因此前端将始终收到HTTP 200状态代码(好的)。因此,使用.success()
或.error()
没有任何意义,因为jQuery不会基于HTTP代码知道我们是成功还是失败。相反,我们使用.always()
回调并检查返回的JSON对象的值以确定成功或错误。现在我们可以简单地使用.always()
处理程序中的if语句来执行成功代码(&#34; if&#34;)或错误代码(&#34; else&#34;)。您希望在显示或隐藏模态等方面做的任何事情都可以在前端的JavaScript中完成,这是代码所属的位置。
我希望这会有所帮助。