Introduction
In the previous articles, we've seen how to design a website using Gatsby, a React-based framework. We've focused on the visual aspect of the project, that is the front end, leaving aside what concerns the processing aspect, namely the back end. In this article, we'll see how to use PHP to create a REST service for sending an email and how to invoke it from a React component, specifically from a page that will allow sending messages.
Prerequisites
To invoke a REST service, we can use the
Axios library which greatly facilitates these types of calls. To install the library, run this command:
Creating the Contacts Page
Let's start by writing the code for the new page that will be used to send a message to the site owner or administrator. Inside the
pages directory, let's create two files:
- - contacts.js: this is the page through which to send the message;
- - contacts.module.scss: this is the file with the stylesheets.
In the
contacts.js file, let's insert the code to define the page for sending information requests:
import React, { Component } from 'react';
import Layout from '../components/layout'
import axios from 'axios';
import * as styles from "./contacts.module.scss"
// ATTENTION:
// the value of this constant must be modified to correspond
// to the directory where the PHP script for the REST service will be placed
const API_PATH = 'http://localhost:8000/api/index.php';
class Contacts extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
email: '',
subject: '',
message: '',
mailSent: false,
error: null
}
}
handleFormSubmit(event) {
event.preventDefault();
axios({
method: 'post',
url: `${API_PATH}`,
headers: { 'content-type': 'application/json' },
data: this.state
})
.then(result => {
this.setState({
mailSent: result.data.sent
})
})
.catch(error => {
this.setState({ error: error.message })
});
}
render() {
return (
<Layout>
<div className={styles.contacts}>
<form action="#">
<div className={styles.settings}>
<label className={styles.form} htmlFor="name">
Name:
</label>
<input className={styles.form} type="text" name="name" id="name"
value={this.state.name}
onChange={e => this.setState({ name: e.target.value })}
/>
<label className={styles.form} htmlFor="email">
Email:
</label>
<input className={styles.form} style={{ padding: "5px", marginTop: "-6px" }}
type="email" name="email" id="email"
value={this.state.email}
onChange={e => this.setState({ email: e.target.value })}
/>
<label className={styles.form} htmlFor="subject">
Subject:
</label>
<input className={styles.form} style={{ padding: "5px", marginTop: "-6px" }}
type="text" name="subject" id="subject"
value={this.state.subject}
onChange={e => this.setState({ subject: e.target.value })}
/>
<label className={styles.form} htmlFor="message">
Message:
</label>
<textarea className={styles.form} style={{ padding: "5px", marginTop: "-6px" }}
name="message" id="message" rows="5"
value={this.state.message}
onChange={e => this.setState({ message: e.target.value })}
/>
</div>
<br />
{!this.state.mailSent &&
<div className={styles.buttons}>
<button className={styles.form} type="submit" onClick={e => this.handleFormSubmit(e)} >
Send
</button>
</div>
}
<div>
{this.state.mailSent &&
<div className={styles.thanks}>Thank you for sending the message.</div>
}
</div>
</form>
<br />
</div>
</Layout >
)
}
}
export default Contacts
Some observations about the code:
- - the value of the API_PATH constant must be modified to correspond to the directory where the PHP script for the REST service will be placed;
- - the form requires the name of who is sending the message, their email address, the subject, and the message;
- - the handleFormSubmit callback is the point where the Axios library is used for calling the REST service:
- - the call is of type POST and the request body is the page state, whose information reflects the data requested in the form;
- - the state update happens by leveraging the onChange event of individual fields: this way, when the Send button is pressed, the state is updated and ready to be used by Axios
- - when Send is pressed, the handleFormSubmit callback comes into play, which calls the PHP script defined by the API_PATH constant, which we'll analyze shortly.
In the
contacts.module.scss file, let's insert the code for the stylesheets used in
contacts.js:
.contacts {
margin-top: 30px;
font-family: Roboto;
font-size: 12pt;
line-height: 16px;
background-color: #cccccc;
padding-top: 30px;
padding-bottom: 10px;
padding-left: 10px;
}
div.settings {
display: grid;
grid-template-columns: 100px 400px;
grid-gap: 10px;
}
label.form {
font-family: Roboto;
}
input.form {
font-family: Roboto;
padding: 5px;
margin-top: -6px;
}
textarea.form {
font-family: Roboto;
padding: 5px;
}
button.form {
font-family: Roboto;
}
div.buttons {
width: 510px;
overflow: hidden;
text-align: right;
}
div.settings label {
text-align: right;
}
.thanks {
font-family: Roboto;
font-size: 12pt;
font-style: italic;
}
PHP Back End
We'll put the back end files in a directory inside
static. Inside the
static directory, let's create the
api directory and, within it, another directory
contacts; this way we'll have a directory for each functionality that needs to be managed by the back end. Inside
contacts, we'll create the file
index.php with the logic necessary for data validation and sending the email to the administrator or site owner.
The content of
index.php is:
<?php
header("Access-Control-Allow-Origin: *");
$rest_json = file_get_contents("php://input");
$_POST = json_decode($rest_json, true);
if (empty($_POST['name']) && empty($_POST['email'])) die();
if ($_POST)
{
http_response_code(200);
$name = $_POST['name'];
$from = $_POST['email'];
$subject = $_POST['subject'];
$message = $_POST['message'];
// Address to send the email with the data provided in the Contacts page
$to = "info@myblog.abc";
// Data to include in the email
$msg = "Message from: " . $name . "\r\n".
"Mail: " . $from . "\r\n".
"Subject: " . $subject . "\r\n".
"Message: " . $message;
// Headers
$headers = "MIME-Version: 1.0";
$headers.= "Content-type: text/html; charset=UTF-8";
$headers.= "From: <contacts@www.moschini.cloud>";
// Send email
mail($to, "from the blog's Contacts page", $msg, $headers);
echo json_encode(array(
"sent" => true
));
}
else
{
echo json_encode(["sent" => false, "message" => "Something went wrong..."]);
}
?>
Let's analyze the PHP script:
- - the POST request body is retrieved through:
$rest_json = file_get_contents("php://input");
and then transformed into JSON:
$_POST = json_decode($rest_json, true);
- - if both the name and email address are not populated, the service ends without reporting errors:
if (empty($_POST['name']) && empty($_POST['email'])) die();
otherwise, the information indicated in the form is retrieved and used to compose the content of the email that will be sent to the address specified in the
$to variable;
- - finally, the method for sending the email is invoked:
mail($to, "from the blog's Contacts page", $msg, $headers);
and the
sent attribute is set to true, to be received as the result of the REST service call;
All that's left is to add the link to the
Contacts page in the navigation bar defined in the
Header component to test the message sending form. For this, in the file
header.js we add this line:
<li>
<Link to="/contacts/"
activeClassName={styles.navigationActive}
className={styles.navigation}
>
Contacts
</Link>
</li>
inside the tag
<ul className={styles.navigation}>
...
<li>
<Link to="/contacts/"
activeClassName={styles.navigationActive}
className={styles.navigation}>
Contacts
</Link>
</li>
</ul>
Therefore, the navigation bar interface presents a new
Contactslink that opens the page for sending messages:
After filling in the required information, clicking on
Send, if there are no errors, you'll see the message confirming the email has been sent: