Purtroppo PHP non offre un metodo intuitivo ed immediato per l’invio di email con allegati: per questo motivo spesso si fa ricorso a delle apposite classi (come PHPMailer) per gestire con maggior semplicità questa esigenza. L’utilizzo di classi esterne, seppur comodo, non è tuttavia indispensabile. Con un poco di pazienza, infatti, possiamo scrivere noi stessi il codice PHP per l’invio di email con allegati (cd: attachments) utilizzando la classica funzione mail() integrata nativamente nel linguaggio.
L’allegato, infatti, altro non è che una sorta di "inclusione" di un file all’interno di una mail. Per fare ciò si ricorre al formato MIME multi-part che consente, appunto, di creare una mail suddivisa in diverse parti. La nostra mail, quindi, avrà una semplice parte testuale (il messaggio vero e proprio) ed una parte più complessa contenente l’allegato.
In questo articolo vedremo come creare una sorta di formmail attraverso il quale gli utenti del nostro sito potranno inviarci file in allegato tramite un semplice modulo di upload.
Per raggiungere il nostro scopo realizzeremo due file distinti: un semplice file .html contenente il form ed un file .php che svolgerà tutto il lavoro di elaborazione. Precisamente, il nostro script PHP (che chiameremo formmail.php) dovrà occuparsi dei seguenti compiti:
- Recupero delle informazioni inserite nel form
- Recupero e verifica del file allegato
- Creazione del messaggio MIME multi-part
- Spedizione della email
Ma per prima cosa vediamo il file .html contenente il form:
<form action="formmail.php" method="POST" enctype="multipart/form-data">
<table border="0">
<tr>
<td>Tua Mail:</td>
<td><input type="text" name="mittente" value="" /></td>
</tr>
<tr>
<td>Oggetto:</td>
<td><input type="text" name="oggetto" value="" /></td>
</tr>
<tr>
<td>Messaggio:</td>
<td><textarea cols="20" rows="4" name="messaggio"></textarea></td>
</tr>
<tr>
<td>Allega file:</td>
<td><input type="file" name="allegato" /></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Invia" /></td>
</tr>
</table>
</form>
Non credo sia il caso di soffermarsi sul codice visto sopra in quanto si tratta di una semplice tabella HTML contenente un semplice form. L’unica cosa degna di nota è l’aggiunta di:
enctype="multipart/form-data"
al tag FORM. Questo accorgimento è necessario per la corretta gestione, tramite protocollo HTTP, dell’invio di file mediante il modulo.
Vediamo ora il codice PHP vero e proprio. Data la complessità di alcuni passaggi ho ritenuto opportuno aggiungere ampi commenti che, una volta compresi, potrete agevolmente eliminare dal vostro script:
<?php
// Recupero il valore dei campi del form
$destinatario = 'info@mail-del-sito.com';
$mittente = $_POST['mittente'];
$oggetto = $_POST['oggetto'];
$messaggio = $_POST['messaggio'];
// Valorizzo le variabili relative all'allegato
$allegato = $_FILES['allegato']['tmp_name'];
$allegato_type = $_FILES['allegato']['type'];
$allegato_name = $_FILES['allegato']['name'];
// Creo altre due variabili ad uno interno
$headers = "From: " . $mittente;
$msg = "";
// Verifico se il file è stato caricato correttamente via HTTP
// In caso affermativo proseguo nel lavoro...
if (is_uploaded_file($allegato))
{
// Apro e leggo il file allegato
$file = fopen($allegato,'rb');
$data = fread($file, filesize($allegato));
fclose($file);
// Adatto il file al formato MIME base64 usando base64_encode
$data = chunk_split(base64_encode($data));
// Genero il "separatore"
// Serve per dividere, appunto, le varie parti del messaggio.
// Nel nostro caso separerà la parte testuale dall'allegato
$semi_rand = md5(time());
$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";
// Aggiungo le intestazioni necessarie per l'allegato
$headers .= "\nMIME-Version: 1.0\n";
$headers .= "Content-Type: multipart/mixed;\n";
$headers .= " boundary=\"{$mime_boundary}\"";
// Definisco il tipo di messaggio (MIME/multi-part)
$msg .= "This is a multi-part message in MIME format.\n\n";
// Metto il separatore
$msg .= "--{$mime_boundary}\n";
// Questa è la parte "testuale" del messaggio
$msg .= "Content-Type: text/plain; charset=\"iso-8859-1\"\n";
$msg .= "Content-Transfer-Encoding: 7bit\n\n";
$msg .= $messaggio . "\n\n";
// Metto il separatore
$msg .= "--{$mime_boundary}\n";
// Aggiungo l'allegato al messaggio
$msg .= "Content-Disposition: attachment; filename=\"{$allegato_name}\"\n";
$msg .= "Content-Transfer-Encoding: base64\n\n";
$msg .= $data . "\n\n";
// chiudo con il separatore
$msg .= "--{$mime_boundary}--\n";
}
// se non è stato caricato alcun file
// preparo un semplice messaggio testuale
else
{
$msg = $messaggio;
}
// Invio la mail
if (mail($destinatario, $oggetto, $msg, $headers))
{
echo "<p>Mail inviata con successo!</p>";
}else{
echo "<p>Errore!</p>";
}
?>
Da segnalare, nella gestione dell’allegato, l’utilizzo dell’encoding base 64. E’ stato, pertanto, necessario compiere alcune operazioni sul file: lo abbiamo aperto (abbiamo usato fopen con "rb" – read binary), ne abbiamo estratto il contenuto (usando fread) e lo abbiamo passato alla funzione base64_encode (abbiamo usato chunk_split per suddividere la stringa restituita da base64_encode in segmenti più ridotti).
Concludo ricordando che il codice qui proposto ha puramente finalità didattica: prima di essere messo in produzione, infatti, dovrebbe essere arricchito di una serie di controlli circa la corretta compilazione dei campi del form oltre che sul tipo di file che l’utente sta cercando di inviarci.