I need help in my code, I'm trying to send a FormData from Angular to PHP and later send a mail, always appears the PHP vars empty, I'm doing something wrong and doesn't see what
On the HTML use formGroup and ngSubmit
My HTML code:
<form [formGroup]="form"
(ngSubmit)="onSubmit()">
<div class="form-boxes">
<div class="row">
<div class="col-12 col-md-6">
<div class="form-floating mb-3">
<input type="text"
class="form-control"
id="name"
formControlName="name"
placeholder="Name"
required>
<label for="name">Name</label>
<div *ngIf="showErrorMessages && name.invalid"
class="text-end text-danger my-1">
You must fill the name
</div>
</div>
</div>
<div class="text-center">
<input [disabled]="isLoading"
class="btn btn-page"
type="submit"
value="Send">
</div>
<input [formControl]="honeypot"
class="d-none"
type="text" />
</form>
</div>
On the Ts use the FormControl Validators and the http.post to pass the data to PHP
My .ts code:
export class ContactComponent
implements OnInit
{
form: FormGroup;
name: FormControl = new FormControl("", [Validators.required]);
showErrorMessages: boolean = false; // flag to show error messages
submitted: boolean = false; // show and hide the success message
honeypot: FormControl = new FormControl(""); // we will use this to prevent spam
isLoading: boolean = false; // disable the submit button if we're loading
responseTitle: string = ''; // the response title message to show to the user
responseMessage: string = ''; // the response message to show to the user
serverUrl: string = "./assets/scripts/mailer.php" //Start php via the built in server
constructor(
private formBuilder: FormBuilder,
private http: HttpClient
)
{
this.form = this.formBuilder.group({
name: this.name,
honeypot: this.honeypot
});
}
ngOnInit(): void
{
}
onSubmit()
{
if (this.form.status == "VALID" && this.honeypot.value == "")
{
this.form.disable(); // disable the form if it's valid to disable multiple submissions
var formData: any = new FormData();
formData.append("name", this.name.value);
this.isLoading = true; // sending the post request async so it's in progress
this.submitted = false; // hide the response message on multiple submits
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
};
this.http.post(this.serverUrl, formData, httpOptions).subscribe(
(response) =>
{
this.responseTitle = "Thanks!";
this.responseMessage = "Thanks for send a message";
this.form.enable(); // re enable the form after a success
this.submitted = true; // show the response message
this.isLoading = false; // re enable the submit button
Swal.fire({
title: this.responseTitle,
text: this.responseMessage,
icon: 'success'
});
},
(error) =>
{
this.responseTitle = "Sorry!";
this.responseMessage = "Some issues happens";
this.form.enable(); // re enable the form after a success
this.submitted = true; // show the response message
this.isLoading = false; // re enable the submit button
Swal.fire({
title: this.responseTitle,
text: this.responseMessage,
icon: 'error'
});
}
);
} else
{
this.showErrorMessages = true;
this.responseTitle = "Sorry!";
this.responseMessage = "Some issues happens";
Swal.fire({
title: this.responseTitle,
text: this.responseMessage,
icon: 'error'
});
}
}
}
On tje PHP retrieve the JSON from Angular with this
$postdata = file_get_contents("php://input");
$request = json_decode($postdata);
My PHP code:
<?php
$postdata = file_get_contents("php://input");
$request = json_decode($postdata);
$name = $request->name;
$to = "example#mail.com";
$title = "From: $name";
$body = "test";
$body = wordwrap($body, 70);
$header = "MIME-Version: 1.0\r\n";
$header.= "Content-Type: text/plain; charset=utf-8\r\n";
$header.= "X-Priority: 1\r\n";
mail($to, $title, $body, $header);
?>
You don't need FormData to send JSON to your API. Even if you force the content type to application/json, I'm not sure it will be properly formatted.
Plain JavaScript objects can be sent as JSON using the angular HTTP client. To do so, pass a plain object to the post method:
this.http.post(this.serverUrl, this.name.value, httpOptions)
Related
i have two rest api end points for the Calculator and another for the email submission.
i want to include the data from calculator to the email handler function.
Calculator Handler:
// function for the endpoint for form
add_action('rest_api_init', 'create_rest_endpoint');
function create_rest_endpoint() {
// Create endpoint for front end to connect to WordPress securely to post form data
register_rest_route('bohio/v1', 'submit', array(
'methods' => 'POST',
'callback' => 'handle_query',
'permission_callback' => '__return_true'
));
}
// callback method
function handle_query($data) {
// Handle the form data that is posted
// Get all parameters from form
$output = $data->get_params();
// form fields : service, bed, bath,square_feet,cadence
}
Email handler:
function handle_email($data) {
// Handle the form data that is posted
// Get all parameters from form
$emailData = $data->get_params();
// Set fields from the form
$field_name = sanitize_text_field($emailData['name']);
$field_email = sanitize_email($emailData['email']);
//Check if nonce is valid, if not, respond back with error
if (!wp_verify_nonce($emailData['_wpnonce'], 'wp_rest')) {
return new WP_Rest_Response('Message not sent', 422);
}
else {
// Remove unneeded data from paramaters
unset($emailData['_wpnonce']);
unset($emailData['_wp_http_referer']);
// Send the email message
$headers = [];
// $admin_email = get_bloginfo('admin_email');
$admin_email = get_option('bh_email_sub');
// var_dump($admin_email);
$from_email = get_option('bh_email_sub');
$admin_name = get_option('bh_admin_sub_name');
// $admin_name = get_bloginfo('name');
// Set admin email as recipient email if no option has been set
$recipient_email = $admin_email;
$headers[] = "From: {$admin_name} <{$from_email}>";
$headers[] = "Reply-to: {$field_name} <{$field_email}>";
$headers[] = "Content-Type: text/html";
$subject = "New email submission from {$field_name}";
$message = '';
$message = "<h2>New Email submission from {$field_name}</h2>";
// Loop through each field posted and sanitize it
foreach ($emailData as $label => $value) {
switch ($label) {
case 'message':
$value = sanitize_textarea_field($value);
break;
case 'email':
$value = sanitize_email($value);
break;
default:
$value = sanitize_text_field($value);
}
$message .= '<strong>' . sanitize_text_field(ucfirst($label)) . ':</strong> ' . $value . '<br />';
}
wp_mail($recipient_email, $subject, $message, $headers);
$confirmation_message = "The message was sent successfully!!";
// return $confirmation_message;
return $confirmation_message;
}
}
How would i access the data from handle_query to handle_email and send via email. Both functions lies in the same file of a plugin.
I've made a contact form for a website that works - so well that bots spam the company using it. Not good.
I've looked into adding a google recaptcha validation system.
I've succesfully added the widget to the website as well as gone so far as:
Website returns an error to the user if captcha isn't verified when they click submit.
Website shows correct affirmation message when captcha is verified and they press submit.
So far so good.
The issue:
The form sends regardless of the captcha. So regardless if it actually shows the error to the user about the captcha being verified or not, it still submits the message - ultimately making this bot stopping recaptcha worthless. It looks nice... but is it really? Not yet.
I suspect it's the .js validation script I have that does this. I've tried a few things like changing order of code around etc, but my newbie status really makes it hard and I'm close to giving up.
My form uses php, ajax for instant verification if form is sent, js and the good old html and css.
.PHP:
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require 'vendor/autoload.php';
$firstname = ($_POST['firstname']);
$lastname = ($_POST['lastname']);
$phone = ($_POST['phone']);
$email = ($_POST['email']);
$message = ($_POST['message']);
$msg = ($_POST['msg']);
$okMessage = ' SUCCESS ';
$errorMessage = ' ERROR';
$secretKey = " EXAMPLE ";
$responseKey = $_POST['g-recaptcha-response'];
$userIP = $_SERVER['REMOTE_ADDR'];
$mail = new PHPMailer(true);
try {
$mail->SMTPDebug = 0;
$mail->isSMTP();
$mail->Host = ' EXAMPLE ';
$mail->SMTPAuth = true;
$mail->Username = ' EXAMPLE ';
$mail->Password = ' EXAMPLE ';
$mail->SMTPSecure = 'ssl';
$mail->Port = 465;
$mail->WordWrap = 50;
$mail->Priority = 1;
$mail->CharSet = 'utf-8';
$mail->setFrom(' EXAMPLE ', ' EXAMPLE ');
$mail->addAddress(' EXAMPLE ');
$mail->addReplyTo($email);
$mail->isHTML(true);
$url = "https://www.google.com/recaptcha/api/siteverify?secret=$secretKey&response=$responseKey&remoteip=$userIP";
$response = file_get_contents($url);
$response = json_decode($response);
$mail->Subject = 'NY BESKED - EXAMPLE';
$mail->Body = (' EXAMPLE ');
$mail->AltBody = (' EXAMPLE ');
if (!$mail->send() || !$response->success) {
throw new \Exception('ERROR TRY AGAIN' . $mail->ErrorInfo);
} else {
$responseArray = array('type' => 'success', 'message' => $okMessage);
}
} catch (\Exception $e) {
$responseArray = array('type' => 'danger', 'message' => $e->getMessage());
}
if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
$encoded = json_encode($responseArray);
header('Content-Type: application/json');
echo $encoded;
} else {
echo $responseArray['message'];
}
JS PART:
$(function ValidateEmailForm() {
window.verifyRecaptchaCallback = function (response) {
$('input[data-recaptcha]').val(response).trigger('change')
};
window.expiredRecaptchaCallback = function () {
$('input[data-recaptcha]').val("").trigger('change')
};
$('#contact-form').validator();
$('#contact-form').on('submit', function (e) {
if (!e.isDefaultPrevented()) {
var url = "contact.php";
$.ajax({
type: "POST",
url: url,
data: $(this).serialize(),
success: function (data) {
var messageAlert = 'alert-' + data.type;
var messageText = data.message;
var alertBox = '<div class="alert ' + messageAlert + ' alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' + messageText + '</div>';
if (messageAlert && messageText) {
$('#contact-form').find('.messages').html(alertBox);
$('#contact-form')[0].reset();
grecaptcha.reset();
}
}
});
return false;
}
});
});
and the HTML part:
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<div class="col-12 d-flex justify-content-center">
<div class="g-recaptcha" data-sitekey="6Lf80bUUAAAAADrnadBM_GYs0PY8p4QqP7ol45ac"></div>
</div>
What's the issue here? Thank you in advance!
Your conditions are backwards. You should check the captcha first:
if (!$response->success || !$mail->send()) {
I have implemented Google reCaptcha on a site, for the newsletter subscription form, and it does not stop spam. I got up to 20 spam subscribers per day!
What am I not doing correct? Please have a look at the code:
HTML
<form method="post" action="databasepage.php" id="formid" >
<div id="g-recaptcha-answer"></div>
<input name="email" placeholder="Email..." type="email" required>
<button class="g-recaptcha" data-sitekey="my_key" data-callback='onReturnCallback'>Submit</button>
</form>
jQuery
<script>
var onReturnCallback = function(response) {
document.getElementById('g-recaptcha-answer').innerHTML = '';
var url='proxy.php?url=' + 'https://www.google.com/recaptcha/api/siteverify';
$.ajax({ 'url' : url,
dataType: 'json',
data: { response: response },
success: function( data ) {
var res = data.success.toString();
if (res == 'true') {
document.getElementById('g-recaptcha-answer').innerHTML = 'Please wait for a redirect.';
document.getElementById("formid").submit();
}
else {
document.getElementById('g-recaptcha-answer').innerHTML = 'Verification incorrect.';
grecaptcha.reset();
}
}
});
};
</script>
proxy.php
<?php
if (!isset($_SERVER['HTTP_X_REQUESTED_WITH'])) {
header('HTTP/1.0 403 Forbidden');
die('You are not allowed to access this file.');
}
header('Content-type: application/json');
$url=$_GET['url'];
$response=$_GET['response'];
$secret = "secret_key";
$params = array('secret'=> $secret, 'response'=> $response);
$json=file_get_contents( $url . '?secret=' . $secret . '&response=' . $response);
echo $json;
?>
I have tested this with Incognito Mode, I get the step when I have to verify pictures, if I am not logged in Gmail etc., in reCaptcha admin area I have no errors, but I STILL RECEIVE SPAM EMAILS IN MY DATABASE!!!
What is wrong in my approach?
I have a form to call ajax for back-end processing, all input will stored in table and will return 'success' to to notify user the submission is success. But I facing an issue during callback, input data can saved into table but the callback is halted with error below, I have no idea what is goes wrong, the same script was applied to another form (with different form field) are working fine.
console log - Chrome:
Uncaught TypeError: Cannot read property 'length' of undefined
m.extend.each
$.ajax.success
j
k.fireWith
x
b
Firefox
TypeError: a is undefined
...rCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e...
firefox error is pointed to f=a.
Script:
$(document).ready(function() {
$("#status").hide();
$('#btn_submit').click(function(){
var params = $('#project_form').serialize();
var btn = $(this);
btn.button('loading')
$.ajax({
url: baseurl + '/process_form.php',
type: 'POST',
data: params,
dataType: 'json',
success: function(response){
if(response.success == 'success'){
$('#status').html('<b>Thank you</b>').show();
$('html,body').animate({
scrollTop: $('#top').offset().top
},500);
}else{
$('[id$="_error"]').html('');
$.each(response.error, function(key, value){
if(value){
$('#' + key + '_error').html(value);
}
});
}
},
error: function(){
console.log(arguments);
}
}).always(function(){
btn.button('reset')
});
});
});
process_form.php
header("Content-Type: application/json");
$serialized_data = serialize($_POST);
$fullname = $mysqli->real_escape_string(ucwords(strtolower($_POST['fullname'])));
$age = $mysqli->real_escape_string(ucwords(strtolower($_POST['age'])));
$email = $mysqli->real_escape_string(strtolower(trim($_POST['semail'])));
$phone = $mysqli->real_escape_string(trim($_POST['phone']));
$proj_id = preg_replace('/[^0-9]/', '', $mysqli->real_escape_string($_POST['project_id']));
$proj_name = $mysqli->real_escape_string(ucwords(strtolower($_POST['project_name'])));
$agent_id = preg_replace('/[^0-9]/', '', $mysqli->real_escape_string($_POST['agent_id']));
$agent_email = $mysqli->real_escape_string(strtolower(trim($_POST['agent_email'])));
$agent_name = $mysqli->real_escape_string(ucwords(strtolower($_POST['agent_name'])));
$captcha = $_POST['captcha_code'];
$func = new Functions();
$message = array();
// validate
if(empty($fullname) || strlen($fullname) < 2){
$message['error']['fullname'] = 'Your name is required';
}
if(empty($age)){
$message['error']['age'] = 'Your age is required';
}
if(!$func->check_email_address($email)){
$message['error']['semail'] = 'Invalid email address';
}
if(empty($phone) || strlen($phone) < 10){
$message['error']['phone'] = 'Phone num is required';
}
$securimage = new Securimage();
$securecode = $securimage->getCode();
if(strtolower($securecode) != strtolower($captcha)) {
$message['error']['captcha'] = 'Incorrect security code';
}
if(!isset($message['error'])){
// insert table
$create = $mysqli->query("INSERT INTO `xxx` ...") or die($mysqli->error);
if($create){
//send email
$to = xxx;
$subject = 'yyy';
$msg = '<html>
<body>
blah...
</body>
</html>';
$from = zzz;
$headers = 'MIME-Version: 1.0' . "\r\n";
$headers .= 'Content-type: text/html; charset=UTF-8' . "\r\n";
$headers .= 'From: '.$fullname.' <'.$from.'>' . "\r\n";
if(mail($to, $subject, $msg, $headers)){
$message['success'] = 'success';
}
}
}
echo json_encode($message);
change this:
if(response.success == 'success'){
to this:
if(response[0].success == 'success'){
What seems to me, you have an array of object [{}] so response.success is not available that way, instead you can pass the index like suggested in the answer above response[0].success.
I think it is because the mail function failed, and returned false here:
if(mail($to, $subject, $msg, $headers)){
$message['success'] = 'success';
}
so your response neither has success property, nor error property, and this causes an error here:
$.each(response.error, function(key, value){
if(value){
$('#' + key + '_error').html(value);
}
});
You can try something like:
if(mail($to, $subject, $msg, $headers)){
$message['success'] = 'success';
}else{
$message['error']['mail'] = 'Mail error!';
}
or set $message['success'] = 'success'; directly after saving data into table regardless mail success.
I am trying to retrieve data from AngularJS file to PHP file, but I get the error that it's empty.
I can't find any good examples that are dealing with posting data from angularJS to php file and so I need help.
Angularjs file:
angular.module('myApp', ['ajoslin.promise-tracker'])
.controller('help', function ($scope, $http, $log, promiseTracker, $timeout) {
$scope.ph_numbr =/[0-9]+/;
// Form submit handler.
$scope.submit = function(form) {
// Trigger validation flag.
$scope.submitted = true;
// If form is invalid, return and let AngularJS show validation errors.
if (!$scope.toggle || $scope.toggle.length <= 0 || form.$invalid) {
return;
}
// Default values for the request.
$scope.progress = promiseTracker('progress');
var config = {
params : {
//'callback' : 'JSON_CALLBACK',
'name' : $scope.name,
'email' : $scope.email,
'toggle' : $scope.toggle,
'phone' : $scope.phone,
'comments' : $scope.comments
},
tracker : 'progress'
};
$http({
method : 'POST',
url : 'js/contact.php',
data: config,
headers : {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
})
.success(function(data, status, headers, config) {
if (data.success) {
$scope.name = null;
$scope.email = null;
$scope.toggle = null;
$scope.phone = null;
$scope.comments = null;
$scope.messages = 'Your form has been sent!';
$scope.submitted = false;
} else {
$scope.messages = 'Oops, we received your request, but there was an error processing it.';
$log.error(data);
}
})
.error(function(data, status, headers, config) {
$scope.progress = data;
$scope.messages = 'There was a network error. Try again later.';
$log.error(data);
});
// Hide the status message which was set above after 3 seconds.
var promise = $timeout(function() {
$scope.messages = null;
}, 3000);
$scope.progress.addPromise(promise);
};
});
php file:
<?php
/*error_reporting(E_ALL);
ini_set('display_errors', '1');
require_once 'js/PHPMailerAutoload.php';*/
ini_set('display_errors', 'On');
error_reporting(E_ALL | E_STRICT);
$data = file_get_contents("php://input");
$postData = json_decode($data);
if (isset($_POST['name']) && isset($_POST['email']) && isset($_POST['toggle']) && isset($_POST['comments'])) {
//check if any of the inputs are empty
if (empty($_POST['name']) || empty($_POST['email']) || empty($_POST['toggle']) || empty($_POST['comments'])) {
$data = array('success' => false, 'message' => 'Please fill out the form completely.');
echo json_encode($data);
exit;
}
$email = trim($_POST['email']);
$subject = trim($_POST['toggle']);
//email address settings
$my_address = "*#yahoo.com";
$headers = "From: ".$email;
$message = "Name: " . $_POST['name'] . "\r\n\r\nMessage: " . $_POST["phone"] . "\r\n\r\nMessage: " . stripslashes($_POST['comments']);
$to = $my_address;
if (isset($_POST['ref'])) {
$mail->Body .= "\r\n\r\nRef: " . $_POST['ref'];
}
if(!$mail->send()) {
$data = array('success' => false, 'message' => 'Message could not be sent. Mailer Error: ' . $mail->ErrorInfo);
echo json_encode($data);
exit;
}
mail($to, $subject, $message, $headers);
$data = array('success' => true, 'message' => 'Thanks! We have received your message.');
echo json_encode($data);
} else {
$data = array('success' => false, 'message' => 'Please fill out the form completely.');
echo json_encode($data);
}
?>
The error message that I get is: "Please fill out the form completely" - which means it doesn't get the values.
My other question is how in the AngularJS do I retrieve the data.success value from the php file?
You seem to be getting the data here:
$data = file_get_contents("php://input");
$postData = json_decode($data);
but then you're using $_POST instead. Perhaps this would work:
if (empty($postData['name']) //etc
It looks like you're accessing data.success appropriately and the value should be set to false as your code currently is.
Additional code review:
If there are errors on the server, it's best to return a status code that indicates that. As is, the server is returning 200 (default), which means everything is OK, even though the request is actually failing. That would eliminate the need for data.success. If the server sends status 200, your .success function will fire. If it returns an error status, like 404, then your .error function would fire instead.
I have doubts about your need of the Content-Type header. You might want to reconsider if that's necessary.
On your Angular form, you ought to nest those $scope properties in an object:
$scope.formData = {
name: '',
email: '',
//etc
}
Then, you can simply pass that directly to your $http call and to reset the values you can simply do $scope.formData = {}.