Formulaire de contact sans javascript avec pièce jointe

Stop aux pop-up sauvages, indiquant que tel ou tel champ n'a pas été renseigné correctement, via une vérification javascript. Il est très facile de concevoir un formulaire entièrement géré par des instructions PHP. On fait juste appel à la récursivité : le script se traite lui même par rechargement de la page, en utilisant la variable prédéfinie super globale fr2.php.net/variables.predefined $_POST transmise par le serveur. Aussi, comme cette variable contient un tableau complet des données de formulaire, ce dernier est modifiable sans nécessairement modifier le code PHP (ajout de champs à volonté).

Fondements

Pour commencer, voyez la feuille de styles dev.ppan.net/webdev_form.css spécifique qui compose ce formulaire. Ensuite, copiez le code commenté ci-dessous ou téléchargez l'archive zip. Le nom de fichier est sans importance, car le formulaire s'appelle lui-même via la variable prédéfinie $_SERVER['PHP_SELF'] (c'est ré-cur-sif !).

Ce type de méthode, côté serveur, implique un rechargement de page à chaque erreur. Certains contestent ce principe en défendant la vérification javascript, mais quid du javascript quand il est désactivé ?...

Vous pouvez tester ce formulaire. Comme je suis un garçon bien élevé je ne mettrai pas votre email dans une quelconque mailing-liste. Au pire, mettez un téléphone spatial et pas d'email, il partira tout de même !

FAQ

Pourquoi certaines fichiers ne passent pas ?
La limite d'upload par défaut (php.ini) est fixée à 2 Mo mais elle dépend de l'hébergeur et peut être bien moindre.

Pourquoi le script n'envoie rien ?
Vérifier que la fonction mail() est disponible chez l'hébergeur.

Pourquoi le champ de fichier n'est pas visible ?
Il faut créer le répertoire upload sur le serveur. S'il porte un autre nom, modifier la variable $rep (pour la racine $rep='/')

Comment limiter la pièce jointe à un type de fichier ?
Il faut tester $mimetype. Exemple pour un type image :

if(!stristr($mimetype,'image')) {
	$erreur = "Seulement un fichier de type image SVP";
	$focus = 7;
}

Comment créer ou supprimer un champ ?
Tout fonctionne par couple vérification (PHP) et champ (HTML) correspondant. En cas de compréhension difficile du PHP, contentez vous d'ajouter la partie HTML (mais sans vérification).

<?
# code PHP
if (empty($_POST['foo'])) {
	$erreur = "Merci de renseigner Champ";
	$focus = 30; // chaque champ a sa propre valeur $focus
}
?>
<!-- code html -->
<p><label for="foo">Champ</label>
<input id="foo"<? if($focus == 30) echo " class='focus'";?> name="foo" value="<?= htmlentities($_POST['foo'],ENT_QUOTES)?>"></p>

Pourquoi la page ne se redirige pas après traitement du formulaire ?
Le code PHP ci-dessous doit impérativement être placé avant tout code HTML. Ceci est dû à la fonction header() qui gère l'envoi d'en-tête HTTP et doit s'exécuter avant toute sortie (un caractère quelconque avant la première balise <?php est considéré comme tel).

Traitement (début de page)

<?php
error_reporting (E_ERROR | E_WARNING | E_PARSE);
/*
Envoi de formulaire sans javascript avec pièce jointe proposé par Pierre Pesty http://dev.ppan.net/

Variables A MODIFIER selon vos besoins :
*/
# remplacez login@fai par votre email
$destinataire = "login@fai";
# nom et titre de page
$pageName = "Formulaire de contact";
# en-tête de l'objet du mail (option: vide)
$entete = "[dev.ppan.net]";
# envoi en copie carbone (option: vide)
$email_cc = "";
# envoi en copie cachée (option: vide)
$email_bcc = "";
# emplacement de la feuille de styles
$cssform = "webdev_form.css";
# nom du répertoire pour upload des pièces jointes
# le répertoire (ici "upload") doit être créé sur le serveur
$rep = "upload/"; // ne pas oublier le slash /
# taille max de la pièce jointe (multiple de 1024)
$taillemax = 204800;
# menu déroulant pour l'objet (option: vide)
# ajout d'option : 'n'=>'Choix 1', 'n+1'=>'Choix 2', etc.
# la première ligne (optionnelle) impose un choix
$objets = array(
    0 => 'Choisissez',
    1 => 'Test du script',
    2 => 'Ce script',
    3 => 'Autre',
);
# page vers laquelle rediriger le script après envoi réussi
$pageconfirme = "index.php";
/*
si $pageconfirme n'est pas dédiée aux messages on peut y traiter
la variable $_GET['mailOK'] comme ceci :
if(isset($_GET['mailOK']))
    echo "Votre message a été envoyé";
*/

/*
fin des modifications
*/

$erreur = false;
$message = false;
$focus = 0;

# l'utilisateur a validé le formulaire
if (!empty($_POST)) {

	# vérification des champs requis (Nom, Objet, Message, Email ou Tel)
	if (empty($_POST['Message'])) {
		$erreur = "Merci de renseigner le message";
		$focus = 1; // modification couleur du champ de saisie concerné
	}
	if (empty($_POST['Objet'])) {
		$erreur = "Merci de renseigner l'objet";
		$focus = 2;
	}
	if (empty($_POST['Nom'])) {
		$erreur = "Merci de renseigner votre nom";
		$focus = 3;
	}
	# email et tel sont vides : pas glop !
	if (empty($_POST['Email']) && empty($_POST['Tel'])) {
		$erreur = "Saisir email et/ou t&eacute;l&eacute;phone SVP";
		$focus = 4;
	}
	# vérification de l'email non vide
	elseif (!empty($_POST['Email'])) {
		if(!preg_match('`^[[:alnum:]]([-_.]?[[:alnum:]])*@[[:alnum:]]([-_.]?[[:alnum:]])*\.([a-z]{2,4})$`',$_POST['Email'])) {
			$erreur = "Email non conforme";
			$_POST['Email'] = "";
			$focus = 5;
		}
	# vérification du téléphone (sans espaces)
	} elseif (!is_numeric(str_replace(" ","",$_POST['Tel']))) {
		$erreur = "Téléphone non conforme";
		$_POST['Tel'] = "";
		$focus = 6;
	}
	# pièce jointe (nouveauté 12.10.2005)
	$piecejointe = "";
	if(!$erreur && strlen($_FILES['Fichier']['name'])) {
		$fichier = $_FILES['Fichier'];
		# upload du fichier sur le serveur
		$temp = $fichier['tmp_name'];
		$name = $fichier['name'];
		$size = $fichier['size'];
		$destination = $rep.$name;
		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";
		if($erreur) $focus = 7;
		else {
			# lecture du 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',
					'.psd' => 'image/x-xwd',
					'.png' => 'image/png',
					'.txt' => 'text/plain',
					'.doc' => 'application/msword',
					'.xls' => 'application/vnd.ms-excel',
					);
					# par défaut
					if(!$type = $mime[strrchr($fichier,'.')]) $type = "application/octet-stream";
					return $type;
				}
			}
			/*
				pour utiliser mime_content_type()
				éditer le fichier php.ini et enlever le commentaire sur :
				extension=php_mime_magic.dll
				sous Windows ajouter ces 2 lignes :
				mime_magic.debug = On
				mime_magic.magicfile = "c:\chemin_du_fichier\magic.mime"
				NB : fonction non activée chez OVH
			*/
			$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";
				$focus = 7;
			}
		}
	
	}
	# pas d'erreur donc on continue
	if(!$erreur) {

		# traitement du tableau $_POST qui contient les paires name => value
		$message_final = "";
		foreach($_POST as $key => $value) {
			# la boucle passe les champs vides ou non désirés
			# pour passer d'autres champs les séparer par |
			if (!strlen($value) || preg_match("/MAX_FILE_SIZE|Objet/i", $key)) continue;
			$message_final .= "$key : ".strip_tags($value)."\n";
		}
		# formatage du message de confirmation affiché (option)
		# conversion des sauts de ligne et des caractères spéciaux
		$message = nl2br(htmlentities($message_final));
		# si $objets est un tableau : Objet = select donc index = $_POST['Objet']
		if(is_array($objets))
			$objet = "$entete ".$objets[$_POST['Objet']];
		# sinon Objet = input donc en français dans le texte !
		else
			$objet = "$entete ".$_POST['Objet'];
		# si l'email n'est pas renseigné on le remplace par celui
		# du destinataire, en ajoutant une alerte au message
		$final_mail = $_POST['Email'];
		if(empty($_POST['Email'])) {
			$final_mail = $destinataire;
			$message_final .= "\nNe pas répondre par mail : email absent.\n";
		}
		# en-têtes
		$headers = "From: ".$final_mail;
		if(strlen($email_cc))
			$headers .= "\nCC: ".$email_cc;
		if(strlen($email_bcc))
			$headers .= "\nBCC: ".$email_bcc;
		# hôte expéditeur
		$message_final .= "Hôte : ".gethostbyaddr($_SERVER['REMOTE_ADDR']);
		# 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";
		}

		# envoi du mail
		if (@mail($destinataire, stripslashes($objet), stripslashes($message_final), $headers)) {
			@unlink($destination); // suppression de la pièce jointe
			# si la page de redirection est renseignée
			if(!empty($pageconfirme)) {
				@header("Location: ".$pageconfirme."?mailOK=1");
				exit;
			}
		 } else {
			$pageName = "Echec !";
			$erreur = "Echec de l'envoi ! Merci d'essayer encore";
		 }

	} else {

		$pageName = "Erreur de saisie !";

	} // if(!$erreur)

} // if ($_POST)
?>

Voir les options d'upload pour parfaire le contrôle du fichier et la protection anti-spam éventuellement.

Ci-après, on note la présence de la fonction htmlentities dans chacun des champs de formulaire. Outre l'affichage universel de caractères accentués ou spéciaux, elle a deux objectifs : éviter le hack via des instructions type javascript (qui s'exécuteraient en cas d'erreur, au rechargement de page) et, via la constante ENT_QUOTES, recharger les post-données avec apostrophe (quote) incompatible avec les champs input.

[Haut de page]

Affichage (fin de page)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title><? echo $pageName?></title>
<meta name="author" content="Pierre Pesty">
<meta name="generator" content="http://dev.ppan.net/">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link href="<? echo $cssform?>" type="text/css" rel="stylesheet">
</head>
<body>
	<div>
<?		if (!$erreur) { ?>
		  <h4>Contact</h4>
		  <p>Merci de renseigner les champs marqués d'un astérisque (email et/ou téléphone)</p>
<?		} else { ?>
		  <p class="alerte"><? echo $erreur?></p>
<?		} ?>
		  <hr>
		  <form name="formulaire" action="<? echo $_SERVER['PHP_SELF']?>" method="post" enctype="multipart/form-data">
			 <p>
				<label for="nom">Nom</label><input id="nom" <? if($focus == 3) echo "class=\"focus\"";?> name="Nom" maxlength="30" value="<? echo htmlentities($_POST['Nom'], ENT_QUOTES)?>"> 
			 </p>
			 <p>
				<label for="email">Email</label><input id="email" <? if($focus == 5 || $focus == 4) echo "class=\"focus\"";?> name="Email" maxlength="60" value="<? echo htmlentities($_POST['Email'], ENT_QUOTES)?>">
			 </p>
			 <p>
				<label for="tel">Téléphone</label><input id="tel" <? if($focus == 6 || $focus == 4) echo "class=\"focus\"";?> name="Tel" maxlength="20" value="<? echo htmlentities($_POST['Tel'])?>">
			 </p>
			 <p>
<?		if (is_array($objets)) { ?>
				<label for="objet">Objet</label><select name='Objet' <? if($focus == 2) echo "class=\"focus\"";?> id="objet">
<?
foreach($objets as $key => $val) {
    echo "				  <option value='$key'";
    // vérifier si une des entrées a été choisie
    if($key == $_POST['Objet']) echo " selected";
    echo ">$val\n";
}
?>
				</select>
<?		} else { ?>
				<label for="objet">Objet</label><input id="objet" <? if($focus == 2) echo "class=\"focus\"";?> name="Objet" maxlength="60" value="<? echo htmlentities($_POST['Objet'], ENT_QUOTES)?>">
<?		} ?>
			 </p>
			 <p>
				<label for="message">Message</label><textarea <? if($focus == 1) echo "class=\"focus\"";?> id="message" name="Message"><? echo htmlentities(stripslashes($_POST['Message']))?></textarea>
			 </p>
<?		if (file_exists($rep)) { ?>
			 <p>
				<label for="fichier">Pièce jointe</label><input type="hidden" name="MAX_FILE_SIZE" value="<? echo $taillemax?>"><input type="file" id="fichier" <? if($focus == 7) echo "class=\"focus\"";?> name="Fichier" size="35">
			 </p>
			 <p>
				<label>&nbsp;</label>NB : taille du fichier inférieure à <?= (int)($taillemax/1024)?> Ko
			 </p>
<?		} ?>
			 <p>
				<label>&nbsp;</label><input id="submit" type="submit" value="Envoyer"> <a href="./">Accueil</a>
			 </p>
		  </form>
	</div>
</body>
</html>

Variante (code partiel)

Plutôt que de recevoir la pièce jointe, pourquoi ne pas la lire en ligne ? Tout se passe dans la partie traitement (PHP). Pour cela on a d'abord besoin, dans les variables, de l'URL du site où sera stockée la pièce jointe :

[Haut de page]

# répertoire temporaire d'upload (option: vide ou $rep inconnu)
$rep = "upload/"; // ne pas oublier le slash /
# URL absolue où se trouve le répertoire
$monsite = "http://dev.ppan.net/"; // ne pas oublier le slash /

Puis, au lieu de coder le fichier joint et l'envoyer, on le garde sur le serveur pour lecture ultérieure. Cependant, pour éviter les noms identiques, donc un écrasement, on lui attribue alors un nom codé :

	$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
		$chars = array(
			"a","A","b","B","c","C","d","D","e","E","f","F","g","G","h","H",
			"i","I","j","J","k","K","l","L","m","M","n","N","o","O","p","P",
			"q","Q","r","R","s","S","t","T","u","U","v","V","w","W","x","X",
			"y","Y","z","Z","1","2","3","4","5","6","7","8","9","0");
		$max_elements = count($chars) - 1;
		# composition du nom de fichier aléatoire (8 caractères)
		for($i=0; $i<8; $i++) $aleatoire .= $chars[rand(0,$max_elements)];
		# extraction de l'extension du fichier original
		$extension = strtolower(substr(strrchr($name, "."), 1));
		# attribution du nom de fichier sur le serveur
		$newname = $aleatoire.".".$extension;
		$destination = $rep.$newname;
		# 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";
		if($erreur) $focus = 7;
		else $piecejointe = $monsite.$destination;
	}

Enfin on ajoute au mail l'URL absolue du fichier téléchargé :

		if(strlen($piecejointe)) {
			# si pièce jointe on ajoute au mail un lien vers le fichier
			$message_final .= "\nDocument joint : $piecejointe";
			# on ajoute également un lien de suppression
			$message_final .= "\nSupprimer : ".$monsite."supfichier.php?destination=".$destination;
		}
		$headers .= "\nMIME-Version: 1.0\nContent-Type: text/plain; charset=ISO-8859-1\nContent-Transfer-Encoding: 7bit\n";

Bien évidemment on supprime la ligne :

			@unlink($destination); // suppression de la pièce jointe

Reste à créer un fichier supfichier.php qui se chargera de la destruction du fichier une fois lu, en deux lignes, afin d'éviter la gestion FTP du répertoire.

supfichier.php

<?php
@unlink($_GET['destination']);
@header("Location: ./");
?>
Fab a commenté le 22.04.2011

Bonjour,
Merci pour cet excellent script, et pour votre gentillesse de le mettre à dispo de tous :-)
Pourriez-vous m'aider sur un point : je n'arrive pas à rendre le champs "envoi de pièce jointe" obligatoire...
Merci

Réponse du webmestre :
if (empty($_FILES['Fichier']['name'])) {
$erreur = "Merci de joindre un fichier";
}
Ajouter une vérification des autres champs via javascript, afin d'éviter le rechargement à chaque erreur.

Joh1 a commenté le 13.02.2011

Merci beaucoup pour ce script plein de commentaires et facile à adapter. Ca m'a fait gagner beaucoup de temps.

Franck a commenté le 02.02.2011

Bonjour, merci pour ce super formulaire.
cependant j'ai un léger problème quand je reçois le mail. en effet, toute est normal si mon formulaire est rempli avec une pièce jointe. Mais lorsque je ne joint pas de fichier la ponctuation dans le mail n'est pas prise en compte correctement. du type : é = é ; ô = ô... etc cela provient-il du charset? je suis passé en utf-8, mais rien ne change... pourriez vous me répondre svp?

Fabrice a commenté le 01.02.2011

Bonjour,
Merci pour ce script.
J'aurais besoin d'ajouter un bouton radio (type "votre choix : OUI ou NON"). Pourriez-vous m'indiquer la marche à suivre ?
Merci !

Réponse du webmestre :
Il suffit d'ajouter l'élément de formulaire name="Choix" avec pour value="oui" et "non". Le script traitera automatiquement son ajout dans le message.

Cyril M a commenté le 06.01.2011

Merci pour ce code.
J'ai un soucis, j'utilise le formulaire sur la home page d'un site en utilisant seulement deux champs (nom et email), j'ai pu faire les modifications de code sans soucis majeur.
Mon problème est que lorsque je reviens sur cette page, un message m'indique que le formulaire va de nouveau être envoyé et effectivement je reçois de nouveau un mail. Comment faire pour que le formulaire soit de nouveau vierge ou soit qu'aucun nouveau mail soit envoyé.
Merci d'avance et encore bravo. Et Meilleurs vœux pour cette nouvelle année.

Réponse du webmestre :
Afin d'éviter un F5 ou rafraîchissement de la page, il est conseillé d'utiliser la redirection de la page ($pageconfirme) en cas de succès. En revanche il est, à ma connaissance, impossible d'éviter un retour sur le formulaire (flèche navigateur) qui déclenche à nouveau la soumission des variables $_POST du formulaire.
Bonne année.

Berticoyote a commenté le 05.01.2011

Bon je me joins à tous pour vous remercier et vous tirer mon chapeau...
Pour un pauvre graphiste peu doué en php comme moi... c'est génial...
Par contre j'ai un petit probleme... je n'arrive pas à configurer la page de redirection une fois le message envoyé.
Une fois le mail parti, la redirection ne se fait, on reste sur la même page (formulaire.php par exemple) et plus rien ne s'affiche.... lorsque je regarde le code source de la page d'ailleurs je me rend compte qu'il ne s'affiche que le début de ma page jusqu'à la partie php qui est alors supprimé.... en gros le code source est celui de la même page que le formulaire... et à partir du premier < ? plus rien ?!?...
Une idée ?
D'avance merci et encore bravo

Réponse du webmestre :
Vous devez renseigner
$pageconfirme = "index.php";
par la page ad hoc et y traiter la variable $_GET['mailOK']. Si la redirection header() ne fonctionne pas, c'est qu'il y a un bug quelque part.
NB : il est normal qu'aucun code PHP ne s'affiche puisqu'il est exécuté sur le serveur (chez l'hébergeur), qui ne renvoie (au "client") que le code HTML concerné.

Fabrice a commenté le 28.12.2010

Bonjour,
Merci pour cet article très complet, de loin le meilleur (et j'ai passé 1 jour 1/2 entier à visiter les forums de développeurs!).
J'aurais deux question svp à vous soumettre :
1- Comment faire pour ne récupérer que des fichiers PDF en pièce jointe ?
2- J'ai réussi à faire fonctionner correctement le script sur Gmail, mais pas avec OUTLOOK. Mon problème est que les emails doivent automatiquement arriver dans ce programme.
Merci par avance de votre réponse.

Réponse du webmestre :
1. avant la ligne "# pièce jointe" il faut ajouter un test de $_FILES['Fichier']['tmp_name'] en utilisant la fonction mime_content_type() ou finfo_file() qui doit retourner "application/pdf".
2. le script, exécuté sur un serveur web et utilisant la fonction mail() de PHP, n'a strictement rien à voir avec le logiciel qui réceptionne les mails. Par conséquent si le message parvient sur un compte Gmail, l'erreur sous Outlook vient d'ailleurs.

Pascal a commenté le 25.12.2010

Mille merci !
Cela fait 15 jours que je cherchais ce type de formulaire qui fonctionne.
Si seulement j'avais trouvé votre code avant...
Je suis très très débutant en PHP et j'ai pourtant réussi du premier coup avec vos explications très claires.
J'aimerais tant être aussi doué mais bon.........
Encore merci et continuez SVP !

Jeff a commenté le 14.10.2010

Ok j'ai finis par y parvenir!
Merci beaucoup :)

Jeff a commenté le 13.10.2010

Idem pour moi.
Je planche la dessus depuis 2 semaines déjà et je ne parvient pas à ajouter des pièces jointes au mail.
Il y a forcement quelque chose qui m'échappe.

Réponse du webmestre :
Le problème d'upload multiple est de deux ordres : il faut traiter un tableau (champs sous la forme name="fichier[]" avec crochets) et savoir combien de pièces jointes devront être ajoutées. En HTML c'est un peu lourd car il faut un script (PHP ou javascript) qui ajoute autant de champs que l'utilisateur en demande. L'idéal est alors d'utiliser un applet Java : voir l'article "Upload multiple" sur ces ondes.

Solakin a commenté le 12.03.2010

Bonjour,
Je suis très content d'être tombé sur ce tuto très bien fait et qui a le mérite d'être sérieusement réalisé.
Bravo donc !
Néanmoins, comme d'autres j'aimerais beaucoup que vous ajoutiez la méthode pour pouvoir ajouter d'autre pièces jointes...je sais que ça demande du temps et de la motivation mais de mon coté, je vous fais cette demande car ça fait des semaines que je planche sur ce "détails" et malgré des résultats approximatifs je n'ai toujours pas réussi à avoir trois pièces jointes inclues dans le mail envoyé...
Alors s'il vous plait: un petit effort supplémentaire serait vraiment bienvenu avec les lignes de codes complètes car parfois une indication qui vous semblera claire ne sera quand même pas suffisante pour les débutant comme moi.
Merci.
(C'est ça la rançon du succès... ;-) )

Réponse du webmestre :
Pour implémenter reCAPTCHA, il suffit d'ajouter ces lignes :
$resp = recaptcha_check_answer($privatekey, $_SERVER["REMOTE_ADDR"], $_POST["recaptcha_challenge_field"], $_POST["recaptcha_response_field"]);
if(!$resp->is_valid) { $erreur = "Réponse fausse ! (". $resp->error .")"; }
juste avant la ligne :
$piecejointe = "";
(je n'ai pas pris le temps de tester)

Thieric a commenté le 29.11.2009

Bonjour,
Votre script est tout simplement formidable. J'aurais voulu avoir votre expertise pour savoir comment intégrer cet outil de Captcha qui est très bien lui aussi, à votre script. J'ai bien essayé mais le formulaire ne semble pas tenir compte du captcha lorsqu'il est validé...

Voici le captcha dont je parle : http://recaptcha.net/plugins/php/

Merci d'avance pour toute aide,

Thiéric

Arnaud a commenté le 12.09.2009

Script très propre, autant que je puisse en juger.
On arrive à le comprendre sans y connaître grand chose en php...
Mais quand même : que doit-on modifier pour qu'apparaissent en même temps tous les messages d'erreurs, et la coloration des champs respectifs, plutôt que l'un après l'autre ?

Merci pour la leçon.
Merci pour le partage.

Lina a commenté le 04.09.2009

bravo pour ce script très facile à utiliser, très efficace :) !! Merci de le partager !

Lady06 a commenté le 20.07.2009

Alors là, je ne dis qu'un seul mot : bravo ! !
Il ne me reste qu'à tester demain avec un fichier css et le contrôle anti-spam.
Merci à vous et à votre gentillesse d'avoir partagé ce code

Le_gemaux a commenté le 24.05.2009

bonjour
peut on modifier le code afin que le même message saisi par l'internaute lui soit renvoyé à l'adresse qu'il a indiqué ??

j'ai pensé à ça vu que beaucoup de serveurs gratuits tardent à envoyer le mail ou le supprime (pour contrer les spam) malgré une fonction mail activé (c'est le cas de 123.fr par exemple).

j'ai pensé à mettre une variable dans le champ Copie carbone les paramètres , celle ci correspondrait à la valeur inséré dans le champ mail.

que pensez vous ?? je m'y connait pas trop en la matière désolé si je dis des bétises

Réponse du webmestre :
Pour ajouter le mail au formulaire c'est très simple !
# en-têtes
$headers = "From: ".$final_mail;
if(!empty($_POST['Email']))
$headers .= "nCC: ".$_POST['Email'];

Carl a commenté le 14.02.2009

Bonjour,

Très bon script et surtout facile à installer.

Aidez-moi s'il vous plait à ajouter 2 fonctionnalités à mon formulaire:

1- Afficher les informations saisies sur la page (après avoir cliqué sur le bouton envoyer);

2- Envoyer un email de confirmation à ce celui qui a rempli le formulaire.

Merci

Réponse du webmestre :
Le point 1 n'est pas une bonne idée mais, à la place de
@unlink($destination);
@header("Location:".$pageconfirme."?mailOK=1");
exit;
on affiche $message_final sur la page.
Pour le point 2, il suffit d'ajouter sous
if (@mail($destinataire, stripslashes($objet), stripslashes($message_final), $headers))
ces deux lignes :
if(!empty($_POST['Email']))
@mail($_POST['Email'], stripslashes($objet), stripslashes($message_final), "From: ".$_POST['Email']);
(je n'ai pas ajouté de vérification)

Py a commenté le 15.04.2008

Bonjour,

J'ai un petit souci... quand je mets l formulaire sur mon site/serveur la ligne permettant de sélectionner une pièce joint n'apparait plus... Que faire?

Merci pour ce script!

Réponse du webmestre :
Il faut créer le répertoire "upload" sur le serveur (racine du site).
Ou un autre nom mais il faut alors modifier la variable $rep.

Dominique a commenté le 29.10.2007
Bonsoir,
Je voudrais également m'associer aux autres pour la qualité de ce script.
J'ai cependant deux questions :
1. Comment n'accepter que certaines extensions de fichiers et pas d'autres [...]
Je voudrais donc n'accepter que des images et non des fichiers .exe ou . php
Comment faire ?

2. Où faut-il rajouter le formulaire anti-spam au formulaire sans javascript ??

Merci et bonne continuation.
Dominique

Réponse du webmestre :
Pour ne charger que des images, ajouter ce test :
<?php
$mimetype = mime_content_type($destination);
# lecture et conversion du fichier
if(!eregi('image',$mimetype)) {
    $erreur = "Seulement un fichier de type image SVP";
    $focus = 7;
} elseif($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";
    $focus = 7;
}
?>

Ceci étant dit, la fonction mime_content_type est dépréciée au profit de FileInfo :
http://fr3.php.net/manual/fr/ref.fileinfo.php
Ce qui ne remet pas en cause ce qui est écrit.

2. Pour ajouter le captcha, modifier :
if (!empty($_POST))
par :
if(!empty($_POST) && !strlen($erreur))
et ajouter tout ce qui est avant cette ligne (le code PHP dans le formulaire anti spam).

A l'intérieur du formulaire HTML, placer n'importe où (de préférence avant la validation):
<html>
<? if($imagecode) { ?>
<? echo "$imagecoden"?><input type="text" name="vateuf" size="<?= $nbrchars?>" maxlength="<?= $nbrchars?>" value="<?= htmlentities($_POST['vateuf'],ENT_QUOTES)?>">
 Recopiez les caractères à gauche SVP <a href="<?= $_SERVER['PHP_SELF']."?newcode=1"?>">Nouveau</a>
<? } ?>
</html>
Le_gemaux a commenté le 13.09.2007

Bonsoir
merci pour ce script très pratique !
je désir enlever la case téléphon et ne laisser que le nom (ou pseudo) + l'adresse mail, j'ai simplement effacé la case Tel mais le script a buggué... rien ne s'affiche sur le navigateur (page blanche)

pouvez vous m'aider svp ?

Merci à vous

Roger1664 a commenté le 31.07.2007

Magnifique script !!! Et très réactif...

Didier a commenté le 05.04.2007

Bonjour,
juste une petite question : peut-on récuperer les données du formulaire et les afficher dans la page de redirection ? Merci.

Réponse : vous pouvez choisir d'afficher le message dans le formulaire (sans redirection) en prenant soin d'utiliser strip_tags et htmlentities pour éviter l'injection de code. Pour convertir les sauts de ligne : nl2br.

Capo a commenté le 07.02.2007

Désolé, j'ai trouvé mon erreur... Une bétise de "/"
Désolé et encore merci pour ce script !!!
ps : Ce script d'article commentable me plait... C'est qui, C'est ou? C'est vous ?...

Réponse du webmestre :
Ce script est entièrement développé par mes soins. Merci.

Capo a commenté le 07.02.2007

Bonjour Pierre, Bonjour tout le monde...

Alors avant de commencer, je vais vous signaler que je débute dans le "Webmastering" en général... Autrement dit je ne vois pas spécialement de différence entre tous les languages..

Mais bon j'ai quand même reussi a faire quelque chose de pas mal que je mettrais en ligne surement prochainement...

VOICI MA QUESTION :

"Pourquoi crée t-on un dossier 'upload' si les pieces jointes sont envoyées sur ma boite mail ?"

En fait je voudrais que les fichiers atterissent directement sur MON serveur afin de ne pas a les "re-uploader" si je veux les mettre en ligne tot ou tard , mais que j'ai juste a les déplacer dans un autre dossier...

Peut etre que je dis une bétise, je m'en excuse auparavant.... mais j'ai vraiment du mal a tout comprendre dans le code (je parle des codes en général, celui ci a l'avantage de convenir a tout le monde, et c'est parfaitement ce que je cherchais, ca m'évite de faire valider 2 formulaires differents a mes visiteurs...

En attendant une réponse de quelqu'un, Je vous remercie tous et Monsieur Pierre en particulier. Je trouve ca bien de faire partager le fruit de son labeur... Bravo.

A bientot !!

Denis a.k.a Capo

Michel a commenté le 30.11.2006

Merci pour cette application de formulaire avec pièce jointe que j'essaie d'utiliser.
Je butte néanmoins sur un point...
Si je fais une erreur (exprès pour un test) dans la saisie, un message m'alerte et me dit quel champ n'est pas bon. Par contre, l'adresse du fichier joint disparait ??
Avez-vous une solution pour ce problème ?
Merci
Michel

Réponse du webmestre :
Malheureusement non, pas à ma connaissance. Il faut détecter que l'upload de fichier a été demandé et, en car d'erreur, avertir l'utilisateur de le recharger.
Sinon, faire l'upload en deuxième phase (une fois que le formulaire est validé). Ce que font certains sites.

Denis a commenté le 09.11.2006

Bonjour et merci pour le script.
Cependant il est utile de signaler aux lecteurs que :

$rep est égal à "/" tout court et non pas à "upload/"

Ceci m'a couté deux jours de recherche ... mais en même temps m'a permi d'approfondir mes connaissances en PHP

bonne suite

Réponse du webmestre :
Non Denis : $rep vaut le nom du répertoire que vous aurez choisi pour l'upload.
Si $rep = "upload/" le répertoire "upload" est à créer en FTP (ce n'est peut être pas implicite pour le béotien).
Si $rep = "/" les fichiers seront placées à la racine du site. Pourquoi pas...

Lout a commenté le 12.10.2006

bonjour,
il marche trés bien et t'il possible de faire plusieurs envoient de pièces jointes avec ce script?
si oui comment doit-on procéder?
merci d'avance.

Nonel a commenté le 30.09.2006

Bonjour Pierre,
Félicitation pour votre code ... magnifique et extrêmement facile d'utilisation.

Par contre je me pose des questions au niveau de la sécurité de votre code.
Est il mis à jour régulièrement ? Et la protection est elle suffisante contre les injections SQL et autre joyeuseté de ce genre.
Merci d'avance.

Réponse du webmestre :
Pour le spam voir le formulaire anti-spam, ici même. Pour ce qui concerne l'injection de données SQL, ce scipt n'utilise pas de bdd...

NSH a commenté le 12.09.2006

Merci. Implémenté pour l'envoi de communication sur le site d'un congrès scientifique. J'ai bien sur laissé les sources. ;)

NIMBUS a commenté le 11.09.2006

Bonjour,
J'ai inserer le formulaire dans ma page tout fonctionne au poil, mais je n'ai pas le script "téléchargement de fichier"
QUE PUIS JE FAIRE ?

Réponse du webmestre :
Tu as dû oublier de créer et/ou définir le répertoire $rep. Si ce dernier n'est pas conforme, l'option upload n'est pas activée.

SBégouin a commenté le 11.08.2006
Une petite rectification pour mime_content_type :
<?
				function GetExtensionName($File)
				{
  					return strtolower(substr($File, strrpos($File, '.')));
				}
				
				function mime_content_type($fichier)
				{
					# ajouter autant de combinaisons que souhaitées
					$mime = array(
					'.gif' => 'image/gif',
					'.jpg' => 'image/jpeg',
					'.psd' => 'image/x-xwd',
					'.png' => 'image/png',
					'.txt' => 'text/plain',
					'.doc' => 'application/msword',
					'.xls' => 'application/vnd.ms-excel',
					);
					if (!isset($mime[GetExtensionName($fichier)]))
					{
						return "application/octet-stream";
					}
					else
					{
						return $mime[GetExtensionName($fichier)];
					}
				}
?>
Griggione a commenté le 12.05.2006

Bonsoir tous

Merci Pierre pour ta réponse!

Si je recharchais la sécurité, le titre de formulaire sans javascript a de suite retenu mon attention, désireux de garder l'xtml+css+un peu de php.
Le soucis des validateurs, notamment celui du WAI pour les handicaps.

Reprenons dans l'ordre:
1/ oui mais comme dit avant, le lien vers le formulaire sera dans plusieurs pages.Et meme il y aura deux formulaires, l'un avec plus de champs textes.
Se sera un site de tutos et donc, de temps en temps, au milieu du texte, je vais faire un lien pour les questions.
D'ou mon soucis de revenir sur le point exact.
Si je prend le tutoriel sur l'Embedded, 6pages, 80 photos, il serait fastidieux de revenir a la page index et refaire la recherche.
Bien sur, comme le php n'est pas mon copain, si la possibilité existe, je suis partant de suite.

2/J'ai suivi les conseils, bien sur, et appliqué les changements.
Le resultat plus loin.

3/J'avais testé avant la réponse pour le Doctype et pas de probleme.
J'ai aussi appliqué le rajout de code.
Mais le xhtml+css sont mes copains.

Avoir un beau script bien sécurisé et sans JS est une chose.
Garder le style de son site aussi.
J'ai respecté le code, joué sur le style seulement et tout marche bien pour l'instant.
Je m'y suis mis, et soyons honnete, c'est 5h qu'il m'a fallu, toujours ce probleme de copinage avec php, mais on avance bien dans nos relations. :D

Voila, je vous livre le résultat et poserais quelques questions, car je suis un peu bloqué pour l'instant.

http://griggione.free.fr/web/pics1/site9.png

1/ comment faire pour redimensionner le champ de Objet
2/ comment faire pour donner un lien vers le fichier css pour styliser le message de reponse bien envoyé, etc.....
3/ .....déja vu pour revenir à la page voulue.

Voila, et une fois fini ces modifs, je m'attaque aux parties upload et protection anti-spam.

Non Pierre, pas sur la tete.

Griggione a commenté le 11.05.2006
Bonjour

Un nouveau fan pour ce script  :D 

Pourquoi,ben parce en recherche d'un script sécurisé, Google m'a donné ce lien.
Et pour de bon c'est notre ami.  ;) 

Quelques questions du nembie de service:

1/ j'ai esayé de mettre onClick='history.go()' pour revenir à la page en cours (le lien formulaire sera sur plusieurs pages),ça passe pas.

2/ Si je comprend bien,pour retirer ou mettre une obligation de remplir un champ,il faut enlever dans: # vérification des champs requis (Nom, Objet, Message, Email ou Tel) 
Et je suppose rectifier le numero de: $focus = 5;

3/Peut-on changer le Doctype sans probleme,puisque je suis en (x)HTML 1.0....normalement oui.

En tout cas merci pour ce script qui va surement prendre sa place dans le site.
Et l'url dans la page lien  ;) 

Réponse du webmestre :
1. je ne vois pas trop l'intérêt d'utiliser du javascript.

2. dans le code PHP ajouter/supprimer :
if (empty($_POST['nom_du_champ'])) {
  $erreur = "Merci de renseigner nom_du_champ";
  $focus = id_erreur;
}
Dans la balise HTML du champ concerné ajouter/supprimer :
<input name="nom_du_champ"<? if($focus == id_erreur) echo " class="focus"";?>>

3. vérifier les balises non fermantes (ex. <br />), ajouter </option> dans le menu déroulant, vérifier le code avec Tidy.
Rvb a commenté le 08.05.2006

Bon , c'est tapis rouge respect et dans le plus pur esprit open source.Voila des contributions simples fonctionnelles utilisables même par un débutant comme moi....je ne saurais qu'encourager de telles initiatives rarement de ce niveau!!!!
Bravo et merci
Hervé

Bertrand3478 a commenté le 11.04.2006

Un grand merci!

Je débute en php (je suis webdesigner, mais je n'aime pas trop mettre le nez dans le code) et j'aimerais savoir si ce code est facilement modifiable pour permettre l'upload de 2 fichiers.

Merci d'avance

AkhenatonXP a commenté le 02.04.2006

Très bon script, même pour un amateur ;)

cependant, j'ai un message d'erreur pour tous les objets de mon formulaire :

Notice: Undefined index: Message in contact.php on line 259

J'utilise le formulaire original, mis à jour avec mon adresse mail et ma page de redirection, ces tests s'effectuent en local avec easyphp. Les mails partent bien, je les reçois et si les 2 champs obligatoires ne sont pas remplis, j'ai bien les champs "jaunes".
Même en tentant d'initialiser des valeurs avec l'appel de la page contact.php?Nom=&.... :/

Merci pour ce superbe code et toutes les explications très claires qui vont avec.

Jari a commenté le 29.03.2006

Dommage que la mise en oeuvre soit compliquée. Ce serait peut être mieux de mettre tous les fichiers nécessaires dans le zip et un ReadMe. Script trés intéressant mais mise en application à revoir.

Bounounours a commenté le 16.03.2006
bonjour,
tres tres bien votre formulaire le meilleur jamais vu, mais un pour un debutant en php , tres difficile de rajouter des cases a cocher et des selects sans exemples surtout si on veut que certains ne soient pas obligatoires. j'ai essayer de faire un select mais ils m'envoie les numeros du tableau pas les variables.
ce serait vraiment cool un exemple avec tous ce qu'on peux imaginer de mettre dedans.

amicalement
bounounours qui pousse un peu il est vrai :O)

Réponse du webmestre :
<?php
/******* Ajout d'un menu déroulant *******/
# au début du script, déclaration du tableau
# option menu déroulant 'Choix'
# ajout d'option : 'n'=>'Choix 1', 'n+1'=>'Choix 2',
# la première ligne (optionnelle) impose un choix
$selecteur = array(
    0 => 'Choisissez',
    1 => 'Choix 1',
    2 => 'Choix 2',
    3 => 'Choix 3',
);

/* après if ($_POST) seulement si $selecteur[0] = 0 */
if (!$_POST['Choix']) {
    $erreur = "Merci de renseigner Choix";
    $focus = 20; # valeur différente des autres $focus
}
?>

<!-- dans le formulaire -->
<p><label for="Choix">Choix</label>
<select name='Choix' <? if($focus == 20) echo "class="focus"";?> id="Choix">
<?
foreach($selecteur as $key => $val) {
    echo "  <option value='$key'";
    if($key == $_POST['Choix']) echo " selected";
    echo ">$valn";
}
?>
</select></p>
Zeitoun a commenté le 28.02.2006

bonjour
en effet, c'est du tres beau travail

avez vous une solution afin que l'email soit confirmé?
c'est a dire avoir un deuxième champ email qui vérifie que sa valeur soit bien égale a celle du premier?
merci d'avance
zeitoun

Vincz68 a commenté le 20.02.2006

bonjour,

super boulot, vraiment bravo! fontionne nickel!

g un pb, et pas seulement avec votre formulaire (cela fait 3 jours que j'essaie): quand je joints un fichier de plus de 300ko, j'ai un échec d'envoie du mail; comme si il y avait un timeout (soit dans le traitement, soit dans l'upload chez mon hébergeur). L'upload se passe bien car je peux sauver mon fichier (jusqu'à 2Mo) et le retrouver chez mon hebergeur. peut-être que vous pourrez me donner une solution... vue vos connaissances en envoie de mail.
Merci. Vincent
(NDLA : problème ponctuel résolu)

Kevin a commenté le 11.01.2006
bonjour,
comment on fait pour ajouter des cases à cocher ?
tres bien ce formulaire!
merci

Réponse du webmestre :
<?php
if ($_POST) {
    if (!$_POST['jailu']) {
        $erreur = "Merci de cliquer la case à cocher";
    }
}
?>
<? if (!$_POST || $erreur) { ?>
    <input type="checkbox" name="jailu" value="1" <? if($_POST['jailu']) echo "checked"?>> J'ai lu et approuvé
<? } ?>

[Réagir à cet article]

http://dev.ppan.net [Haut de page] [Document mis à jour le 07.01.2011]