Programming Notes
Think it, Code it, Run it    moschini.cloud  

Integrazione con PHP
Data pubblicazione: 04 settembre 2022

Introduzione

Nei precedenti articoli, abbiamo visto come progettare un sito tramite Gatsby, un framework basato su React.

Abbiamo concentrato l'attenzione sull'aspetto visuale del progetto, ovvero il front end, tralasciando ciò che concerne l'aspetto elaborativo, ossia il back end.

In questo articolo, vedremo come utilizzare il linguaggio PHP per creare un servizio REST per l'invio di una e-mail e come invocarlo da un componente React, in particolare da una pagina che permetterà l'invio di messaggi.


Prerequisiti

Per poter invocare un servizio REST possiamo utilizzare la libreria Axios che facilita notevolmente questo tipo di chiamate. Per installare la libreria, eseguiamo questo comando:

    npm install axios

Creazione della pagina dei contatti

Iniziamo con la scrittura del codice per la nuova pagina che servirà per inviare un messaggio al proprietario o all'amministratore del sito. all'interno della directory pages creiamo due file:

  • contacts.js: è la pagina attraverso la quale inviare il messaggio
  • contacts.module.scss: è il file con gli stylesheets

Nel file contacts.js inseriamo il codice per definire la pagina per la richiesta di informazioni da inviare:

import React, { Component } from 'react';
import Layout from '../components/layout'
import axios from 'axios';
import * as styles from "./contacts.module.scss"

// ATTENZIONE:
// il valore di questa costante deve essere modificato in modo che corrisponda
// alla directory nella quale sarà posto lo script PHP per il servizio REST
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">
                Nome:
              </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">
                Oggetto:
              </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">
                Messaggio:
              </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)} >&nbsp;&nbsp;Invia&nbsp;&nbsp;</button>
              </div>
            }

            <div>
              {this.state.mailSent &&
                <div className={styles.thanks}>Grazie per aver inviato il messaggio.</div>
              }
            </div>

          </form>
          <br />
        </div>
      </Layout >
    )
  }
}

export default Contacts

Alcune osservazioni sul codice:

  • il valore della costante API_PATH deve essere modificato in modo che corrisponda alla directory nella quale sarà posto lo script PHP per il servizio REST;
  • la form richiede il nome di chi sta inviando il messaggio, il suo indirizzo mail, l'oggetto e il messaggio;
  • la callback handleFormSubmit è il punto in cui viene utilizzata la libreria Axios per la chiamata al servizio REST:
    • la chiamata è di tipo POST e il body della richiesta è lo stato della pagina, le cui informazioni riflettono i dati richiesti nella form;
    • l'aggiornamento dello stato avviene sfruttando l'evento onChange dei singoli campi: in questo modo, alla pressione del pulsante Invia lo stato è aggiornato e pronto per essere utilizzato da Axios
  • quando si preme Invia entra in gioco la callback handleFormSubmit che richiama lo script PHP definito dalla costante API_PATH, che analizzeremo tra poco.

Nel file contacts.module.scss inseriamo il codice per gli sylesheets utilizzati 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;
}

Back end PHP

I file legati al back end li andremo a mettere in una directory interna a static. Dentro la directory static creiamo la directory api e, al suo interno, una ulteriore directory contacts; in questo modo avremo una directory per ciascuna funzionalità che ha bisogno di esser gestita da back end. All'interno di contacts andremo a creare il file index.php con la logica necessaria alla validazione dei dati e all'invio della mail all'amministratore o al proprietario del sito.

Il contenuto di index.php è:

<?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'];

	  // Indirizzo a cui inviare la mail con i dati forniti nella pagina Contacts 
	  $to = "info@mioblog.abc";

	  // Dati da includere nella mail
	  $msg = "Messaggio da: " . $name . "\r\n" .
  	       "Mail: " . $from . "\r\n" .
	  	     "Oggetto: " . $subject . "\r\n" .
		       "Messaggio: " . $message;

	  // Headers
	  $headers = "MIME-Version: 1.0\r\n";
	  $headers.= "Content-type: text/html; charset=UTF-8\r\n";
	  $headers.= "From: <contatti@www.moschini.cloud>";

    // Invio mail
	  mail($to, "dalla pagina Contacts del blog", $msg, $headers);

	  echo json_encode(array(
  	 	"sent" => true
	  ));
	}
  else
	{
	  echo json_encode(["sent" => false, "message" => "Qualcosa è andato storto ..."]);
	}
?>

Analizziamo lo script PHP:

  • il body della richiesta POST viene recuperato tramite:
      $rest_json = file_get_contents("php://input");

e quindi trasformato in JSON:

      $_POST = json_decode($rest_json, true);
  • se il nome e l'indirizzo e-mail sono entrambi non valorizzati, il servizio termina senza segnalare errori:
      if (empty($_POST['name']) && empty($_POST['email'])) die();

altrimenti si recuperano le informazioni indicate nella form e si utilizzano per comporre il contenuto della mail che verrà inviata all'indirizzo specificato nella variabile $to;

  • infine, si invoca il metodo per l'invio della mail:
      mail($to, "dalla pagina Contacts del blog", $msg, $headers);

e si valorizza l'attributo sent a true, in modo da essere recepito come risultato della chiamata al servizio REST;


Non resta che aggiungere il link alla pagina Contacts nella navigation bar definita nel componente Header per poter testare la form per l'invio dei messaggi.

Per questo, nel file headeer.js aggiungiamo questa linea:

    <li><Link to="/contacts/" activeClassName={styles.navigationActive} className={styles.navigation}>Contacts</Link></li>

all'interno del tag

    <ul className={styles.navigation}>
      ...
      <li><Link to="/contacts/" activeClassName={styles.navigationActive} className={styles.navigation}>Contacts</Link></li>
    </ul>

Quindi, l'interfaccia della navigation bar presenta un nuovo link Contacts che apre la pagina per l'invio dei messaggi:

Blog

Dopo aver compilato le informazioni richieste, al click su Invia, se non ci sono errori, si visualizza il messaggio di avvenuto invio della e-mail:

Blog