Welcome Guest, Not a member yet? Register   Sign In
Multiple file uploads
#1

[eluser]neen[/eluser]
Hi there,

I have a form like so:

Code:
<form action="upload" enctype="multipart/form-data" method="post">
    <input type="file" name="featured_image[0]">
    <input type="file" name="featured_image[1]">
    <input type="file" name="featured_image[2]">
    <input type="file" name="featured_image[3]">
    <input type="submit" value="Upload Images">
</form>

How can I use the upload library with the above form?

I get an error when I try to upload (You did not select a file to Upload.)
#2

[eluser]Colin Williams[/eluser]
You either need to give each file input a unique name (featured_image_0, featured_image_1) etc, and process each one in a loop, or overload the Uploader class to handle file upload arrays.

Copying this from an earlier post I made:

So, yeah, I was failing to pass $config from my constructor to CI_Upload's constructor...

I also updated it so the API remains the same, just call $this->upload->do_upload(), not ->do_multi_upload()

Code:
<?php

class MY_Upload extends CI_Upload {
  
   function MY_Upload($props = array())
   {
      parent::CI_Upload($props);
   }
  
   function do_upload($field = 'userfile')
   {
      $success = FALSE;
      if (isset($_FILES[$field]) and is_array($_FILES[$field]['error']))
      {
         // Create a pseudo file field for each file in our array
         for ($i = 0; $i < count($_FILES[$field]['error']); $i++)
         {
            // Give it a name not likely to already exist!
            $pseudo_field_name = '_psuedo_'. $field .'_'. $i;
            // Mimick the file
            $_FILES[$pseudo_field_name] = array(
               'name' => $_FILES[$field]['name'][$i],
               'size' => $_FILES[$field]['size'][$i],
               'type' => $_FILES[$field]['type'][$i],
               'tmp_name' => $_FILES[$field]['tmp_name'][$i],
               'error' => $_FILES[$field]['error'][$i]
            );
            // Let do_upload work it's magic on our pseudo file field
            $success = parent::do_upload($pseudo_field_name);
         }
      }
      else
      // Works just like do_upload since it's not an array of files
      {
         $success = parent::do_upload($field);
      }
      return $success;
   }
  
}

A few caveats that should be addressed: The $this->upload->data() method will only return data of the last file to be uploaded, not all files uploaded. If one of the fields errors, there is no way to know which individual one was erroneous. Not impossible problems to solve, but the code above has yet to address either of them. I'll work on rounding it out if I get some time, or need to do it myself.

For now, it might be good to just have unique names for x number of upload fields, then process each one individually.

Here's my controller:

Code:
&lt;?php

class Upload extends Controller {
  
   function Upload()
   {
      parent::Controller();
   }
  
   function index()
   {
      $data = array(
         'error' => array(),
         'upload_data' => array(),
      );
      
      $this->load->helper('form');
      
      $config['upload_path'] = 'uploads';
      $config['allowed_types'] = 'gif|jpg|png';
      $config['max_size'] = '2048';
      $config['max_width'] = '1024';
      $config['max_height'] = '768';
      $this->load->library('upload', $config);
      
      if ( ! $this->upload->do_upload())
      {
         $data['error'] = array('error' => $this->upload->display_errors());
      }  
      else
      {
         $data['upload_data'] = $this->upload->data();
      }
      
      $this->load->view('sandbox/upload', $data);
      
   }
  
}

And my view:

Code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
&lt;html &gt;
&lt;head&gt;
   &lt;title&gt;Multi Upload Test&lt;/title&gt;
   &lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8" /&gt;
&lt;/head&gt;
&lt;body&gt;
  
   &lt;? foreach ($error as $msg) : ?&gt;
   <div style="color: red; display: block; margin: 12px 0">&lt;?= $msg ?&gt;</div>
   &lt;? endforeach; ?&gt;
  
   &lt;? if (count($upload_data)) : ?&gt;
      <ul>
      &lt;?php foreach($upload_data as $item => $value):?&gt;
         <li>&lt;?php echo $item;?&gt;: &lt;?php echo $value;?&gt;</li>
      &lt;?php endforeach; ?&gt;
      </ul>
   &lt;? endif; ?&gt;
  
   <h1>Single File Upload</h1>
  
   &lt;?= form_open_multipart('sandbox/upload') ?&gt;
      <div>&lt;?= form_upload('userfile') ?&gt;</div>
      <div><button type="submit">Upload!</button></div>
   &lt;/form&gt;
  
   <h1>Multiple File Upload</h1>
  
   &lt;?= form_open_multipart('sandbox/upload') ?&gt;
      <div>&lt;?= form_upload('userfile[]') ?&gt;</div>
      <div>&lt;?= form_upload('userfile[]') ?&gt;</div>
      <div>&lt;?= form_upload('userfile[]') ?&gt;</div>
      <div><button type="submit">Upload!</button></div>
   &lt;/form&gt;
  
&lt;/body&gt;
&lt;/html&gt;
#3

[eluser]neen[/eluser]
I never thought about that, but now I am doing using a completely separate field for each file...it is working perfectly!

Here's my code:

Code:
public function upload()
        {
            // setup the config
            $config['upload_path']   = "/Projects/{$this->config->item('common_path')}/assets/images/series/featured/";
            $config['allowed_types'] = 'gif|jpg|png';
            $config['overwrite']     = TRUE;
            $config['remove_spaces'] = TRUE;
            $this->load->library('upload', $config);
            
            $image_types = array("image/jpeg", "image/gif", "image/x-png", "image/png");
            
            $images      = array();
            // $imagesarray = array();
            $series = $this->input->post('featured_series');
            // we are saving the featured series...
            for($i =0; $i <= count($_FILES); $i++)
            {
                if(in_array(strtolower($_FILES['featured_image_'.$i]['type']), $image_types))
                {
                    // get the extension
                    $extension = split("[/\\.]", strtolower($_FILES['featured_image_'.$i]['name']));
                    $extension = $extension[(count($extension)) - 1];
                    
                    // get the new filename...
                    $category = $this->category_model->getCatbyID($series[$i]);
                    $_FILES['featured_image_'.$i]['name'] = url_title(strtolower($category['name']), 'dash') . '.' . $extension;
                    if(!$this->upload->do_upload("featured_image_{$i}"))
                    {
                        $error = $this->upload->display_errors();
                        dump($error);
                    } else {
                        $data = $this->upload->data();
                        dump($data);                    
                    }
                }
            }
        }

Obviously I am going to need to edit the $config stuff (gonna chuck that in config/upload.php)
#4

[eluser]neen[/eluser]
I forgot to mention, but there are some custom things in there..

This is basically a system to let my users select a 'series' to show on the front page of my website.

I am renaming the image file for normalization reasons (I never need to store that info in the database, since the system will know exactly what the image name is based on the category).
#5

[eluser]Colin Williams[/eluser]
That is definitely the route to go in order to work nicely with the standard Upload class.
#6

[eluser]drewbee[/eluser]
I see that you are on the right track, and one thing I would like to point out is that when naming your files, dont give them a position in the array.

IE
Code:
&lt;form action="upload" enctype="multipart/form-data" method="post"&gt;
    &lt;input type="file" name="featured_image[]"&gt;
    &lt;input type="file" name="featured_image[]"&gt;
    &lt;input type="file" name="featured_image[]"&gt;
    &lt;input type="file" name="featured_image[]"&gt;
    &lt;input type="submit" value="Upload Images"&gt;
&lt;/form&gt;
That way, if a user adds an image to the second one and maybe 4th, it will end up generating an array on the server side of simply 1 & 2.

Just personal preference I guess, but I have always seen it done this way.
#7

[eluser]neen[/eluser]
Actually, if I use an array, it makes it hell to use the standard upload class (because it is not expecting a multi-dimensional array for the fields)...so instead, I am using _1, _2, _3, etc
#8

[eluser]frietkot[/eluser]
I'm using the code from Colin Williams and it works great.
But how do I incorporate the image_lib class to upload multiple images and then resize them?
#9

[eluser]amites[/eluser]
Another option is to use the library I published at

http://www.mitesdesign.com/blog/open-sou...de-igniter

uses a JQuery dialog to upload multiple files from a single input, though the process beyond that is much the same as what's been posted, though I don't know if they've tested their code yet,

gotta love the community here
#10

[eluser]Colin Williams[/eluser]
My offering is more of the start of a solution, not a complete one. Seems better to just name your fields uniquely and upload them in a loop.




Theme © iAndrew 2016 - Forum software by © MyBB