CakePHP-Fr.Org

Forum francophone du Framework CakePHP

Vous n'êtes pas identifié.

#1 04-02-2015 19:38:39

iwn
Pitivier
Lieu: La Rochelle
Date d'inscription: 22-01-2015
Messages: 18
Site web

[RESOLU] V3-RC1 --- Perte des données input file on error

Bonsoir à tous
Quand je fais un insert ou update avec des champs input de type file, et qu'une erreur est détecter avec le validate, les données ne sont perdues dans le retour du form.

Aussi bien sur un simple upload ou un muti-upload.....
Je tourne en rond depuis ce matin sur ce bug .....

pour info:
le controlleur :

Code: php

  1.  public function write($id){
  2.  
  3.     $this->loadModel('Users');
  4.  
  5.     $user = $this->Users->get($id);
  6.  
  7.     if(is_null($user)){
  8.  
  9.       $this->Flash->error(__("Cet utilisateur n'existe pas ou n'est pas actif !"));
  10.       return $this->redirect($this->referer());
  11.  
  12.     }
  13.  
  14.     $message  = $this->Messages->newEntity();
  15.     $message->referer = $this->referer();
  16.  
  17.     if($this->request->is('post')){
  18.       $message  = $this->Messages->newEntity($this->request->data, ['validate' => 'create']);
  19.       $message->from_user_id = $this->Auth->user('id');
  20.       $message->created_ip = $this->request->clientIp();
  21.  
  22.       foreach ($message->attachments as $key => $attachment) {
  23.  
  24.         if((!empty($attachment)) && ($attachment['error'] === 0)){
  25.           $e = 0;
  26.           $file = new File($attachment['name'], false, 0644);
  27.  
  28.           if(($attachment['type'] != 'image/jpeg') && ($attachment['type'] != 'image/png')){
  29.             $message->errors('attachments[' . $key . ']', [__("Type de fichier invalide.")]);
  30.             $e = 1;
  31.           }
  32.  
  33.           if(($file->ext() != 'jpg') && ($file->ext() != 'png')){
  34.             $message->errors('attachments[' . $key . ']', [__("Les extentions sont {0}.", '.jpg, et .png')]);
  35.             $e = 1;          
  36.           }
  37.  
  38.           if($attachment['error'] > 2000000){
  39.             $message->errors('attachments[' . $key . ']', [__("Le fichier a une taille superieure à {0}", '2MB')]);
  40.             $e = 1;        
  41.           }
  42.  
  43.           if($e == 1){
  44.             $message->attachments[$key] = [
  45.                                   'name' => '',
  46.                                   'type' => '',
  47.                                   'tmp_name' => '',
  48.                                   'error' => (int) 4,
  49.                                   'size' => (int) 0
  50.                                 ];
  51.           }
  52.         }
  53.  
  54.       }
  55.  
  56.       if ($this->Messages->save($message)) {
  57.  
  58.         foreach ($message->attachments as $attachment) {
  59.  
  60.           if($attachment['error'] === 0){
  61.             $this->loadModel('MessagesAttachments');
  62.            
  63.             $file = new File($attachment['tmp_name'], false, 0644);
  64.             $file_ext = (new File($attachment['name'], false, 0644))->ext();
  65.             $new_file_name = md5(rand() . uniqid() . time()) . '_' . $message->id . '_' . $message->to_user_id .'_' . $message->from_user_id . '.' . $file_ext;
  66.             $data = [
  67.                       'attachment' => $attachment,
  68.                       'message_id' => $message->id,
  69.                       'file' => $new_file_name
  70.                     ];           
  71.  
  72.             $query  = $this->MessagesAttachments->newEntity($data, ['validate' => 'MessageAttachment']);
  73.  
  74.             if($this->MessagesAttachments->save($query)) {
  75.  
  76.               $file->copy(WWW_ROOT . 'img/messages_attachments/' . $new_file_name, true);
  77.  
  78.             } else {
  79.  
  80.               $query = $this->MessagesAttachments->query();
  81.               $query->delete()
  82.                 ->where(['message_id' => $message->id, 'created_by' => $message->from_user_id])
  83.                 ->execute();
  84.  
  85.               unlink(WWW_ROOT . 'img/messages_attachments/*_' . $message->id . '_' . $message->to_user_id .'_' . $message->from_user_id . '.*')
  86.              
  87.               $this->Messages->delete($message);
  88.  
  89.               $this->Flash->error(__("Vous avez tenter d'envoyer un fichier non autorisé.<br>Le message a été supprimé."));
  90.               return $this->redirect($message->referer);
  91.            
  92.             }
  93.  
  94.           }
  95.  
  96.         } 
  97.  
  98.         $this->Flash->success(__("Votre message à été correctement envoyé."));
  99.         return $this->redirect($message->referer);
  100.      
  101.       } else {
  102.  
  103.         $this->Flash->error(__("Merci de corriger vos erreurs."))
  104.      
  105.       } 
  106.  
  107.     }
  108.  
  109.     $this->set(compact('message', 'user'));
  110.  
  111.   }

la vue :

Code: php

  1. <div class="container-fluid" id="contact">
  2.   <section class="container">
  3.     <div class="row">
  4.       <div class="col-xs-12 col-sm-10 col-sm-offset-1 pt-40">
  5.        <div class="well">
  6.           <legend>Envoyer un message à <?= $user->username?></legend>
  7.           <?= $this->Form->create($message, ['type' => 'file']) ?>
  8.             <?= $this->Form->input('to_user_id', ['required' => true, 'label' => false, 'default' => $user->id, 'type' => 'hidden']) ?>
  9.             <?= $this->Form->input('referer', ['required' => true, 'label' => false, 'default' => $message->referer, 'type' => 'hidden']) ?>
  10.             <div class="row">
  11.               <div class="form-group col-sm-6">
  12.                 <label for="objet" class="control-label">Objet de votre message :</label>
  13.                 <?= $this->Form->input('title', ['label' => false, 'class' => 'form-control']) ?>
  14.               </div>
  15.             </div>            
  16.             <div class="row">              
  17.               <div class="form-group col-sm-12">
  18.                 <label for="message" class="control-label">Votre message :</label>
  19.                 <?= $this->Form->input('content', ['type' => 'textarea' ,'label' => false, 'class' => 'form-control']) ?>
  20.               </div>              
  21.             </div>
  22.             <label for="upload" class="control-label">Pièce jointe : (<span class="text-warning small">Uniquement des fichiers images en format jpg ou png et de moins de 2Mo.</span>)</label>
  23.             <? if ($this->Form->isFieldError('attachments')) { echo $this->Form->error('attachments'); } ?>
  24.     <?php if(!$this->request->is('mobile')){ ?>
  25.             <div class="row">
  26.               <div class="form-group col-sm-3">
  27.                 <div class="fileinput fileinput-new" data-provides="fileinput">
  28.                   <div class="fileinput-new thumbnail" style="width: 200px; height: 200px;">
  29.                   <?php
  30.                    if(isset($message->attachments[0]['name'])){
  31.                       echo $this->Html->image('https://www.placehold.it/200x200/EFEFEF/AAAAAA&text=' . $message['attachments'][0]['name'], ['escape' => false]);
  32.                     } else {
  33.                       echo $this->Html->image('https://www.placehold.it/200x200/EFEFEF/AAAAAA&text=no+image', ['escape' => false]);
  34.                     }
  35.                   ?>
  36.                   </div>
  37.                   <div class="fileinput-preview fileinput-exists thumbnail" style="width: 200px; height: 200px;"></div>
  38.                   <div>
  39.                     <span class="btn btn-default btn-file">
  40.                       <span class="fileinput-new"><?= __("Choisir image") ?></span>
  41.                       <span class="fileinput-exists"><?= __("Modifier") ?></span>
  42.                       <?= $this->Form->input('attachments[0]', ['type' => 'file', 'accept' => 'image/*',
  43.                                                                 'label' => false,
  44.                                                                 'templates' => ['inputContainer' => '{{content}}</span>', 'inputContainerError' => '{{content}}</span>{{error}}'],
  45.                                                                 'default' => $message['attachments'][0]
  46.                                                                ]) ?>
  47.                     </span>
  48.                     <a href="#" class="btn btn-danger fileinput-exists" data-dismiss="fileinput"><?= __("Supprimer") ?></a>
  49.                   </div>
  50.                 </div>
  51.               </div>
  52.               <div class="form-group col-sm-3">
  53.                 <div class="fileinput fileinput-new" data-provides="fileinput">
  54.                   <div class="fileinput-preview thumbnail" style="width: 200px; height: 200px;">
  55.                   <?php
  56.                    if(!is_null($message->attachments[1]['name'])){
  57.                       echo $this->Html->image('https://www.placehold.it/200x200/EFEFEF/AAAAAA&text=' . $message['attachments'][1]['name'], ['escape' => false]);
  58.                     } else {
  59.                       echo $this->Html->image('https://www.placehold.it/200x200/EFEFEF/AAAAAA&text=no+image', ['escape' => false]);
  60.                     }
  61.                   ?>                    
  62.                   </div>
  63.                   <div>
  64.                     <span class="btn btn-default btn-file">
  65.                       <span class="fileinput-new"><?= __("Choisir image") ?></span>
  66.                       <span class="fileinput-exists"><?= __("Modifier") ?></span>
  67.                       <?= $this->Form->input('attachments[1]', ['type' => 'file', 'label' => false, 'templates' => ['inputContainer' => '{{content}}</span>', 'inputContainerError' => '{{content}}</span>{{error}}']]) ?>
  68.                     </span>
  69.                     <a href="#" class="btn btn-danger fileinput-exists" data-dismiss="fileinput"><?= __("Supprimer") ?></a>
  70.                   </div>
  71.                 </div>
  72.               </div>
  73.               <div class="form-group col-sm-3">
  74.                 <div class="fileinput fileinput-new" data-provides="fileinput">
  75.                   <div class="fileinput-preview thumbnail" style="width: 200px; height: 200px;"></div>
  76.                   <div>
  77.                     <span class="btn btn-default btn-file">
  78.                       <span class="fileinput-new"><?= __("Choisir image") ?></span>
  79.                       <span class="fileinput-exists"><?= __("Modifier") ?></span>
  80.                       <?= $this->Form->input('attachments[2]', ['type' => 'file', 'label' => false, 'templates' => ['inputContainer' => '{{content}}</span>', 'inputContainerError' => '{{content}}</span>{{error}}']]) ?>
  81.                     </span>
  82.                     <a href="#" class="btn btn-danger fileinput-exists" data-dismiss="fileinput"><?= __("Supprimer") ?></a>
  83.                   </div>
  84.                 </div>
  85.               </div>
  86.               <div class="form-group col-sm-3">
  87.                 <div class="fileinput fileinput-new" data-provides="fileinput">
  88.                   <div class="fileinput-preview thumbnail" style="width: 200px; height: 200px;"></div>
  89.                   <div>
  90.                     <span class="btn btn-default btn-file">
  91.                       <span class="fileinput-new"><?= __("Choisir image") ?></span>
  92.                       <span class="fileinput-exists"><?= __("Modifier") ?></span>
  93.                       <?= $this->Form->input('attachments[3]', ['type' => 'file', 'label' => false, 'templates' => ['inputContainer' => '{{content}}</span>', 'inputContainerError' => '{{content}}</span>{{error}}']]) ?>
  94.                     </span>
  95.                     <a href="#" class="btn btn-danger fileinput-exists" data-dismiss="fileinput"><?= __("Supprimer") ?></a>
  96.                   </div>
  97.                 </div>
  98.               </div>                                          
  99.             </div>
  100.     <?php
  101.       } else {
  102.     ?>
  103.             <div class="row">
  104.               <div class="form-group col-xs-6">
  105.                 <div class="fileinput fileinput-new" data-provides="fileinput">
  106.                   <div class="fileinput-preview fileinput-exists thumbnail" style="max-width: 200px; max-height: 200px;"></div>
  107.                   <div>
  108.                     <span class="btn btn-default btn-file">
  109.                       <span class="fileinput-new"><?= __("Choisir image") ?></span>
  110.                       <span class="fileinput-exists"><?= __("Modifier") ?></span>
  111.                       <?= $this->Form->input('attachment[0]', ['type' => 'file', 'label' => false, 'templates' => ['inputContainer' => '{{content}}</span>', 'inputContainerError' => '{{content}}</span>{{error}}']]) ?>
  112.                     </span>
  113.                     <a href="#" class="btn btn-danger fileinput-exists" data-dismiss="fileinput"><?= __("Supprimer") ?></a>
  114.                   </div>
  115.                 </div>
  116.               </div>
  117.               <div class="form-group col-xs-6">
  118.                 <div class="fileinput fileinput-new" data-provides="fileinput">
  119.                   <div class="fileinput-preview fileinput-exists thumbnail" style="max-width: 200px; max-height: 200px;"></div>
  120.                   <div>
  121.                     <span class="btn btn-default btn-file">
  122.                       <span class="fileinput-new"><?= __("Choisir image") ?></span>
  123.                       <span class="fileinput-exists"><?= __("Modifier") ?></span>
  124.                       <?= $this->Form->input('attachment[1]', ['type' => 'file', 'label' => false, 'templates' => ['inputContainer' => '{{content}}</span>', 'inputContainerError' => '{{content}}</span>{{error}}']]) ?>
  125.                     </span>
  126.                     <a href="#" class="btn btn-danger fileinput-exists" data-dismiss="fileinput"><?= __("Supprimer") ?></a>
  127.                   </div>
  128.                 </div>
  129.               </div>
  130.     <?php } ?>              
  131.             <hr>
  132.             <div class="row text-center">
  133.               <?= $this->Form->button('Envoyer', ['type' => 'submit', 'class' => 'btn btn-success']) ?>
  134.             </div>                
  135.           <?= $this->Form->end(); ?>
  136.         </div>
  137.       </div>
  138.     </div>
  139.   </section>
  140. </div>
  141. <?= $this->Html->css('/assets/jasny-bootstrap-3.1.3/dist/css/jasny-bootstrap.min', ['block' => 'css']) ?>
  142. <?= $this->Html->script('/assets/jasny-bootstrap-3.1.3/dist/js/jasny-bootstrap.min', ['block' => 'script']) ?>

Si y a du debug ..... c'est normal ! lol

A toi mon ami Cake17 .... On est peut être voisin lol !


Passez à la V3 .... que du BONHEUR !!!

Hors ligne

 

#2 04-02-2015 22:47:55

cake17
Cooker
Date d'inscription: 29-03-2012
Messages: 381
Site web

Re: [RESOLU] V3-RC1 --- Perte des données input file on error

:-) il y a 2 ans oui, maintenant c'est Bordeaux !

Je t'avoue que ces 2 gros pavés ne donnent pas envie de mettre le nez dedans... smile
Peux-tu décrire en épurant un peu le code (genre pour la vue par exemple mettre juste les $this->Form et retirer les div) ?

En regardant vite fait dans le controller, il y a des validations que je mettrais plus dans ton fichier AttachmentsTable, il vaut mieux mettre un max de chose possible dans les models plutôt que dans les controllers en règle générale. Regarde ici

Hors ligne

 

#3 05-02-2015 15:51:10

iwn
Pitivier
Lieu: La Rochelle
Date d'inscription: 22-01-2015
Messages: 18
Site web

Re: [RESOLU] V3-RC1 --- Perte des données input file on error

Salut Cake17, bon tu as migrer vers la capitale lol !
En ce qui concerne la validation en fait je la fais 2 fois une première en dur dans le controleur pur renvoyer les erreurs et une seconde lors de l'insert dans la table messages_attachments où la c'est bien le model qui fait sont boulot.
Je vais nettoyer la vue pour qu'elle soit plus comestible ! big_smile
Le truc en gros c'est que je perd le input en cas de soucis de validation...
L'input est bien présent si je fait un debug de message dans la vue mais quand je revalide c'est partis ....
je vais tenter le coups avec une vue hyper simple....


Passez à la V3 .... que du BONHEUR !!!

Hors ligne

 

#4 05-02-2015 16:16:25

iwn
Pitivier
Lieu: La Rochelle
Date d'inscription: 22-01-2015
Messages: 18
Site web

Re: [RESOLU] V3-RC1 --- Perte des données input file on error

Bon une fois nettoyer au plus simple !!

la vue:

Code: php

  1. <div class="container-fluid">
  2.   <section class="container">
  3.     <div class="row">
  4.       <div class="col-xs-12 col-sm-10 col-sm-offset-1 pt-40">
  5.        <div class="well">
  6.           <legend>Envoyer un message à <?= $user->username?></legend>
  7.           <?= $this->Form->create($message, ['type' => 'file']) ?>
  8.             <?= $this->Form->input('to_user_id', ['required' => true, 'label' => false, 'default' => $user->id, 'type' => 'hidden']) ?>
  9.             <?= $this->Form->input('referer', ['required' => true, 'label' => false, 'default' => $message->referer, 'type' => 'hidden']) ?>
  10.             <?= $this->Form->input('title', ['label' => false, 'class' => 'form-control']) ?>
  11.             <?= $this->Form->input('content', ['type' => 'textarea' ,'label' => false, 'class' => 'form-control']) ?>
  12.             <?= $this->Form->input('attachments[0]', ['type' => 'file', 'accept' => 'image/*',
  13.                                                                 'label' => false,
  14.                                                                 'templates' => ['inputContainer' => '{{content}}</span>', 'inputContainerError' => '{{content}}</span>{{error}}'],
  15.                                                                 'default' => $message['attachments'][0]
  16.                                                                ]) ?>
  17.             <?= $this->Form->input('attachments[1]', ['type' => 'file', 'label' => false, 'templates' => ['inputContainer' => '{{content}}</span>', 'inputContainerError' => '{{content}}</span>{{error}}']]) ?>
  18.             <hr>
  19.             <div class="row text-center">
  20.               <?= $this->Form->button('Envoyer', ['type' => 'submit', 'class' => 'btn btn-success']) ?>
  21.             </div>                
  22.           <?= $this->Form->end(); ?>
  23.         </div>
  24.       </div>
  25.     </div>
  26.   </section>
  27. </div>

le controleur :

Code: php

  1. public function test($id){
  2.  
  3.     $this->loadModel('Users');
  4.  
  5.     $user = $this->Users->get($id);
  6.  
  7.     if(is_null($user)){
  8.  
  9.       $this->Flash->error(__("Cet utilisateur n'existe pas ou n'est pas actif !"));
  10.       return $this->redirect($this->referer());
  11.  
  12.     }
  13.  
  14.     $message  = $this->Messages->newEntity();
  15.     $message->referer = $this->referer();
  16.  
  17.     if($this->request->is('post')){
  18.  
  19.       $message  = $this->Messages->newEntity($this->request->data, ['validate' => 'create']);
  20.      
  21.       $message->from_user_id = $this->Auth->user('id');
  22.       $message->created_ip = $this->request->clientIp();
  23.  
  24.       debug($message);
  25.  
  26.  
  27.       if ($this->Messages->save($message)) {
  28.  
  29.         $this->Flash->success(__("Votre message à été correctement envoyé."));
  30.         return $this->redirect($message->referer);
  31.      
  32.       } else {
  33.  
  34.         $this->Flash->error(__("Merci de corriger vos erreurs."))
  35.      
  36.       } 
  37.  
  38.     }
  39.  
  40.     $this->set(compact('message', 'user'));
  41.  
  42.  
  43.   }

le messagesTable

Code: php

  1. <?php
  2. namespace App\Model\Table;
  3.  
  4. use Cake\ORM\Query;
  5. use Cake\ORM\Table;
  6. use Cake\Validation\Validator;
  7.  
  8. class MessagesTable extends Table {
  9.  
  10. /**
  11.  * Initialize method.
  12.  *
  13.  * @param array $config The configuration for the Table.
  14.  *
  15.  * @return void
  16.  */
  17.   public function initialize(array $config) {
  18.     $this->table('messages');
  19.     $this->displayField('to_user_id');
  20.     $this->primaryKey('id');
  21.  
  22.     $this->addBehavior('Timestamp');
  23.  
  24.     $this->belongsTo('UserFrom', [
  25.       'className' => 'Users',
  26.       'foreignKey' => 'from_user_id'
  27.     ]);
  28.  
  29.     $this->belongsTo('UserTo', [
  30.       'className' => 'Users',
  31.       'foreignKey' => 'to_user_id'
  32.     ]);
  33.  
  34.     $this->hasMany('MessagesAttachments', [
  35.       'className' => 'MessagesAttachments',
  36.       'foreignKey' => 'message_id'
  37.     ]);
  38.  
  39.   }
  40.  
  41.   public function validationCreate(Validator $validator) {
  42.     $validator
  43.       ->notEmpty('title', __("champs requis"))
  44.       ->add('title', [
  45.         'alphanumeric' => ['rule' => ['custom', '#^[A-Za-z0-9-_ ,:.!?]+$#']'message' => __("Uniquement des caractères alphanumériques.")],
  46.         'minLength' => ['rule' => ['minLength', 5]'message' => __("SVP, {0} caractères minimum pour l'objet du message.", 5)]
  47.       ])
  48.       ->notEmpty('content', __("champs requis"))
  49.       ->add('content', [
  50.         'minLength' => ['rule' => ['minLength', 10]'message' => __("SVP, {0} caractères minimum pour le message.", 10)]
  51.       ])
  52.       ->allowEmpty('attachments')
  53.       ->add('attachments', [
  54.         'mimeType' => [
  55.           'rule' => ['mimeType', ['image/jpeg', 'image/png']],
  56.           'message' => __("Type de fichier invalide."),
  57.           'last' => true,
  58.           'on' => function ($context) { return !empty($context['data']['attachments']['name'])}
  59.         ],
  60.         'fileExtension' => [
  61.           'rule' => ['extension', ['jpg', 'png']],
  62.           'message' => __("Les extentions sont {0}.", '.jpg, et .png'),
  63.           'last' => true,
  64.           'on' => function ($context) { return !empty($context['data']['attachments']['name'])}
  65.         ],
  66.         'fileSize' => [
  67.           'rule' => ['fileSize', '<', '2000KB'],
  68.           'message' => __("Le fichier a une taille superieure à {0}", '2MB'),
  69.           'on' => function ($context) { return !empty($context['data']['attachments']['size'])}
  70.         ],
  71.       ]);    
  72.     return $validator;
  73.   }
  74. }

Et la pareil en cas d'erreur, par exemple le champ content vide, je ne retrouve pas les données de l'input attachment. ( même avec un simple input file). Pas de soucis par contre pour les autres données elles sont bien retransmise.


Passez à la V3 .... que du BONHEUR !!!

Hors ligne

 

#5 05-02-2015 21:39:50

iwn
Pitivier
Lieu: La Rochelle
Date d'inscription: 22-01-2015
Messages: 18
Site web

Re: [RESOLU] V3-RC1 --- Perte des données input file on error

Bon je crois que j'ai trouver la raison.... c'est purement coté sécurité HTML on ne peux pas donner une valeur par défaut a un input type file.... après ça peut se comprendre lol !big_smile
Bon bah tan-pis ça va les obliger à faire gaffe lors de la saisie !
En tout cas la V3 .... Top Merci à la Team.

PS: Cake17 si tu passes dans le coin fait signe ..... (sortie Rochefort pour moi)wink


Passez à la V3 .... que du BONHEUR !!!

Hors ligne

 

#6 07-02-2015 16:01:04

cake17
Cooker
Date d'inscription: 29-03-2012
Messages: 381
Site web

Re: [RESOLU] V3-RC1 --- Perte des données input file on error

C'est noté smile

Hors ligne

 

Pied de page des forums

Propulsé par FluxBB
Traduction par FluxBB.fr