picture picture
septembre 19, 2017 PHP 0 Commentaire

Envoyer un e-mail en PHP avec plusieurs pièces jointes

Un client m’a demandé la possibilité de joindre plusieurs pièces jointes aux e-mails envoyés en PHP depuis son intranet.
Mon premier réflexe a été de lui dire de faire un zip avant d’envoyer des fichiers : je craignais surtout pour les ressources du serveur qui n’est pas spécialement taillé pour des uploads lourds. Mais lui craignait que ses destinataires ne soient pas tous suffisamment « geek » pour utiliser un décompresseur (ce qui se justifie pour des envois « grand public » ou seniors…)

Il y a assez peu de ressources sur le net à ce sujet, je vous livre celle-ci : compilation personnelle de plusieurs sources que je n’ai pas toutes retrouvées (que les auteurs m’en excusent… sources en fin d’article)

Préalable

1. Il est possible que la version PHP de votre serveur ne supporte pas la fonction mime_content_type() utilisée plus bas. Elle a été réintroduite avec PHP7, mais elle est considérée comme « deprecated » par certaines versions de PHP 5.

Il suffit en ce cas de rajouter la fonction suivante sur la page :

function _mime_content_type($filename) {
  $result = new finfo();
  if (is_resource($result) === true) {
  return $result->file($filename, FILEINFO_MIME_TYPE);
  }
  return false;
}
									

Cette fonction nécessite l’activation de l’extension fileinfo de PHP.
Pour vérifier exécutez un info.php et cherchez le ligne fileinfo > enabled :

2. Il faudra préalablement vérifier l’extension et le poids du fichier avant envoi pour éviter les problèmes de dépassement des limites du php.ini.

Précisions sur les paramètres de cette fonction

1. $fichiersAJoindre peut être:
– un chaîne de type string contenant le chemin vers 1 seul fichier
– un tableau s’il y a plusieurs pièces jointes sous la forme array (‘Chemin/Vers/Fichier1.ext’,’/chemin/vers/fichiers2.ext’, etc.)
– un tableau structuré comme la super variable globale PHP $_FILES:

$array(
  'file1' => array(
    'name' => ,
    'type' => ,
    'tmp_name' => ,
    'error' => ,
    'size' => ),
  'file2' => array(...),
  'file2' => array(...),
         etc.
)
									


2. $message_txt est obligatoire contient le message au format txt
3. $message_html est facultatif (envoyez une string vide «  » si vous ne souhaitez pas envoyer votre message en html)
4. $destinataire peut-être au format ‘nom@fai.com’ ou ‘Nom Prenom<nom@fai.com>’ ou ‘Nom1 Prenom1<nom1@fai.com>,Nom2 Prenom2<nom2@fai.com>’
5. $expediteur : idem
6. $replyTo est facultatif, si différent de l’expéditeur.

La fonction

On crée une fonction qui analyse les fichiers à joindre à l’e-mail :

function FilePathToArray($leFichier) {
  if (!file_exists($leFichier)){
    return false;
  }
  $AboutTheFile=pathinfo($leFichier);
  return array(
    'chemin' => $leFichier,
    'nom' => $AboutTheFile['filename'],
    'extension'=>$AboutTheFile['extension'],
    'mimeType'=> mime_content_type($leFichier), // cf. prealable ci-dessus
    'contenu' => chunk_split(base64_encode(file_get_contents($leFichier)))
  );
}
									

Et on l’utilise dans le fonction d’envoi du mail:

function SendEmailwidthJoin($message_txt,$message_html,$destinataire,$expediteur,$fichiersAJoindre,$objet,$replyTo="" ) {

  //=== vérifier et préparer les pieces jointes:
  $arrayFiles=array();
  
  //si c'est un fichier seul sur le serveur
  if (is_string($fichiersAJoindre)){
    $lesFichiers[] = FilePathToArray($fichiersAJoindre);
  }
  
  //si c'est un tableau de x fichiers joints sur le serveur
  if (is_array($fichiersAJoindre)){
    if ((isset($fichiersAJoindre[0])) AND (is_string($fichiersAJoindre[0])) ){
      //un array simple avec des strings
      foreach($fichiersAJoindre as $stringFile){
        $lesFichiers[]= FilePathToArray($stringFile);
      }
    }
    //si x fichiers de type $_FILES (cas le + courrant)
    else {
      foreach($fichiersAJoindre as $arrayFiles){
        // si le champ est vide, on saute le tour
        if($arrayFiles['error'] == 4)
          continue;
        else {
          $aboutFile=pathinfo($arrayFiles['name']);
          $lesFichiers[]=array(
            'chemin' => getenv('TMP')."/".$arrayFiles['tmp_name'],
            'nom' => $aboutFile['filename'],
            'extension'=>$aboutFile['extension'],
            'mimeType'=> mime_content_type(getenv('TMP')."/".$arrayFiles['tmp_name']), // cf. prealable
            'contenu' => chunk_split(base64_encode(file_get_contents($arrayFiles['tmp_name'])))
          );
        }
      }
    }
  }

  //===générer les délimiteurs dans l'email ===
  do {
    $leRand=md5(rand());
    $boundary = "-----=".$leRand;
  } 
  while(!strpos($message_txt.$message_html, $leRand) === false);

  do {
    $leRand=md5(rand());
    $boundary_alt = "-----=".md5(rand());
    $isOK=true;
    foreach($lesFichiers as $fichier){
      if(!strpos($fichier['contenu'], $leRand) === false){
        $isOK=false;
      }
    }
  }
  while($isOK==false);

  //=== le type de retour à la ligne ===
  if (!preg_match("#^[a-z0-9._-]+@(hotmail|live|msn).[a-z]{2,4}$#", $destinataire)) {
    $passage_ligne = "rn";
  }
  else{
    $passage_ligne = "n";
  }

  //=== header ===
  $headers ="From: ".$expediteur.$passage_ligne;
  if ($replyTo=="") {
    $headers.= "Reply-to: ".$expediteur.$passage_ligne;
  }
  else {
    $headers.= "Reply-to: ".$replyTo.$passage_ligne;
  }

  $headers.= "MIME-Version: 1.0".$passage_ligne;
  $headers.= "Content-Type: multipart/mixed;".$passage_ligne." boundary="".$boundary.""".$passage_ligne;

  //=====Création du message.
  $message = $passage_ligne."--".$boundary.$passage_ligne;
  $message.= "Content-Type: multipart/alternative;".$passage_ligne." boundary="".$boundary_alt.""".$passage_ligne;

  //=====Ajout du message au format texte.
  if ($message_txt!="") {
    $message.= $passage_ligne."--".$boundary_alt.$passage_ligne;
    $message.= "Content-Type: text/plain; charset="ISO-8859-1"".$passage_ligne;
    $message.= "Content-Transfer-Encoding: 8bit".$passage_ligne;
    $message.= $passage_ligne.$message_txt.$passage_ligne;
  }
  //==========

  //=====Ajout du message au format HTML.
  if ($message_html!=""){
    $message.= $passage_ligne."--".$boundary_alt.$passage_ligne;
    $message.= "Content-Type: text/html; charset="ISO-8859-1"".$passage_ligne;
    $message.= "Content-Transfer-Encoding: 8bit".$passage_ligne;
    $message.= $passage_ligne.$message_html.$passage_ligne;
    //On ferme la boundary alternative.
    $message.= $passage_ligne."--".$boundary_alt."--".$passage_ligne;
  }
  //==========

  //pièces jointes
  foreach($lesFichiers as $fileArray)
  {
    $message.= $passage_ligne."--".$boundary.$passage_ligne;
    $message.="Content-Type: ".$fileArray['mimeType']."; name="".$fileArray['nom'].".".$fileArray['extension'].""".$passage_ligne;
    $message.="Content-Transfer-Encoding: base64".$passage_ligne;
    $message.="Content-Disposition: attachment; filename="".$fileArray['nom'].".".$fileArray['extension'].""".$passage_ligne;
    $message.= $passage_ligne.$fileArray['contenu'].$passage_ligne.$passage_ligne;
  }
  $message.= $passage_ligne."--".$boundary."--".$passage_ligne;
  
  //Et envoi du mail...
  mail($destinataire, $objet, $message, $headers);
}
									

Exemples d’utilisation

1. pour envoyer un tableau avec les fichiers des pièces jointes dans la super variable globale $_FILES:

SendEmailwidthJoin($_POST['messageTXT'], $_POST['messageHTML'], $_POST['destinataire'], $_POST['expediteur'], $_FILES, $_POST['objet']);
									


2. pour envoyer les pièces jointes sous forme d’un tableau des chemins:

SendEmailwidthJoin($_POST['messageTXT'], $_POST['messageHTML'], $_POST['destinataire'], $_POST['expediteur'], array('/var/www/monfichier.pdf','/var/www/consultation.doc'), $_POST['objet']);
									


3. Pour envoyer une seule pièce jointes sous forme de son chemin:

SendEmailwidthJoin($_POST['messageTXT'], $_POST['messageHTML'], $_POST['destinataire'], $_POST['expediteur'], '/var/www/monfichier.pdf', $_POST['objet']);
									

 

Sources : Blog du Grouik, site du zéro et Ficgs

No Responses to “Envoyer un e-mail en PHP avec plusieurs pièces jointes”

Commentaire

Name

Mail (ne sera pas publié)

Website

Laisser ces deux champs tels quels :
:D :-) :( :o 8O :? 8) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen: