Enviar formulário de contato com anexo em PHP
Recentemente precisei montar um formulário de contato em PHP com a possibilidade de enviar um arquivo anexado, e percebi que o PHP não suporta isso nativamente pela função mail(). Como eu não quis usar nenhuma biblioteca de terceiros pronta, vi que seria necessário alterar o header do e-mail e acrescentar nele o anexo. Para alcançar esse resultado, primeiramente precisei alterar o meu formulário. Este abaixo serve como exemplo, note o atributo enctype="multipart/form-data", sem ele não vai funcionar.
<!-- form.php -->
<form action="envio.php" method="post" enctype="multipart/form-data">
<p>
<label for="nome">Nome</label>
<input type="text" name="nome" id="nome" required="" />
</p>
<p>
<label for="email">Email</label>
<input type="email" name="email" id="email" required="" />
</p>
<p>
<label for="anexo">Anexo</label>
<input type="hidden" name="MAX_FILE_SIZE" value="100000" />
<input type="file" id="anexo" name='anexo' />
</p>
</form>No script que vai receber os dados para envio, verifico a existência do anexo, já que ele é opcional, e codifico ele no header do e-mail. Aproveito e também dou uma limpada nos textos enviados, para evitar o chamado Email injection, já que não devemos confiar em textos enviados pelo usuário.
<?php
// evitar email injection
function clean_string($string) {
$bad = array(
"content-type",
"bcc:",
"to:",
"cc:",
"href"
);
return str_replace($bad, "", $string);
}
//variáveis
$status = false;
$nome = clean_string($_POST['nome']);
$email = clean_string($_POST['email']);
$mensagem = "Enviado pelo <strong>formulário de contato</strong>";
$destino = "[email protected]"; //E-mail do destinatário
$assunto = "Contato"; // Assunto do E-mail
// se o nome temporário do arquivo estiver vazio, ele não foi enviado
if (empty($_FILES['anexo']['tmp_name'])) {
//cabeçalho
$headers = "Content-type: text/html; charset=utf-8\r\n";
$headers .= "From: $nome <$email>\r\n"; //E-Mail do destinatário
$headers .= "Reply-To: $email\r\n";
//envio
$status = mail ($destino, $assunto, $observacao, $headers);
} else {
// inicialmente, abre o arquivo e converte ele para base64
$file = $_FILES['anexo']['tmp_name'];
$originalFile = $_FILES['anexo']['name'];
$file_size = filesize($file);
$handle = fopen($file, "rb");
$content = fread($handle, $file_size);
fclose($handle);
$content = chunk_split(base64_encode($content));
// separador aleatório necessário para enviar conteúdo mixed
$separator = md5(time());
// fim de linha (usando uma constante do PHP para fim de linha)
$eol = PHP_EOL;
// cabeçalho principal (multipart obrigatório)
$headers = "From: $nome <$email>" . $eol;
$headers .= "MIME-Version: 1.0" . $eol;
$headers .= "Content-Type: multipart/mixed; boundary=\"" . $separator . "\"" . $eol . $eol;
$headers .= "Content-Transfer-Encoding: 8bit" . $eol;
$headers .= "This is a MIME encoded message." . $eol . $eol;
// mensagem (apenas formato html aqui)
$headers .= "--" . $separator . $eol;
$headers .= "Content-Type: text/html; charset=\"utf-8\"" . $eol;
$headers .= $mensagem . $eol . $eol;
// anexo usando o nome do arquivo original
$headers .= "--" . $separator . $eol;
$headers .= "Content-Type: application/octet-stream; name=\"" . $originalFile . "\"" . $eol;
$headers .= "Content-Transfer-Encoding: base64" . $eol;
$headers .= "Content-Disposition: attachment" . $eol . $eol;
$headers .= $content . $eol . $eol;
$headers .= "--" . $separator . "--";
// enviar email
$status = mail($destino, $assunto, "", $headers);
}
if ($status) {
echo "Envio com sucesso";
} else {
echo "Ocorreu um erro no envio";
}Pronto, com isso agora o formulário é capaz de enviar os anexos corretamente. Fontes