-2

I am working on a Social Network application with Codeigniter 3, Ion-Auth and Bootstrap 4. You can see the Github repo HERE.

I have tried to add an avatar at user's registration.

For this purpose, I first added an "avatar" column to the users table. Then, in the view I added:

<div class="form-group">
    <?php $avatar['class'] = 'form-control';
    echo lang('edit_user_avatar_label', 'avatar');?>
    <input type="file" class="form-control" name="userfile" id="avatar" size="20">
</div>

In the Auth controller (application/controllers/Auth.php) I created this upload method:

public function upload_image() {
    $config['upload_path'] = './assets/img/avatars';
    $config['allowed_types'] = 'jpg|jpeg|png';
    $config['max_size'] = 2048;

    $this->load->library('upload', $config);

    if (!$this->upload->do_upload('userfile')) {
        $error = array('error' => $this->upload->display_errors());
        $this->_render_page('auth' . DIRECTORY_SEPARATOR . 'create_user', $error);
    } else {
        $this->data = array('image_metadata' => $this->upload->data());
        $this->_render_page('auth' . DIRECTORY_SEPARATOR . 'create_user', $this->data);
    }
}

Finally, to the existing $additional_data array, from the orihinal create_user() method, I added the line 'avatar' => $_FILES['userfile']['name']:

$additional_data = [
    'first_name' => $this->input->post('first_name'),
    'last_name' => $this->input->post('last_name'),
    'avatar' => $_FILES['userfile']['name'],
    'company' => $this->input->post('company'),
    'phone' => $this->input->post('phone'),
];

The above line, when added to the $data array from the edit_user($id) method, has no errors, yet when added to the $additional_data array, it gives the error: Undefined index: userfile.

Where is my mistake?


UPDATE:

I replaced <?php echo form_open("auth/create_user");?> with <?php echo form_open_multipart("auth/create_user");?>.

Result: the image filename (with extension), is added in the users table avatar column. There is a problem though: the actual upload of the image, to ./assets/img/avatars does not take place.

Razvan Zamfir
  • 4,209
  • 6
  • 38
  • 252
  • If you are going to suggest that we use your code from your Github project, can you please make it so it reflects the changes you are trying to make in your question. Your Github version did not have - the avatar field in the database migration, I had to manually create that. You did not have the correct form_open() which should be form_open_multipart(). – TimBrownlaw Sep 02 '20 at 07:31
  • @TimBrownlaw I have already changed from `form_open()` to `form_open_multipart()`. – Razvan Zamfir Sep 02 '20 at 07:37
  • @TimBrownlaw Please look at the "UPDATE" section of the question. – Razvan Zamfir Sep 02 '20 at 07:42
  • Hmm, yes you did. My apologies. But I had forked it a few hours ago and it wasn't changed. – TimBrownlaw Sep 02 '20 at 07:44

4 Answers4

2

Finaly working!!

    if ($this->form_validation->run() === TRUE)
    {
        $email = strtolower($this->input->post('email'));
        $identity = ($identity_column === 'email') ? $email : $this->input->post('identity');
        $password = $this->input->post('password');

        //return $this->upload_image();
        $config['upload_path'] = './assets/img/avatars';
        $config['file_ext_tolower']     = TRUE;
        $config['allowed_types']        = 'gif|jpg|png';
        $config['max_size']             = 100;
        $config['max_width']            = 1024;
        $config['max_height']           = 768;
        $this->load->library('upload', $config);

        if (!$this->upload->do_upload('userfile'))
        {
                $error = array('error' => $this->upload->display_errors());
                print_r($error);
                $file_name = null;
        }
        else
        {
                $file_name = $this->upload->data('file_name');
        }
        $additional_data = [
            'first_name' => $this->input->post('first_name'),
            'last_name' => $this->input->post('last_name'),
            'avatar' =>  $file_name,
            'company' => $this->input->post('company'),
            'phone' => $this->input->post('phone'),
        ];
        print_r($additional_data);
    }

Result Array

Array ( [first_name] => admin [last_name] => admin [avatar] => design.png [company] => admin [phone] => 9999999999 )
Ashok
  • 346
  • 1
  • 8
1

UPDATE

In the comments OP posted a link to the full code. Checking that out, the problem is very clear. I described it, and a fix, in the comments below my answer. Copying that comment here:

You load the upload library on line 473, in the upload_image() method. But you are calling $this->upload->data() in a different method (line 530, in the create_user() method), where you have not loaded the upload library. Move the code from upload_image() into create_user(). Refactor once you have it working if you want, keep it simple until it is

Original Answer

It looks like you've been working through the documentation, your code is very similar to the example they provide. But you've stopped short of the critical last step where they explain how to access the details of the uploaded file! :-)

They demonstrate how to do that by returning a view with the upload data:

$data = array('upload_data' => $this->upload->data());
$this->load->view('upload_success', $data);

So the upload file info is available through $this->upload->data(), not PHP's superglobal $_FILES.

The docs go on to describe the data() method:

data([$index = NULL])

[...]

This is a helper method that returns an array containing all of the data related to the file you uploaded.

[...]

To return one element from the array:

$this->upload->data('file_name');       // Returns: mypic.jpg

So for your Ion Auth code, this should work (assuming the filename is all you need to store):

$additional_data = [
    'first_name' => $this->input->post('first_name'),
    'last_name'  => $this->input->post('last_name'),
    'avatar'     => $this->upload->data('file_name'),
    'company'    => $this->input->post('company'),
    'phone'     => $this->input->post('phone'),
];
Don't Panic
  • 13,965
  • 5
  • 32
  • 51
  • I get an `Undefined property: Auth::$upload` error. – Razvan Zamfir Aug 21 '20 at 06:35
  • Thanks for the edits, I wrote it in a rush. Have you verified that `$this->upload->data('file_name')` gives your filename? Your error suggests you are doing that step in an Auth library or something? `$this` refers to the controller where you loaded the `upload` library, so that should be back there. – Don't Panic Aug 21 '20 at 08:34
  • It does return something, but not the filename, for some reason. I have pushed the **[project](https://github.com/Ajax30/ci-social)** to Github. – Razvan Zamfir Aug 21 '20 at 09:19
  • You load the upload library on [line 473](https://github.com/Ajax30/ci-social/blob/master/application/controllers/Auth.php#L473), in the `upload_image()` method. But you are calling `$this->upload->data()` in a different method ([line 530](https://github.com/Ajax30/ci-social/blob/master/application/controllers/Auth.php#L530), in the `create_user()` method), where you have not loaded the upload library. Move the code from `upload_image()` into `create_user()`. Refactor once you have it working if you want, keep it simple until it is. – Don't Panic Aug 22 '20 at 00:03
  • I would like to keep `upload_image()` as a separate method and reuse it. – Razvan Zamfir Aug 22 '20 at 09:03
  • Doing `print_r($additional_data)` returns `Array ( [first_name] => John[last_name] => Doe[avatar] => [company] => [phone] => +40730649302 )` – Razvan Zamfir Aug 22 '20 at 09:12
  • 1
    Yes, that's clear, and I've already explained why ... It sounds like you haven't understood the problem I described? Your code won't work as-is. I've described how to fix it. Best of luck. – Don't Panic Aug 22 '20 at 09:53
  • I already am returning the picture's name (with extension). It is inserted in the *users* table too.The file does not upload though. – Razvan Zamfir Sep 02 '20 at 07:24
  • Do you mean you've already fixed the issue I described, and so are now getting a value for `avatar` in your `$additional_data` array? – Don't Panic Sep 02 '20 at 07:26
  • Well I would strongly suspect that your /assets/img/avatars folder needs to have the correct permissions of at least 777. Your code needs to be able to handle errors due to the file upload. – TimBrownlaw Sep 02 '20 at 08:20
  • @TimBrownlaw I think maybe you replied to the wrong thread/answer? – Don't Panic Sep 02 '20 at 08:29
  • @dontpanic it was in response to Razvans comment - "The file does not upload though" – TimBrownlaw Sep 02 '20 at 09:18
1

The problem seems to be in your form. I reviewed your code and found that auth/create_user.php uses form_open() method instead of using form_open_multipart() method because a normal form won't post files, hence in your controller not getting userfile index from $additional_data variable.

rkg
  • 805
  • 5
  • 14
  • Of course, that was it. In fact, my Edit for did have this: ``. I forgot to add it to the Create form. – Razvan Zamfir Aug 31 '20 at 19:29
  • There is a problem though: the actual upload of the image, to `./assets/img/avatars` does not take place, evan thought the image filename, with extension, is added in the table's _avatar_ column. – Razvan Zamfir Aug 31 '20 at 19:35
1

As has been clearly explained in the other answers, here is the Copy and Paste answer for you.

To reiterate what has been already stated.

$this->upload->data('file_name'),

Does not exist as you have not performed the required steps to create it and hence why you were getting the very "clearly stated" error message.

So you need to add in...

$config['upload_path'] = './assets/img/avatars/';
$config['allowed_types'] = 'gif|jpg|png';
$config['max_size'] = 100;
$config['max_width'] = 1024;
$config['max_height'] = 768;

$this->load->library('upload', $config);
$this->upload->do_upload('userfile');

So your code becomes...

if ($this->form_validation->run() === TRUE) {
    $email = strtolower($this->input->post('email'));
    $identity = ($identity_column === 'email') ? $email : $this->input->post('identity');
    $password = $this->input->post('password');

    //return $this->upload_image();
    $config['upload_path'] = './assets/img/avatars/';
    $config['allowed_types'] = 'gif|jpg|png';
    $config['max_size'] = 100;
    $config['max_width'] = 1024;
    $config['max_height'] = 768;

    $this->load->library('upload', $config);
    $this->upload->do_upload('userfile');


    $additional_data = [
        'first_name' => $this->input->post('first_name'),
        'last_name'  => $this->input->post('last_name'),
        'avatar'     => $this->upload->data('file_name'),
        'company'    => $this->input->post('company'),
        'phone'      => $this->input->post('phone'),
    ];
}

Now, as you have this in your do_upload() method, you could put the file upload code in another method and call it from both, so you are not "repeating yourself". I'll leave that up to you do work out.

Update: A possible refactoring

Create a new method to init the File Upload

protected function init_do_upload() {
    $config['upload_path'] = './assets/img/avatars';
    $config['allowed_types'] = 'gif|jpg|png';
    $config['max_size'] = 100;
    $config['max_width'] = 1024;
    $config['max_height'] = 768;

    $this->load->library('upload', $config);
}

Your existing do_upload() becomes...

/**
 * Upload avatar
 */
public function do_upload() {
    $this->init_do_upload();
    if ( ! $this->upload->do_upload('userfile')) {
        $error = array('error' => $this->upload->display_errors());
        $this->load->view('upload_form', $error);
    } else {
        $this->data = array('upload_data' => $this->upload->data());
        $this->_render_page('auth' . DIRECTORY_SEPARATOR . 'create_user', $this->data['upload_data']);
    }
}

And the code segment in create_user() becomes...

if ($this->form_validation->run() === TRUE) {
    $email = strtolower($this->input->post('email'));
    $identity = ($identity_column === 'email') ? $email : $this->input->post('identity');
    $password = $this->input->post('password');


    $this->init_do_upload();
    $this->upload->do_upload('userfile');

    $additional_data = [
        'first_name' => $this->input->post('first_name'),
        'last_name'  => $this->input->post('last_name'),
        'avatar'     => $this->upload->data('file_name'),
        'company'    => $this->input->post('company'),
        'phone'      => $this->input->post('phone'),
    ];
}
TimBrownlaw
  • 5,457
  • 3
  • 24
  • 28
  • This was run from your Github project, with the additions I had to make to add in the users column for avatar. And correcting the form_open() to form_open_multipart(). – TimBrownlaw Sep 02 '20 at 07:32
  • I've not added any error checking/handling in the case where there is no image or an error occurs in your create_user() method for the file upload. That's for you to complete. – TimBrownlaw Sep 02 '20 at 07:59
  • I used your code. The image file name _does_ get written in the avatar column, but the image itself is _not_ uploaded. – Razvan Zamfir Sep 02 '20 at 09:11
  • Have you checked your folder permissions? They should be 777. When I ran "the code" I used a var_dump($this->uploads) and saw the uploads error message regarding the upload path not being valid). It was my permissions... I run on a Linux system so I get to see all that fun stuff happen re permissions. – TimBrownlaw Sep 02 '20 at 09:22
  • I have am XAMPP server on Windows. – Razvan Zamfir Sep 02 '20 at 09:26
  • @RazvanZamfir I downloaded and installed your code from Github. I installed the Database and added the missing avatar column. I create the Missing /assets/img/avatars folder and set the permissions (o which I had to do for my system) and yes it all worked else I would not have posted the code. – TimBrownlaw Sep 02 '20 at 10:24
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/220860/discussion-between-timbrownlaw-and-razvan-zamfir). – TimBrownlaw Sep 02 '20 at 12:49