Jump to content

[RESOLU] Créer un formulaire avec possibilité d'attacher une pièce-jointe


Recommended Posts

Bonjour,

 

J'ai rajouté un petit formulaire à la page de détail produit. Je ne rencontre pas de problèmes particuliers avec les champs textes, les listes déroulantes etc... En revanche, je n'arrive pas à faire fonctionner l'envoi de pièces jointes (elles ne sont pas envoyées sur le serveur, si j'en crois la rapidité avec laquelle le formulaire est traité; et c'est confirmé : puisqu'elles ne sont pas dans le dossier Uploads...).

 

Je me suis inspiré du formulaire de contact d'origine et voici ce que j'ai fait (je ne mets pas les codes complets, histoire de gagner du temps) :

 

themes/mon_theme/product.tpl

<form action="{$request_uri|escape:'htmlall':'UTF-8'}" method="post">
(...)
<label for="fileUpload">{l s='Attach File'}</label>
<input type="hidden" name="MAX_FILE_SIZE" value="2000000" />
<input type="file" name="fileUpload" id="fileUpload" />
(...)
<input type="submit" name="submitMessage" id="submitMessage" value="Envoyer" class="exclusive"/>
</form>

 

controllers/front/ProductController.php

public function postProcess()
{
	if (Tools::isSubmit('submitMessage'))
   {
	 $fileAttachment = null;
  if (isset($_FILES['fileUpload']['name']) && !empty($_FILES['fileUpload']['name']) && !empty($_FILES['fileUpload']['tmp_name']))
  {
$extension = array('.txt', '.rtf', '.doc', '.docx', '.pdf', '.zip', '.png', '.jpeg', '.gif', '.jpg');
$filename = uniqid().substr($_FILES['fileUpload']['name'], -5);
$fileAttachment['content'] = file_get_contents($_FILES['fileUpload']['tmp_name']);
$fileAttachment['name'] = $_FILES['fileUpload']['name'];
$fileAttachment['mime'] = $_FILES['fileUpload']['type'];
  }
(...)
if (!empty($_FILES['fileUpload']['name']) && $_FILES['fileUpload']['error'] != 0)
			$this->errors[] = Tools::displayError('An error occurred during the file-upload process.');
		elseif (!empty($_FILES['fileUpload']['name']) && !in_array(substr(Tools::strtolower($_FILES['fileUpload']['name']), -4), $extension) && !in_array(substr(Tools::strtolower($_FILES['fileUpload']['name']), -5), $extension))
			$this->errors[] = Tools::displayError('Bad file extension');
(...)
if (!empty($contact->email))
		   {
			   if (Mail::Send((int)self::$cookie->id_lang, 'contact2', Mail::l('Demande information produit', (int)self::$cookie->id_lang),
				   array(
					   (...)
					   '{attached_file}' => isset($_FILES['fileUpload'], $_FILES['fileUpload']['name']) ? $_FILES['fileUpload']['name'] : '',
					   '{message}' => stripslashes($message)
					   ),

				   $contact->email, $contact->name, $from, $fileAttachment)
AND Mail::Send((int)self::$cookie->id_lang, 'contact_form', Mail::l('Your message has been correctly sent', (int)self::$cookie->id_lang), array('{message}' => stripslashes($message)), $from))
				   self::$smarty->assign('confirmation', 1);
			   else
				   $this->errors[] = Tools::displayError('An error occurred while sending message.');
		   }
}

 

Si je compare mon fichier du controller à celui de contact (ContactController.php), je constate qu'il me manque quelque-chose comme ca

elseif (isset($filename) && rename($_FILES['fileUpload']['tmp_name'], _PS_MODULE_DIR_.'../upload/'.$filename))
   $cm->file_name = $filename;

 

Ca semble être le code qui définit où sont "uploadées" les pièces-jointes, mais dans ce code "$cm" pose un problème dans mon script puisque je ne sais pas trop à quoi il se réfère? Et surtout je ne sais pas comment l'utiliser dans mon cas?

 

Merci d'avance!

Edited by Nicks (see edit history)
Link to comment
Share on other sites

Merci Matt75,

 

Effectivement maintenant je vois que les PJ sont bien envoyées dans le dossier Uploads, en revanche elles ne sont toujours pas attachées au mail...

 

J'ai testé d'afficher la valeur de la pj dans le corps du mail :

'{attached_file}' => isset($_FILES['fileUpload'], $_FILES['fileUpload']['name']) ? $_FILES['fileUpload']['name'] : '',

 

Et j'obtiens dans le mail :

nom_du_ficher.extension (ex: toto.doc)

 

Encore une petite idée? :)

 

Merci!

Link to comment
Share on other sites

Cette ligne est inutile :

'{attached_file}' => isset($_FILES['fileUpload'], $_FILES['fileUpload']['name']) ? $_FILES['fileUpload']['name'] : '',

 

Tu dois transmettre le fichier à la classMail pour qu'il soit mis en pièce jointe, la méthode send de cette class que tu utilises pour envoyer l'email possède un paramètre pour ça et d'ailleurs tu as une variable fileAttachment qui devrait normalement transmettre le fichier.

 

Essaye de faire un die(var_dump($fileAttachment)) avant d'appeler ta class Mail pour vérifier ce que contient cette variable, normalement elle devrait contenir les informations sur ton fichier.

 

Ton code est pas super propre, faudrait nettoyer un peu pour y voir plus clair.

Link to comment
Share on other sites

Encore une fois merci de ton intérêt et pour tes commentaires constructifs (désolé d'avance si tu fais des bonds en lisant ce qui va suivre, je crois toutefois que tu as cerné que je ne suis pas un spécialiste de PHP ;) )

 

J'essaie de transmettre un pdf (test.pdf - 3.42 Ko)

J'ai donc fait

if(isset($fileAttachment)){
	  die(var_dump($fileAttachment));
    }

avant d'appeller la Classe Mail et j'obtiens :

array(3) { ["content"]=> string(3505) "%PDF-1.5 %���� 4 0 obj <> endobj xref 4 5 0000000016 00000 n 0000000524 00000 n 0000000620 00000 n 0000000852 00000 n 0000000396 00000 n trailer <<38A0C59E34438E43996439AA5391D422>]/Prev 3296>> startxref 0 %%EOF 8 0 obj <>stream h�b```b``|��f�������~��f� �@� �n�� endstream endobj 5 0 obj <>>> endobj 6 0 obj <>/Rotate 0/TrimBox[0.0 0.0 1280.0 800.0]/Type/Page>> endobj 7 0 obj <>stream H�0 endstream endobj 1 0 obj <> endobj 2 0 obj <>stream Adobe InDesign CS5 (7.0.4) 2013-05-21T15:54:26+02:00 2013-05-21T15:54:26+02:00 2013-05-21T15:54:26+02:00 uuid:ef71e42b-5a1c-47fe-99d2-fec4ee0b88ce xmp.did:152BB9E01DC2E2118F8291B9931F84D6 xmp.did:152BB9E01DC2E2118F8291B9931F84D6 proof:pdf created xmp.iid:152BB9E01DC2E2118F8291B9931F84D6 2013-05-21T15:53:55+02:00 Adobe InDesign 7.0 application/pdf Adobe PDF Library 9.9 False endstream endobj 3 0 obj <> endobj xref 0 4 0000000000 65535 f 0000000930 00000 n 0000000981 00000 n 0000003121 00000 n trailer <<38A0C59E34438E43996439AA5391D422>]>> startxref 116 %%EOF " ["name"]=> string(8) "test.pdf" ["mime"]=> string(15) "application/pdf" }

 

Après j'admets volontiers que mon code est en bordel, mais à priori tout est là, quand je compare avec ce qui est fait sur le formulaire de contact de base + les autres sujets que j'ai lu traitant de ma problématique.

 

Revoici mon code (un peu mieux organisé)

 

01. themes/montheme/product.tpl

<form action="{$request_uri|escape:'htmlall':'UTF-8'}" method="post" enctype="multipart/form-data">
<!-- Ici les autres champs -->
<label for="fileUpload">{l s='Attach File'}</label>
<input type="hidden" name="MAX_FILE_SIZE" value="2000000" />
<input type="file" name="fileUpload" id="fileUpload" />
<input type="submit" name="submitMessage" id="submitMessage" value="Envoyer" class="exclusive"/>
</form>

 

02. controllers/front/ProductController.php

public function postProcess()
{
    if (Tools::isSubmit('submitMessage'))
   {
	 $fileAttachment = null;
  if (isset($_FILES['fileUpload']['name']) && !empty($_FILES['fileUpload']['name']) && !empty($_FILES['fileUpload']['tmp_name']))
  {
   $extension = array('.txt', '.rtf', '.doc', '.docx', '.pdf', '.zip', '.png', '.jpeg', '.gif', '.jpg');
   $filename = uniqid().substr($_FILES['fileUpload']['name'], -5);
   $fileAttachment['content'] = file_get_contents($_FILES['fileUpload']['tmp_name']);
   $fileAttachment['name'] = $_FILES['fileUpload']['name'];
   $fileAttachment['mime'] = $_FILES['fileUpload']['type'];
  }
	   // ... Ici mes restrictions sur les autres champs...
  //Vérif sur l'envoi de la PJ
	   elseif (!empty($_FILES['fileUpload']['name']) && $_FILES['fileUpload']['error'] != 0)
   $this->errors[] = Tools::displayError('An error occurred during the file-upload process.');
  elseif (!empty($_FILES['fileUpload']['name']) && !in_array(substr(Tools::strtolower($_FILES['fileUpload']['name']), -4), $extension) && !in_array(substr(Tools::strtolower($_FILES['fileUpload']['name']), -5), $extension))
   $this->errors[] = Tools::displayError('Bad file extension');
   }
   if (!empty($contact->email))
		   {
			 //Tableau 'var_list' avec mes champs à faire figurer dans le mail
			 $var_list = array(
    '{email}' => $from,
				   '{client}' => $client,
				   '{id_produit}' => $id_produit,
				   '{societe}' => $societe,
				   '{nom}' => $nom,
				   '{prenom}' => $prenom,
				   '{fonction}' => $fonction,
				   '{secteuractivite}' => $secteuractivite,
				   '{adresse}' => $adresse,
				   '{codepostal}' => $codepostal,
				   '{ville}' => $ville,
				   '{pays}' => $pays,
				   '{tel}' => $tel,
				   '{fax}' => $fax,
				   '{sujet}' => $sujet,
				   //Ci-dessous attached_file ne sert à rien, si ce n'est indiquer le nom de la PJ (nom et extension qui apparaissent bien dans le mail + bien chargé dans /upload)
				   '{attached_file}' => isset($_FILES['fileUpload'], $_FILES['fileUpload']['name']) ? $_FILES['fileUpload']['name'] : '',
				   '{message}' => stripslashes($message)
    );
			   if(
				 // Le mail est envoyé avec les différents champs, j'oublie pas d'ajouter $fileAttachment - je pensais naïvement que ca suffirait 
				 Mail::Send((int)self::$cookie->id_lang, 'contact2', Mail::l('Demande information produit', (int)self::$cookie->id_lang), $var_list, $contact->email, $contact->name, $from, $fileAttachment)
				    AND Mail::Send((int)self::$cookie->id_lang, 'contact_form', Mail::l('Your message has been correctly sent', (int)self::$cookie->id_lang), array('{message}' => stripslashes($message)), $from, $fileAttachment))
				   self::$smarty->assign('confirmation', 1);
			   else
				   $this->errors[] = Tools::displayError('An error occurred while sending message.');
		   }
   }

 

Voilà, et donc le résultat c'est que la PJ est bien envoyée sur le ftp (/upload) mais pas dans le mail...

Link to comment
Share on other sites

Bon ta variable contient bien le fichier joint et elle semble bien transmise à la fonction.

Normalement tu devrais l'avoir en pièce jointe.

Par contre tu utilises un objet $contact à plusieurs reprise alors que je ne vois instancié nul part...

 

En gros tu veux faire un formulaire de contact comme celui de Prestashop mais avec des champs en plus c'est ça ?

Edited by Matt75 (see edit history)
  • Like 1
Link to comment
Share on other sites

$contact est bien instancié c'est juste que je n'ai pas mis tout le code histoire de faciliter la lecture de mon problème.

 

C'est à peut près ca oui, le formulaire de contact avec plus de champs dans la fiche produit pour que je puisse récupérer la variable "product name" (ou product id). L'idée c'est qu'en naviguant sur un produit, si le client aimerait plus de renseignement sur celui-ci il puisse envoyer un mail très simplement depuis la page produit sans avoir à passer par la page contact et devoir noter lui-même la référence du produit (et risquer de se tromper).

 

En tout cas, ca ne marche pas comme ca.

 

Si je continues ma comparaison avec le formulaire de contact d'origine, dans le controller on trouve une autre fonction initContent :

controllers/front/ContactController.php

public function initContent()
{
 parent::initContent();
 $this->assignOrderList();
 $email = Tools::safeOutput(Tools::getValue('from',
 ((isset($this->context->cookie) && isset($this->context->cookie->email) && Validate::isEmail($this->context->cookie->email)) ? $this->context->cookie->email : '')));
 $this->context->smarty->assign(array(
  'errors' => $this->errors,
  'email' => $email,
  'fileupload' => Configuration::get('PS_CUSTOMER_SERVICE_FILE_UPLOAD')
 ));
(...)

 

Je me demande si ca peut jouer? Je pensais jusque-là que c'était ce qui permettait d'afficher les messages dans le BO, non?

Link to comment
Share on other sites

Salut,

 

Bon déjà c'est pas très propre de faire comme tu le fais, c'est-à-dire de mettre du code directement dans le controller Product, il vaudrait mieux faire un module pour ne pas perdre tes modifications après une mise à jour de Prestashop, ensuite récupérer le code du controller Contact n'est pas idéal car il est conçu pour fonctionner avec un ObjectModel Contact dont le but est d'enregistrer les messages dans le BO.

 

Le mieux aurait été de faire un module avec un code totalement indépendant et sans utilisé d'ObjectModel puisque tu veux juste envoyer un Mail et pas stocker en base de données.

 

Le problème quand on est un truc brouillon c'est que quand ça marche pas, c'est difficile d'identifier ce qui ne va pas car c'est le bazar.

 

Concrètement ton formulaire, il est affiché dans la fiche produit ou il faut cliquer sur un lien pour le faire apparaître ?

Parce que bon autant essayer de faire un truc propre, qui fonctionne et qui ne gênera pas les futurs mises à jour.

 

Tu pourrais me dire quels sont les champs que tu veux dans ton formulaire ?

Link to comment
Share on other sites

Voici ci-dessous mes champs, mais franchement t'embêtes pas avec tous, un champs texte et un champs file pour tester et c'est bon...

 

01. Vous êtes* (liste déroulante <select>

=> options : deja client / particulier / entreprise / revendeur.

02. Société* : champs texte

03. Nom* : champs texte

04. Prénom* :champs texte

05. secteur d'activités : champs texte

06. adresse : champs texte

07. Code postal* : champs texte

08. Ville* : champs texte

09. Pays* : champs texte

10. Tel: champs texte

11. email* : champs texte (validation email, champs "from" pour le mail)

12. fax: champs texte

13. Message* : textarea

14. Ajouter une PJ : champs file

15. Envoyer : bouton submit

 

Je n'ai pas encore défini si le formulaire s'affiche dans la page ou si un bouton renvoit vers une page externe. Mais les deux me vont, donc j'aurai tendance à dire : allons au plus simple!

 

Merci encore pour ton aide précieuse. Je me forme à PHP mais je commence par du procédurale et les quelques connaissances que celà m'apporte ne me servent quasiment à rien quand je suis confronté à des applis en MVC comme PS...

Edited by Nicks (see edit history)
Link to comment
Share on other sites

Quels sont les champs obligatoires ?

Au lieu de redirigé vers une page externe, on peut ouvrir une fenêtre modal comme le module Envoyer à un ami

 

Cela fait beaucoup de champs à remplir, tu devrais peut être envisager de cacher certains champs si la personne est connecté et que ces champs sont déjà renseignés dans son compte ou alors les pré-remplir avec les infos déjà présente dans le compte.

Les gens n'aiment pas remplir les formulaires, donc si ils ont trop de champs à remplir une majorité d'entre eux ne le fera pas.

Link to comment
Share on other sites

J'ai rajouté des * pour les champs obligatoires.

 

Je suis sensible à tes remarques pour améliorer l’expérience utilisateur, tout comme il faudra également que je conditionne certains champs en valeurs numériques (code postal, numéro de tel...). J'ai pensé à la popup aussi, ou une div en display:none qui passe en display:block après un clic sur un bouton etc...

 

Si je n'ai pas précisé tout cela c'est simplement pour ne pas faire fuir les gens comme toi prêt à me filer un coup de pouce, donc je me cantonne à l'essentiel :)

Link to comment
Share on other sites

Salut,

 

Bon j'ai fais un mix de plusieurs de mes modules pour faire un truc qui colle a ton besoin.

 

Mon module ajoute un lien sur la fiche de produit nommé "Nous contacter à propos de ce produit", que tu pourras modifier dans les traductions si besoin.

Lors d'un clic sur ce lien, un popup s'ouvre avec le formulaire de contact.

Une fois le formulaire valide, un email est envoyé à l'adresse indiqué dans la configuration du module avec la pièce jointe.

Compatible uniquement Prestashop 1.5 (Module MVC et helpers)

 

Pour télécharger le module, me contacter.

 

A+

Edited by Matt75 (see edit history)
  • Like 1
Link to comment
Share on other sites

Salut,

 

Déjà, les mots me manquent pour te remercier comme il se doit, mais vraiment c'est extrêmement généreux de ta part :)

 

Ensuite, j'ai donc téléchargé ton module que j'ai installé et testé.

Et malheureusement je suis confronté à un petit problème, je n'arrive pas à envoyer le mail.

J'ai essayé une première fois en remplissant tous les champs (PJ comprise) puis une seconde en ne remplissant que les champs obligatoires et j'ai invariablement la même erreur :

 

1. Failed to send email

 

J'ai essayé en réactivant le thème par défaut de Prestashop et en modifiant les droits sur le module, mais sans succès.

 

J'ai trouvé les lignes où tu conditionne l'affichage de cette erreur :

modules/productcontact/controllers/front/defaults.php (l.138)

if (file_exists(_PS_MODULE_DIR_.$this->module->name.'/mails/'.$iso.'/productcontact.txt') && file_exists(_PS_MODULE_DIR_.$this->module->name.'/mails/'.$iso.'/productcontact.html'))
 if (!Mail::Send((int)Configuration::get('PS_LANG_DEFAULT'), 'productcontact', Mail::l('Product contact form', $id_lang), $templateVars, strval(Configuration::get('BETTERPRICE_EMAIL')), strval(Configuration::get('PS_SHOP_NAME')), strval($productcontact_email), strval($productcontact_firstname).strval($productcontact_lastname), $attachment, NULL, _PS_MODULE_DIR_.$this->module->name.'/mails/'))
  $return['errors'][] = $this->module->l('Failed to send email');

 

J'utilise Prestashop 1.5.4.1

Link to comment
Share on other sites

Re!

 

Cette fois c'est tout bon :)

 

J'ai testé avec et sans PJ, ca marche parfaitement bien

 

Encore une fois merci infiniment pour ton temps et ton travail, je suis certain que ton module va servir à beaucoup de monde!

Link to comment
Share on other sites

Je n'ai clairement pas le niveau pour saisir toutes les subtilités de ton code, mais je te confirme que rien qu'au niveau de l'indentation et de l'organisation du code c'est très organisé donc bien lisible.

 

Tu aurais des ressources à conseiller (tuto, livres, videos?) pour qui veut apprendre le modèle MVC? (j'ai lu le cours sur la POO sur le siteduzero (http://www.siteduzero.com/informatique/tutoriels/programmez-en-oriente-objet-en-php) mais j'ai pas réussi à faire fonctionner l'application... )

Link to comment
Share on other sites

Concernant Prestashop, les ressources pour apprendre sont quasi nulles. (la documentation est très pauvre)

 

Néanmoins certains dev partagent leurs connaissances comme J.Danse qui a publié un canvas de module qui a servit à beaucoup de monde, d'autres ont créé leur propre documentation, certains publient parfois des trucs & astuces.

 

Moi généralement je mets à disposition de le code de certains de mes modules (Ceux qui n'ont qu'un faible potentiel de vente et qui présentent un intérêt concernant l'implémentation de telle ou telle possibilité)

 

Pour le PHP en général, y a le site du zéro qui vulgarise assez bien, pour les tutoriels vidéos il y a grafikart et concernant les bouquins, il y en a pas mal mais je trouve pas ça très utile.

Link to comment
Share on other sites

Ok je prends note des ressources (je connaissais déjà lesiteduzero et grafikart aussi qui est très bien certes, mais si t'es super débutant il manque "un fil rouge" je dirai, je suis assez vite perdu rien que dans la classification des vidéos en tout cas).

 

Allez je vais de ce pas me former... ;)

 

@+

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...