CodeIgniter : Upload multiple de fichiers

Cet article présente comment gérer des « uploads » multiple de fichier à travers les formulaires sous codeIgniter. Le code fonctionnera pour un champ input « file » ayant l’attribut multiple comme ceci :

<input type="file" multiple="multiple" name="fichiers[]">

Ou pour une liste de champ input « file » unique comme cela :

<input type="file" name="fichiers[]">
<input type="file" name="fichiers[]">
...

Comme on peux le voir, le nom de l’input doit être sous le format d’un tableau « [] ». Dans notre exemple on le nomme « fichiers ». Ci-dessous le code commenté permettant de traiter les différents fichiers envoyer par le formulaire :

$fieldName = 'fichiers';//nom du champ input file
//ce champs doit exister et avoir un élément "name" sous forme de tableau
if ($_FILES && isset($_FILES[$fieldName]) && is_array($_FILES[$fieldName]['name'])) {
  //dans ce cas on boucle sur chaque élément du tableau
  foreach ($_FILES[$fieldName]['name'] as $key => $name) {
      if ($name) {
          //on copie les variables de l'élément courant dans le tableau $_FILES avec comme nom arbitraire "file_temp". Cela permettra à codeigniter de le traiter comme un champ file simple.
          $_FILES['file_temp']['name'] = $_FILES[$fieldName]['name'][$key];
          $_FILES['file_temp']['type'] = $_FILES[$fieldName]['type'][$key];
          $_FILES['file_temp']['tmp_name'] = $_FILES[$fieldName]['tmp_name'][$key];
          $_FILES['file_temp']['error'] = $_FILES[$fieldName]['error'][$key];
          $_FILES['file_temp']['size'] = $_FILES[$fieldName]['size'][$key];
          //on met en place la configuration pour l'upload du fichier, comme on l'aurait pour n'importe quel input file sous codeigniter
          $config = [];
          $config['upload_path'] = './uploads/mon_dossier/';//dossier d'upload
          $config['allowed_types'] = ['pdf', 'doc', 'docx', 'txt', 'odt'];//types de fichiers autorisé
          $config['file_name'] = 'nom_unique_' . date('YmdHis') . '_' . rand(1000, 9999);//renommage du fichier
          //ligne les plus importantes : ne fonctionnera pas avec l'habituel "$this->load->library('upload', $config);"
          $this->load->library('upload');
          $this->upload->initialize($config);
          //on traite notre fichier dans "file_temp" et on vérifie si il y'a des erreurs.
          if (!$this->upload->do_upload('file_temp')) {    
              $msg_error = $this->upload->display_errors();
              //traiter le message d'erreur comme il vous convient
          } else {
              //tout c'est bien passé vous pouvez récupérer les informations du fichiers de cette façon
              $fichier = $this->upload->data();
              //$fichier['file_name'] -> nom du fichier
              //$fichier['client_name'] -> nom d'origine du fichier
              //traiter la réussite pour ce fichier comme il vous convient.
          }
      }
  }
}

Une autre petite astuce, pour la validation d’un fichier obligatoire, dans le cas d’un input « file » simple dans cette exemple :

<input type="file" name="fichier" required="required">

Les règles de validation codeigniter ne fonctionne pas pour les input de ce type, par exemple ceci ne fonctionnera pas :

//inutile (sera toujours en erreur)
$this->form_validation->set_rules('fichier', 'Fichier', ['required']);

Et n’oubliez pas que le fait d’ajouter l’attribut « required » en html n’est pas suffisant pour rendre un champ obligatoire. La règle d’or étant qu’il ne faut jamais faire confiance au données en provenance de l’extérieur et toujours faire une validation coté serveur. Donc le « bricolage » pour intercepter l’erreur avec codeigniter est d’utiliser la manière suivante :

//le nom du champ est "fichier". On vérifie qu'il existe et n'est pas vide
if (isset($_FILES['fichier']) empty($_FILES['fichier']['name'])) {
    $this->form_validation->set_rules('fichier', 'Fichier', ['required']);
}

Au passage, pour proposer l’upload de fichier multiples de manière « sexy » à vos utilisateurs (avec prévisualisation des images entre autre) vous pouvez utilisez le plugin javascript suivant file-upload-with-preview.