2

I am working on a basic blog application with Codeigniter 3.1.8 and Bootstrap 4.

The posts, of course, have main images. There is a default image if no image is uploaded by the user but, if an image is uploaded, there are only 3 types allowed: jpg, jpeg and png.

Wanting to warn the user in case she/he tries to upload other file formats, I did this in the Posts controller:

// Upload image
$config['upload_path'] = './assets/img/posts';
$config['allowed_types'] = 'jpg|jpeg|png';
$config['max_size'] = '2048';

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

if(!$this->upload->do_upload()){

    $data['uerrors'] = $this->upload->display_errors();

    if ($data['uerrors']) {
        $this->load->view('partials/header', $data);
        $this->load->view('dashboard/create-post');
        $this->load->view('partials/footer');
    } else {
        $post_image = 'default.jpg';
    }

} else {
    $data = array('upload_data' => $this->upload->data());
    $post_image = $_FILES['userfile']['name'];
}

In the view I have:

<?php foreach ($uerrors as $uerror): ?>
  <span><?php echo $uerror; ?></span>
<?php endforeach; ?>

Yet, I get a Undefined variable: uerrors error.

Here is the entire create() method:

public function create() {

    // Only logged in users can create posts
    if (!$this->session->userdata('is_logged_in')) {
        redirect('login');
    }

    $data = $this->get_data();
    $data['tagline'] = "Add New Post";

    if ($data['categories']) {
        foreach ($data['categories'] as &$category) {
            $category->posts_count = $this->Posts_model->count_posts_in_category($category->id);
        }
    }

    $this->form_validation->set_rules('title', 'Title', 'required');
    $this->form_validation->set_rules('desc', 'Short description', 'required');
    $this->form_validation->set_rules('body', 'Body', 'required');
    $this->form_validation->set_error_delimiters('<p class="error-message">', '</p>');

    if($this->form_validation->run() === FALSE){
        $this->load->view('partials/header', $data);
        $this->load->view('dashboard/create-post');
        $this->load->view('partials/footer');
    } else {
        // Create slug (from title)
        $slug = url_title(convert_accented_characters($this->input->post('title')), 'dash', TRUE);
        $slugcount = $this->Posts_model->slug_count($slug, null);
        if ($slugcount > 0) {
            $slug = $slug."-".$slugcount;
        }

        // Upload image
        $config['upload_path'] = './assets/img/posts';
        $config['allowed_types'] = 'jpg|jpeg|png';
        $config['max_size'] = '2048';

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

        if(!$this->upload->do_upload()){

            $data['uerrors'] = $this->upload->display_errors();

            if ($data['uerrors']) {
                $this->load->view('partials/header', $data);
                $this->load->view('dashboard/create-post');
                $this->load->view('partials/footer');
            } else {
                $post_image = 'default.jpg';
            }

        } else {
            $data = array('upload_data' => $this->upload->data());
            $post_image = $_FILES['userfile']['name'];
        }

        $this->Posts_model->create_post($post_image, $slug);
        $this->session->set_flashdata('post_created', 'Your post has been created');
        redirect('/');
    }
} 

Where is my mistake?

6 Answers 6

1
+50

Your upload code looks okay, but you need to update these following changes.

  1. Pass data to your 'dashboard/create-post' view as you have passed to your 'partials/header' view. Your 'dashboard/create-post' view is not getting any upload error messages, so it is saying 'Undefined variable: uerrors'. So, your upload code should be like this -
if(!$this->upload->do_upload()){
    $data['uerrors'] = $this->upload->display_errors();
    if ($data['uerrors']) {
        $this->load->view('partials/header', $data);
        $this->load->view('dashboard/create-post', $data);
        $this->load->view('partials/footer');
    } else {
        $post_image = 'default.jpg';
    }
} else {
    $post_image = $this->upload->data('file_name');
}
  1. As CodeIgniter Documentation says, 'display_errors()' returns string, not array, you don't have to loop through the error. Just echo it on your 'dashboard/create-post' view.

For your convenience, make your upload task in different method so that you can re-use this in update method also. As example -

private function uploadFile(){
    if ($_FILES['userfile']['name'] === '') {
        return array(
            'status' => TRUE,
            'message' => 'No file selected.',
            'file_name' => 'default.jpg'
        );
    }

    // Upload image
    $config['upload_path'] = './assets/img/posts';
    $config['allowed_types'] = 'jpg|jpeg|png';
    $config['max_size'] = '2048';

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

    if(!$this->upload->do_upload('userfile')){
        return array(
            'status' => FALSE,
            'message' => $this->upload->display_errors('<p class="text-danger ">', '</p>'),
            'file_name' => ''
        );
    }else{
        return array(
            'status' => TRUE,
            'message' => 'File uploaded successfully',
            'file_name' => $this->upload->data('file_name')
        );
    }
}

Then your entire create method should look like this -

public function create() {
    // Only logged in users can create posts
    if (!$this->session->userdata('is_logged_in')) {
        redirect('login');
    }

    $data = $this->get_data();
    $data['tagline'] = "Add New Post";

    if ($data['categories']) {
        foreach ($data['categories'] as &$category) {
            $category->posts_count = $this->Posts_model->count_posts_in_category($category->id);
        }
    }

    $this->form_validation->set_rules('title', 'Title', 'required');
    $this->form_validation->set_rules('desc', 'Short description', 'required');
    $this->form_validation->set_rules('body', 'Body', 'required');
    $this->form_validation->set_error_delimiters('<p class="error-message">', '</p>');

    if($this->form_validation->run() === FALSE){
        $this->load->view('partials/header', $data);
        $this->load->view('dashboard/create-post');
        $this->load->view('partials/footer');
    } else {
        $upload = $this->uploadFile();

        if($upload['status'] === FALSE){
            $data['upload_error'] = $upload['message'];

            $this->load->view('partials/header', $data);
            $this->load->view('dashboard/create-post', $data);
            $this->load->view('partials/footer');
        }else{
            // Create slug (from title)
            $slug = url_title(convert_accented_characters($this->input->post('title')), 'dash', TRUE);
            $slugcount = $this->Posts_model->slug_count($slug, null);
            if ($slugcount > 0) {
                $slug = $slug."-".$slugcount;
            }

            $this->Posts_model->create_post($upload['file_name'], $slug);
            $this->session->set_flashdata('post_created', 'Your post has been created');
            redirect('/');
        }
    }
}

And finally add this line of code on your 'dashboard/create-post' view file, right after file input button.

<?php if(isset($upload_error)) echo $upload_error; ?>

I think all should work.

Sign up to request clarification or add additional context in comments.

2 Comments

What I need is a way to tell the user that she/he tried to load the wrong file-type (a PDF, for instance), not that no file was uploaded. If no file is uploaded, then there is a default image (see $config['allowed_types'] = 'jpg|jpeg|png';).
CodeIgniter does not provide any option to customize upload error messages. Instead, you can do following - 1. Tell the user which file types are supported to upload in create post page. 2. Use the accept attribute in your files input. It will only show accepted file types while selecting a file. Check W3Schools for the attributes usage. Also there was a typo on uploadFile() method which I have updated. Please replace the code with the updated one.
1

There are three things I picked up here

1) not passing $data to the correct view as mentioned before

2) expecting array instead of string on the view ie wrong data type

3) lastly function do_upload() expects parameter string $field. This is missing that's why you are having only the no upload selected error. If this parametre is set codeigniter really throws wrong filetype error. I did this to test

on my view

<form action="http://localhost:8000/welcome/create" method="post" enctype="multipart/form-data">
          <input type="file" name="lname" ><br>
          <input type="submit" value="Submit">
        </form>

then in my controller

if(!$this->upload->do_upload("lname")){

Upload a wrong file type to test this error. You may need to go an extra length to detect the filetype for the actual upload file.

Comments

1

I have succeeded to display the upload errors (if upload is attempted, otherwise a default image is used) by modifying create() this way:

public function create() {

    // Only logged in users can create posts
    if (!$this->session->userdata('is_logged_in')) {
        redirect('login');
    }

    $data = $this->get_data();
    $data['tagline'] = "Add New Post";

    if ($data['categories']) {
        foreach ($data['categories'] as &$category) {
            $category->posts_count = $this->Posts_model->count_posts_in_category($category->id);
        }
    }

    $this->form_validation->set_rules('title', 'Title', 'required');
    $this->form_validation->set_rules('desc', 'Short description', 'required');
    $this->form_validation->set_rules('body', 'Body', 'required');
    $this->form_validation->set_error_delimiters('<p class="error-message">', '</p>');

    if($this->form_validation->run() === FALSE){
        $this->load->view('partials/header', $data);
        $this->load->view('dashboard/create-post');
        $this->load->view('partials/footer');
    } else {
        // Create slug (from title)
        $slug = url_title(convert_accented_characters($this->input->post('title')), 'dash', TRUE);
        $slugcount = $this->Posts_model->slug_count($slug, null);
        if ($slugcount > 0) {
            $slug = $slug."-".$slugcount;
        }

        // Upload image
        $config['upload_path'] = './assets/img/posts';
        $config['allowed_types'] = 'jpg|jpeg|png';
        $config['max_size'] = '2048';

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

        if(!$this->upload->do_upload()){

            $errors = array('error' => $this->upload->display_errors());

            // Display upload validation errors 
            // only if a file is uploaded and there are errors
            if (empty($_FILES['userfile']['name'])) {
                $errors = [];
            }

            if (empty($errors)) {
                $post_image = 'default.jpg';
            } else {
                $data['upload_errors'] = $errors;
            }

        } else {
            $data = array('upload_data' => $this->upload->data());
            $post_image = $_FILES['userfile']['name'];
        }

        if (empty($errors)) {
            $this->Posts_model->create_post($post_image, $slug);
            $this->session->set_flashdata('post_created', 'Your post has been created');
            redirect('/');
        } else {
            $this->load->view('partials/header', $data);
            $this->load->view('dashboard/create-post');
            $this->load->view('partials/footer');
        }
    }
}

In the create-post.php view I have:

<?php if(isset($upload_errors)){
   foreach ($upload_errors as $upload_error) {
    echo $upload_error;
   }
 }?>

Comments

0

This error tells you that a variable doesn't exist or was not initialized. Looking at this code

$data['uerrors'] = $this->upload->display_errors();

if ($data['uerrors']) {

I think that you probably have a $uerrors variable somewhere (not shown in this code) which was not initialized. Note that I do not believe that the array index 'uerrors' would cause you trouble in the chunk above, because, first of all you define it and second, if you reference an array item which does not exist, then you will get a different error message from the one quoted in the question.

3 Comments

I know, but I did pass it to $data, so why the error?
I posted the entire create() method.
@RazvanZamfir at which line is it crashing? Is it if ($data['uerrors']) {
0

Your question is a bit vague. Whatever, the only condition in which the variable $uerrors will set is when create() method will execute which I believe would get executed on POST request. Besides, you didn't mention which part of view is this:

<?php foreach ($uerrors as $uerror): ?>
  <span><?php echo $uerror; ?> </span>
<?php endforeach; ?>

If it's dashboard/create-post view then try passing $data directly to this view instead of passing it to partials/header

Note: I just checked the codeigniter View/Controller samples and I found it to be a good practice to check variable using isset() function call, so instead of executing foreach loop directly, do this:

<? if (isset($uerrors)): ?>
    <? foreach ($uerrors as $uerror): ?>
      <span><?= $uerror; ?></span>
    <? endforeach; ?> 
<? endif; ?> 

2 Comments

Besides, I also checked the dashboard/create-post view and I didn't find any foreach loop so that I can verify. Is it the correct file or another file?
I did not push that part to GitHub, it throws an error. :)
0

You need to initialize $data['uerrors'] as null because you are using it on the front end

$data['uerrors'] = '';

or check the value is not empty on the frontend.

Frontend, you can do this as:

<?php  if (isset($uerrors) && $uerrors != '') {
            foreach ($uerrors as $uerror) {
                echo '<span>' . $uerror . '</span>';
            }
        } ?>

Your controller will be:

 $data = array();
        // Upload image
        $config['upload_path'] = './assets/img/posts';
        $config['allowed_types'] = 'jpg|jpeg|png';
        $config['max_size'] = '2048';

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

        /*You need to initialize  $data['uerrors'] as null because you are using it on front end*/
        $data['uerrors'] = '';
        if (!$this->upload->do_upload('FilePath')) {
            $data['uerrors'] = $this->upload->display_errors();
            $this->load->view('partials/header', $data);
            $this->load->view('dashboard/create-post');
            $this->load->view('partials/footer');
        } else {
            if (isset($_POST{'your_file'})) {
                /*'check your images here that you are receiving from front end'*/
            } else {
                /*If there is no image, then default image is*/
                $post_image = 'default.jpg';
            }
            $data = array('upload_data' => $this->upload->data());
            $post_image = $_FILES['userfile']['name'];
        }

You can further find useful posts on How to upload image in CodeIgniter?

1 Comment

This work for me. checking variable that it is not null is the solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.