Vous n'êtes pas identifié(e).
Bonjour,
J'ai un programme qui permet d'envoyer un mail à de multiples correspondants en ajoutant une pièce jointe.
Mon souci est que la pièce jointe ne fonctionne que si je vais la chercher dans le même répertoire que le fichier PHP principal.
Je m'explique.
J'ai un répertoire /fichiers avec un sous répertoire /images
Dans /fichiers j'ai
mail.php
toto.jpg
Dans /fichiers/images j'ai
toto2.jpg
Quand j'envoie le mail avec toto.jpg, je le reçois bien dans ma boite mail
Quand je veux envoyer toto2.jpg, j'ai ce message:
Warning: fopen(toto2.jpg) [function.fopen]: failed to open stream: No such file or directory in
En fait il ne cherche les pièces jointes que dans le répertoire courant.
J'ai du rater quelque chose mais je ne sais pas où...
Voici mon code
Fichier formulaire.php
et le fichier mail.php (dans le même répertoire que formulaire.php)
if (!ereg($regex,$pseudo)){
die('Pseudo non conforme');
}
elseif (!ereg($regex,$objet)){
die('Objet non conforme');
}
elseif (!ereg($regex,$message)){
die('Message non conforme');
}
elseif (!preg_match($regex_mail, $emetteur)){
die('Email non conforme');
}
else {
require_once('config/config.inc.php');
foreach ($_POST['dest'] as $id_user) {
$requete = "SELECT Adresse_mail AS email FROM adherents WHERE ID='$id_user'";
$result=mysql_query($requete) or die('Erreur SQL ! Adherents '.mysql_error());
while ($ecri_ad = mysql_fetch_object($result)) {
//=====Création de la boundary
$boundary = md5(uniqid(microtime(), TRUE));
//==========
//=====Création du header de l'e-mail
$headers = 'From: ASMB Volley-ball <'.$emetteur.'>'."\r\n";
$headers .= 'Mime-Version: 1.0'."\r\n";
$headers .= 'Content-Type: multipart/mixed;boundary='.$boundary."\r\n";
$headers .= "\r\n";
//==========
//=====Ajout du message au format texte
$message = 'Texte affiché par des clients mail ne supportant pas le type MIME.'."\r\n\r\n";
//==========
//=====Ajout du message au format HTML
$message .= '--'.$boundary."\r\n";
$message .= 'Content-type: text/html; charset=iso-8859-1'."\r\n\r\n";
//==========
//=====Ajout de la pièce jointe
$file_name = $_FILES['fichier']['name'];
if (!empty($file_name))
{
$file_type = $_FILES['fichier']['type'];
$file_size = $_FILES['fichier']['size'];
$handle = fopen($file_name, 'r') or die ('Fichier '.$file_name.' ne peut pas être ouvert');
$content = fread($handle, $file_size);
$content = chunk_split(base64_encode($content));
fclose($handle);
$message .= '--'.$boundary."\r\n";
$message .= 'Content-type:'.$file_type.';name='.$file_name."\r\n";
$message .= 'Content-transfer-encoding:base64'."\r\n\r\n";
$message .= $content."\r\n";
}
$message .= '--'.$boundary."\r\n";
if (mail($ecri_ad->email, $objet, $message ,$headers)) {
$msg = 'Le '.$date.' à '.$heure.' par '.$emetteur.' -> Envoi réussi du message à '.$ecri_ad->email.'';
}else{
$msg = 'Le '.$date.' à '.$heure.' par '.$emetteur.' -> Message non envoyé à '.$ecri_ad->email.'';
}
$etat = "mail.txt";
$inF = fopen($etat,"a");
fputs($inF,$msg."\n");
fclose($inF);
}
}
}
?>
De plus, j'ai une question qui va paraitre stupide je pense, mais tant pis, je demande.
Quand j'envoie une même pièce jointe à 25 personnes, cette pièce jointe est envoyée 1 seule fois sur le serveur ? parce qu'en regardant mon programme, je me dis que le traitement de la pièce jointe est dans le foreach donc traité à chaque fois ?
Qui pourrait m'éclairer là dessus ?
Merci d'avance
Cdt
Hors ligne
Pour ce que j'ai compris tu upload un fichier que tu veux joindre, cependant ton fichier est encore dans un répertoire temporaire du serveur.
Or je ne pense pas que les fonction fopen et autre puissent aller voir ce qui se trament dans les dossiers temporaires.
Termines l'upload proprement, inclus le fichier puis supprimes le du serveur. ^_-
Hors ligne
Bonjour,
Que ton problème est délicat^^. En effet ton code utilise le dépôt de fichiers PHP, et de fait il te faut un contrôle d'erreur et de vérification solide avec une version PHP continuellement à jour pour éviter les failles au niveau sécurité sur tes uploads, même si dans ton cas, à ce qu'il semble être, l'upload est de type local.
Ceci étant dit, avec ce système il faut savoir que tous les fichiers déposés sont stockés temporairement sur ton serveur à l'endroit stipulé par la direcive upload_tmp_dir de ton fichier php.ini et récupérable via $_FILES['fichier']['tmp_name'], vu que l'élément du formulaire correspondant a été appelé 'fichier'.
Il faudra donc dans un premier temps vérifier qu'il soit bien défini et qu'il se situe idéalement en dehors de ton arborescence. De plus les entrées de $_FILES sont stockées avec le nom de la balise <file> de ton formulaire HTML.
Ensuite, même si il s'agit d'un formulaire qu'un utilisateur peut utiliser (upload d'un fichier externe sur le serveur) ou utilisé par le serveur vers un utilisateur (upload du fichier source sur le serveur vers le dossier temporaire de dépôt sur le serveur), il reste important, pour protéger le fichier source dans le 2e cas de travailler comme si on était dans le premier cas, c'est à dire d'envoyer le fichier du dossier temporaire et non le fichier à partir du dossier source initial.
Je te conseille donc de placer un code comme suit (faudra l'adapter à ton cas^^ )
Il ne faut pas oublier aussi au niveau erreur de vérifier le type MIME même si on ne transfère que des fichiers texte (auquel cas on vérifiera que $_FILES['fichier']['type] contient bien text/plain). Il ne s'agit pas d'une erreur de sécurité car le type MIME est déduit par le navigateur de l'utilisateur en utilisant l'extension de fichier, puis est passé au serveur. S'il y avait un intérêt à passer un faux type, rien n'empêche un utilisateur malveillant de le faire.
Cordialement,
EDIT : A partir de ce que j'ai dit tu as aussi la réponse à ta dernière question : Oui le fichier est uploadé une seule fois sur le serveur, il faut donc en tenir compte dans ton code^^. N'oublie pas non plus qu'un dossier temporaire par définition est supprimé automatiquement à la fin du traitement. Le code que je t'ai proposé résouds aussi ce détail.
Dernière modification par Jc (24-05-2010 14:21:50)
POO PHP+Ajax en MVC avec PDO et Bases de données épaisses : What else?
Hors ligne
Merci pour ta réponse.
En fait, je serais le seul à utiliser ce programme en tant que responsable du site. C'est pour envoyer des fichiers aux adhérents du site, mais en aucun cas, un adhérent peut lui même en envoyer.
Donc tu dis que j'utilise le dépôt de fichier PHP.
Mais y a t'il une solution plus simple à mettre en oeuvre ?
J'avoue que je nage un peu...
Hors ligne
Bonjour,
Que tu soies le seul à l'utiliser ou non, ce système procure plein d'avantages, faut juste rester vigilant dans tes traitements php associés et je t'ai donné des clefs justement pour ne rien oublier. Bien que visiblement tu nages un peu, et comme tu es le seul à l'utiliser, je serais toi je garderais tout de même ce système.
Dit moi juste ce qui te pose problème, on essayera d'y pourvoir.
POO PHP+Ajax en MVC avec PDO et Bases de données épaisses : What else?
Hors ligne
Re,
Après réflexion je crois savoir ce qui te perturbe avec ce que je t'ai dit. En effet l'utilisation que tu souhaites en faire (ton code) va un peu à l'encontre du principe du dépôt de fichier.
Pour que t'y voies un peu plus clair je vais commencer au début.
Avec le dépôt de fichier, au lieu que les fichiers aillent du serveur vers le navigateur en utilisant le protocole HTTP, ils vont dans le sens opposé c'est-à-dire du navigateur vers le serveur. Habituellement, cette opération est implémentée avec une interface de formulaire HTML.
Prenons le cas d'une balise form typique de dépôt de fichier
Ce qu'il faut savoir :
1) Le dépôt de fichier ne peut se faire qu'avec la méthode post (dans certains cas put est possible)
2) Une fois la fin du script depopt.php atteint, le fichier sera supprimé automatiquement du dossier temporaire sur le serveur. Si un traitement de sauvegarde du fichier posté n'est pas inclus dans depot.php, il sera perdu.
Pourquoi j'ai mis dans mon exemple de code
echo "Problème : Attaque possible par le fichier ".$_FILES['fichier']['name']; exit;
Le contexte de code de cette ligne cherche à savoir si le fichier déposé est bien issu d'un transfert et s'il ne s'agit pas d'un fichier local. Pourquoi? Car un des dangers du dépôt de fichier est qu'une personne mal intentionnée amène un script de dépôt de fichier à traiter un fichier local comme s'il s'agissait d'un fichier transféré. En effet si le fichier local choisi est par exemple /etc/passwd ou le fichier contenant les mots de passe pour les accès à la base de données, la personne aurait accès à toutes les données sensibles de votre site normalement interdites à l'accès.
Conseils les plus importants pour utiliser le dépôt de fichier :
- Faire en sorte que tous les utilisateurs qui ont accès à cette fonction soient des personnes authentifiées à un moment ou un autre et qu'elle soient autorisées.
- Limiter les dépôts de fichier aux adm du site et aux responsables de contenu (par ex)
- Si tous les utilisateurs ont accès au dépôt de fichier penser à utiliser la fonction basename() pour modifier les noms des fichiers qui arrivent sur le serveur. Cette fonction supprime le chemin faisant partie du nom de fichier qui lui est passé en paramètre, qui est une attaque classique utilisée pour déposer un fichier dans un répertoire différent de celui par défaut.
______________
En conséquence, au vu de ce que je viens de dire, il est vrai qu'il est dangereux voire inadapté d'utiliser des fichiers locaux en dépôt pour les envoyer en pièce jointe par mail. Je pense que la fonction a été créee à la base pour avoir une interface d'envoi de mail avec pièce jointe à distance personalisée pour l'adm du site sans avoir les contraintes de taille de pièce jointe que sa boite aux lettres perso lui imposait, le tout sans avoir à s'occuper de gérer l'upload,le stockage et la suppression de fichier au niveau du code sur le serveur, puisque la pièce jointe est automatiquement supprimée après l'envoi du mail.
POO PHP+Ajax en MVC avec PDO et Bases de données épaisses : What else?
Hors ligne
J'ai lu avec attention ce que tu me dis et je comprends le principe, y compris pour la sécurité.
Entre temps, j'ai continué à chercher sur le web afin de trouver quelques pistes supplémentaires et j'ai réussi ce script.
if (!ereg($regex,$pseudo)){
die('Pseudo non conforme');
}
elseif (!ereg($regex,$objet)){
die('Objet non conforme');
}
elseif (!ereg($regex,$message)){
die('Message non conforme');
}
elseif (!preg_match($regex_mail, $emetteur)){
die('Email non conforme');
}
$piecejointe = "";
if(!$erreur && strlen($_FILES['fichier']['name'])) {
$fichier = $_FILES['fichier'];
$name = $fichier['name'];
$temp = $fichier['tmp_name'];
$size = $fichier['size'];
# séquence de caractères
$destination = $rep.$name;
# upload du fichier sur le serveur
if($size > $taillemax)
$erreur = "Taille du fichier $name > ".(int)($taillemax/1024)." Ko";
elseif(!@is_uploaded_file($temp))
$erreur = "Téléchargement du fichier $name impossible";
elseif(!@move_uploaded_file($temp, $destination))
$erreur = "Problème de transfert du fichier $name";
else {
//===== On vérifie maintenant le type de fichier
if(!function_exists('mime_content_type')) {
function mime_content_type($fichier) {
# ajouter autant de combinaisons que souhaitées
$mime = array(
'.gif' => 'image/gif',
'.jpg' => 'image/jpeg',
'.jpeg' => 'image/jpeg',
'.jpe' => 'image/jpeg',
'.bmp' => 'image/bmp',
'.png' => 'image/png',
'.tif' => 'image/tiff',
'.tiff' => 'image/tiff',
'.swf' => 'application/x-shockwave-flash',
'.doc' => 'application/msword',
'.xls' => 'application/vnd.ms-excel',
'.ppt' => 'application/vnd.ms-powerpoint',
'.pdf' => 'application/pdf',
'.ps' => 'application/postscript',
'.eps' => 'application/postscript',
'.rtf' => 'application/rtf',
'.zip' => 'application/zip',
'.rar' => 'application/rar',
'.html' => 'text/html',
'.htm' => 'text/html',
'.txt' => 'text/plain',
);
# par défaut
if(!$type = $mime[strrchr($fichier,'.')]) $type = "application/octet-stream";
return $type;
}
}
$mimetype = mime_content_type($destination);
# lecture et conversion du fichier
if($openf = @fopen($destination, "rb")) {
$fichier = fread($openf, filesize($destination));
@fclose($openf);
# encodage norme RFC 2045
$piecejointe = chunk_split(base64_encode($fichier));
} else {
$erreur = "Problème de lecture du fichier $name";
}
}
}
//===== Ajout du message
if(!$erreur) {
$message_final = "";
$message_final .= strip_tags($message); // valeur du message lui meme
# en-têtes
$headers = 'From: ASMB Volley-ball <'.$emetteur.'>'."\r\n";
# si pièce jointe on ajoute l'en-tête spécifique avec séparateurs
if(strlen($piecejointe)) {
$boundary = "/-------".md5(uniqid(rand()))."-------/"; // séparateur
$headers .= "\nMIME-Version: 1.0\nContent-Type: multipart/mixed; boundary=\"$boundary\"\n";
$message_final =
"This is a multi-part message in MIME format.\n--$boundary\n".
"Content-Type: text/plain; charset=ISO-8859-1\n".
"Content-Transfer-Encoding: 7bit\n\n".
"$message_final\n\n--$boundary\n".
"Content-Type: $mimetype; name=\"$name\"\n".
"Content-Transfer-Encoding: base64\n".
"Content-Disposition: attachment; filename=\"$name\"\n\n".
"$piecejointe\n--".
$boundary."--\n";
}
$message_final =stripslashes($message_final);
//===== On récupère les adresses mail dans la BDD
require_once('config/config.inc.php');
foreach ($_POST['dest'] as $id_user) {
$requete = "SELECT Adresse_mail AS email FROM adherents WHERE ID='$id_user'";
$result=mysql_query($requete) or die('Erreur SQL ! Adherents '.mysql_error());
while ($destinataire = mysql_fetch_object($result)) {
if (mail($destinataire->email, $objet, $message_final, $headers)) {
$msg = 'Le '.date("d-m-Y").' à '.date("H:i").'. Expéditeur: '.$emetteur.' -> Envoi réussi à '.$destinataire->email.'. Pièce jointe: '.$name.'';
}else{
$msg = '*** ECHEC Le '.date("d-m-Y").' à '.date("H:i").'. Expéditeur: '.$emetteur.' -> Envoi vers '.$destinataire->email.'. Pièce jointe: '.$name.'';
}
$etat = "mail.txt";
$inF = fopen($etat,"a");
fputs($inF,$msg."\n");
fclose($inF);
// @unlink($destination); // suppression de la pièce jointe ou non du repertoire d'upload
}
}
}
?>
Il fonctionne parfaitement quand j'envoie les messages dans mon mail orange lu avec outlook par exemple.
Par contre, quand j'envoie ce même message avec la même pièce jointe (un .pdf) dans ma boite gmail, la pièce jointe ressemble à ça.
etc etc...
De plus, le message arrive en spam. Une idée svp ?
Hors ligne
Je pense avoir résolu le problème en remplaçant la ligne
par
Et cette fois j'ai bien reçu le message sous gmail et orange avec la pièce jointe "intacte"
Il ne me reste plus qu'à comprendre ce que j'ai fait....
Hors ligne