Skip to content

Instantly share code, notes, and snippets.

@adityamenon
Created July 31, 2012 05:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adityamenon/3214128 to your computer and use it in GitHub Desktop.
Save adityamenon/3214128 to your computer and use it in GitHub Desktop.
Codeigniter upload a dynamic number of files
<?php if(!defined('BASEPATH')) exit("No direct script access allowed.");
class Upload_test extends CI_Controller {
public function index() {
if($this->input->post('submit')) {
$config['upload_path'] = BASEPATH.'../uploads';
$config['allowed_types'] = 'txt';
$this->load->library('upload', $config);
if(empty($_FILES) {
//redirect or do something else to stop execution
}
foreach ($_FILES as $key => $value) { //THIS IS THE CRUCIAL PART
$this->upload->do_upload($key);
var_dump($this->upload->data());
var_dump($this->upload->display_errors());
}
exit();
}
$this->load->helper('form');
$this->load->view('upload_test');
}
//I have no idea why more complex code exists for the same thing elsewhere on the 'net!
}
@Ocramius
Copy link

I personally prefer following approach (since controllers shouldn't know anything of the environment). This is pseudo-code, but it is basically some SOA principles applied.

<?php

class MyController extends SomeBaseController
{
    protected $uploader;
    public function __construct(UploadHandlerInterface $uploader)
    {
        // injecting a configured uploader
        $this->uploader= $uploader;
    }

    public function indexAction()
    {
        if ($this->getRequest()->isPost()) {
            if (!$this->uploader->receive()) {
                // errors are fetched from the adapter, then the component responsible for generating 
                // responses will transform it into html/json/whatever
                return new ResponseOrViewModel('invalid-data.tpl', $this->uploader->getErrors());
            }

            // success
            return new ResponseOrViewModel('ok.tpl', $this->uploader->getReceivedDataInformation());
        }

        // if it isn't POST, show a form
        return new ResponseOrViewModel('upload.tpl', new SomeForm());
    }
}

(yes, I love opening cans of worms :) )

@adityamenon
Copy link
Author

Thanks for your code input, you have discussed a more intricate form of OOP than the easy stuff I tend to do with CodeIgniter. I was trying to illustrate using CodeIgniter's native upload function in a multi-upload situation, but of course your input on how to handle uploads in general in an OOP context is most welcome.

@Ocramius
Copy link

@adityamenon yes, the fact is that it is problematic to have configuration in a controller.

The controller should just proxy calls to the service layer and translate responses from it (which kind of happens in your example, but is not really clean). It is more a question of doing things right.

That's just me being always critic to examples who show the "doing fast"... But I'm everything but pragmatic :)

@adityamenon
Copy link
Author

Hi! Okay, yes, sorry about the configuration. Actually, CI provides a way to keep that configuration inside a separate file and even initialize the Upload class for use in separate locations (framework configuration files). I guess I should have just alluded to that but somehow felt keeping those lines in this examples make it more complete. In that case, the injection of the uploader happens automatically and nothing is needed to be done.

I am not familiar with Service Oriented Architecture, but in the case of CodeIgniter, do you mean it should just proxy calls to the Model? Yeah, that's a recommended best practice :) But how do I remove all references to $_FILES though? I think by extending the Uploader and putting this logic into that, I am guessing...

Have you ever used CI?

@Ocramius
Copy link

Ocramius commented Aug 1, 2012

I used CI some years ago, so I'm not updated at all about its functionality. I currently stick with ZF2/SF2.

Anyway, the uploader "adapter" (inspired by the old ZF1 file transfer adapter) could be aware of the environment since this is more like a PHP limitation (really feels weird to have files in a separate temporary location by default, but it is to avoid loading them into memory)...
Another way of solving it would be to pass $_FILES like following:$this->uploader->receive($_FILES).
It still doesn't work without some assumptions though.

@adityamenon
Copy link
Author

I used CI some years ago, so I'm not updated at all about its functionality.

Ah okay, that is why we are having slight difficulty aligning thoughts on this - this is more of a quick-solve post, because CI's upload library allows only single file uploads, and it's not clear from the documentation if any input field will work or only the ones created with the CI form helper (making me wonder if there was some sort of 'registration' of file fields required by the library). I wanted to show a simple way of looping the upload library to remove any confusion about it.

@Ocramius
Copy link

Ocramius commented Aug 1, 2012

@adityamenon Aha, I came here from a reshare on G+, not because I'm interested in CI itself :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment