I'd like to ask a question please.
I have inside my model a method that holds both file uploading and image manipulation. The code works fine, but the only problem is I can't figure out how to get the upload error back in the controller in order to pass it to the view and display it to the user.
This is the code in my model:
class Foo_Model extends CI_Model
{
public function do_upload(){
$id = intval($this->input->post('id'));
$config = array(
'upload_path' => './uploads/files/',
'allowed_types' => 'gif|jpg|png',
'max_size' => '2048',
'max_width' => '800',
'max_heigth' => '300',
'overwrite' => true,
'file_name' => 'file_'.$id, // e.g. file_10.jpg
);
$this->load->library('upload', $config);
if ( ! $this->upload->do_upload('file') ) {
return $this->upload->display_errors();
} else {
// file uploaded successfully
// now lets create some thumbs
$upload_file = $this->upload->data();
if ($upload_file['is_image']) {
$config['image_library'] = 'gd2';
$config['source_image'] = $upload_file['file_name'];
$config['create_thumb'] = TRUE;
$config['maintain_ratio'] = TRUE;
$config['width'] = 75;
$config['height'] = 50;
$this->load->library('image_lib', $config);
$this->image_lib->resize();
}
// uploading and resizing was done
return $upload_file;
// return true;
}
}
}
Code in my controller
public function upload(){
$this->foo_model->do_upload();
// need to get the upload error (if any occured) or the upload data
// how can I get them back from function of the model?
$this->load->view('form_upload', $data);
}
You are return errors from Model method so hold returned data in variable and check that is error or file_data
public function upload(){
$upload_data = $this->foo_model->do_upload();
//upload data will be return in array format
if(is_array($upload_data)){
$data['upload_file_info'] = $upload_data
}else{ /*error as string so if not array then always error*/
$data['error'] = $upload_data;
}
$this->load->view('form_upload', $data);
}
Related
I am working on a codeigniter project. In the image upload config I have it as encrypted to allow unique file names to avoid overwriting and doubling of name and for more security in general.
So on upload it will encrypt the image file name, and store the encrypted name in the database while saving the image in my assets folder. But for some reason it doesn't seem to encrypt the image names at all. Almost like it is completely ignoring the $config options and just uploading the image.
Also I have attempted a call back function to avoid blank uploads and again seems that is ignored also and the post are still allowed.
If anyone can lend a tip. Please.
Controller
//Callback validation
$this->form_validation->set_rules('userfile','Photo','callback_photo_check');
if($this->form_validation->run() === FALSE){
$this->load->view('templates/header');
$this->load->view('posts/create', $data);
$this->load->view('templates/footer');
} else {
if($this->form_validation->run()==TRUE){
$config['upload_path'] = 'assets/images/posts';
$config['allowed_types'] = 'gif|jpg|jpeg';
$config['encrypt_name'] = TRUE; //TURN ON
$config['max_size'] = 0;
$config['max_width'] = 0;
$config['max_height'] = 0;
$this->upload->initialize($config);
if(!$this->upload->do_upload('userfile')){
$errors = array('error'=>$this->upload->display_errors());
$this->load->view('templates/header');
$this->load->view('posts/create', $errors);
$this->load->view('templates/footer');
}else {
$this->post_model->create_post($this->upload->data('full_path'),$this->input->post());
}
}
$this->session->set_flashdata('post_created','Your Post has been submitted');
redirect('posts');
}
}
public function photo_check(){
if(empty($_FILES['userfile'])){
$this->form_validation->set_message('photo_check', 'need a image');
return FALSE;
}
else{
return TRUE;
}
}
Model
public function create_post($path,$post){
$data = array(
'about'=> $this->input->post('Description'),
'image' => $path,
);
return $this->db->insert('posts',$data);
I have the same problem before, then I decided to give them(files) a unique name, what I did is:
• I assigned an empty variable which will hold the file name/ path data meant to be modified and I named it as $info_name.
• Everytime the file name will have a duplicate in the existing location it will add a unique extension such as time(seconds,date, etc).
Here is my sample code:
public function new_info($data,$photo){
extract($data);
$info_name = "";
$directory = "C:/xampp/htdocs/Parent folder/child folder/grand child folder/";
$extension= array("jpeg","jpg","png","gif");
$file_name=$photo["form_name"]["name"];
$file_tmp=$photo["form_name"]["tmp_name"];
$ext=pathinfo($file_name,PATHINFO_EXTENSION);
if(in_array($ext,$extension)){
if(!file_exists($directory.$file_name)){
move_uploaded_file($file_tmp=$photo["form_name"]["tmp_name"],$directory.$file_name);
$info_name = $file_name;
}
else{
$filename=basename($file_name,$ext);
$newFileName=$filename.time().".".$ext;
move_uploaded_file($file_tmp=$photo["form_name"]["tmp_name"],$directory.$newFileName);
$info_name = $newFileName;
}
}
// then your sql code here for example:
$data= array( 'user' => $_SESSION["user_id"],
'picture' => $info_name,
);
$this->db->insert('sys_post',$data);
}
To encrypt the uploaded file names, you have to follow below steps.
1) You have to load the Encryption Library.
You can call this library on particular page where there is upload code.
// LOAD LIBRARIES
$this->load->library('encryption');
OR you can also load it in autoload.php file in $autoload['libraries'] = array('database','form_validation','encryption');
2) Now you are using the Encryption class, you must set an encryption key in config.php file.
$config['encryption_key'] = 'your-own-encryption-key';
For more information regarding Encryption => https://codeigniter.com/user_guide/libraries/encryption.html
3) And finally, In your upload code $config['encrypt_name'] = TRUE;.
Hope this will help.
Usually we can get the form data in Codeigniter by using $this->input->get('field_name') or $this->input->post('field_name') and that's fine.
In raw PHP we use $_FILES["fileToUpload"]["name"] to get the file name that the user trying to upload.
My question is: Is there any Codeigniter way to get the name of the file that needs to be uploaded?
I am trying to say that i need to get the file name that the user is trying to upload before trying to save it in my server using Codeigniter library instead of using raw PHP global $_FILES variable.
<?php
class Upload extends CI_Controller {
public function __construct()
{
parent::__construct();
$this->load->helper(array('form', 'url'));
}
public function index()
{
$this->load->view('upload_form', array('error' => ' ' ));
}
public function do_upload()
{
$config['upload_path'] = './uploads/';
$config['allowed_types'] = 'gif|jpg|png';
$config['max_size'] = 100;
$config['max_width'] = 1024;
$config['max_height'] = 768;
$this->load->library('upload', $config);
// get the user submitted file name here
if ( ! $this->upload->do_upload('userfile'))
{
$error = array('error' => $this->upload->display_errors());
$this->load->view('upload_form', $error);
}
else
{
$data = array('upload_data' => $this->upload->data());
$this->load->view('upload_success', $data);
}
}
}
?>
$upload_data = $this->upload->data();
$file_name = $upload_data['file_name'];
Here is the 2 version doc is for 2 and for 3
if you want to get the file name in backend:
$this->upload->file_name It will work based on system/library/upload.php
this function.
public function data()
{
return array (
'file_name' => $this->file_name,
'file_type' => $this->file_type,
...
);
}
If you need to get file name...
Before saving to server... you have work in javascript
<?php echo "<input type='file' name='userfile' size='20' onchange='changeEventHandler(event);' />"; ?>
onchange event in javascript:
<script>
function changeEventHandler(event){
alert(event.target.value);
}
</script>
$data = array('upload_data' => $this->upload->data());
// use file_name within the data() the final code will be
$data = array('upload_data' => $this->upload->data('file_name'));
I made a custom function before working with framework, that I want to use again now. the problem occurs when I tried uploading image with my custom function. it says error undefined index : [the field_name].
most people uses CI library and CI upload function do_upload() but I want to use my own function because it also creates smaller image to be used as thumb.
I started working with CI 3 days ago, and still don't know how to change anything that can make $_FILES[] working.
the view :
<form action="path/to/controller/method" method="post" enctype="multipart/form-data">
<input type="file" name="fupload">
</form>
the controller :
public function __construct(){
parent::__construct();
$this->load->helper('fungsi_thumb'); // this is the custom function
$config['allowed_types'] = '*';
$this->load->library('upload',$config);
}
public function input_file(){
$data = array(
'location_file' => $_FILES['fupload']['tmp_name'],
'type_file' => $_FILES['fupload']['type'],
'name_file' => $_FILES['fupload']['name']
);
$this->load->model('input_model');
$this->input_model->put_file($data);
}
I already put my custom function file in application\helpers\. Should I show the custom function file and the model file too?
I already change the public $allowed_types = '*'; too
UPDATE
the Model
public function put_file($data){
//BUAT FILE
$lokasi_file = $data['location_file'];
$tipe_file = $data['type_file'];
$nama_file = $data['name_file'];
$acak = rand(1,99);
$nama_file_unik = $acak.$nama_file;
UploadImage($nama_file_unik); // this is my custom function
$sql="INSERT INTO produk(gambar)VALUES (?)";
$query=$this->db->query($sql,array($nama_file_unik));
if($query)
{
echo "BERHASIL";
}
else
{
echo "GAGAL";
}
}
UPDATE NEW
I finally able to use $_FILES, I need to load the library inside the controller Constructor.
now the new problem is there is no file uploaded even using do_upload() function inside my own custom made function
this is my custom made function
function UploadImage($fupload_name){
// SET DATA FILE NYA
$config['file_name'] = $fupload_name;
$config['upload_path'] = 'http://localhost/mobileapp/assets/gambar/';
var_dump($config['upload_path']);
//load the upload library
$CI =& get_instance();
$CI->load->library('upload',$config);
//Upload the file
if( !($CI->upload->do_upload('fupload'))){
$error = $CI->upload->display_errors();
}else{
$file_data = $CI->upload->data();
}
}
now as you can see above, I'm trying to change the file_name to a new randomly-generated name (done in the model) using $config['file_name'] = $fupload_name; and making a new object because obviously I need to do this to load library and use the do_upload() method.
but I still cannot use it. now I'm stuck again
Pass $_FILES array from controller to model function, add new file name in config array and use do_upload() directly like,
Controller Function:
public function input_file(){
$this->load->model('input_model');
$this->input_model->put_file($_FILES); // pass $_FILES Array
}
Model Function:
public function put_file($files){
$config['allowed_types'] = '*';
$acak = rand(1,99);
$config['file_name'] = $acak.$files['fupload']['name'];
$this->load->library('upload',$config);
$data = array(
'location_file' => $files['fupload']['tmp_name'],
'type_file' => $files['fupload']['type'],
'name_file' => $files['fupload']['name']
);
if (!$this->upload->do_upload('fupload')) { // pass field name here
$this->upload->display_errors('<p>', '</p>');
} else {
$sql="INSERT INTO produk(gambar)VALUES (?)";
$query=$this->db->query($sql,array($nama_file_unik));
if($query) {
echo "BERHASIL";
} else {
echo "GAGAL";
}
}
}
upload_path in configs must be absolute or relative path and not an url.
So you can something like this():
$config['upload_path'] = './uploads/';
OR this:
$config['upload_path'] = FCPATH . 'uploads/';
Note: FCPATH is absolute path of your index.php folder.
A PHP Error was encountered
Severity: Notice Message:
Undefined index: uploadimg
Filename: models/upload_model.php
Line Number: 26
My code:
Controller
public function do_upload(){
$this->upload->do_upload();
if($this->upload_model->Doupload()){
echo 1;
}else{
echo 0;
}
}
private function set_config_option(){
$config =array(
'allowed_type' => 'gif|jpg|png|jpeg|pdf|doc|xml|zip|rar',
'file_size' => '100',
'max_width' => '1024',
'overwrite' => TRUE,
'max_height' => '768',
);
return $config;
}
Model
private function set_config_option(){
$config =array(
'allowed_type' => 'gif|jpg|png|jpeg|pdf|doc|xml|zip|rar',
'file_size' => '2048000',
'max_width' => '1024',
'overwrite' => TRUE,
'max_height' => '768'
);
return $config;
}
public function Doupload(){
$target_path = 'uploads/';
$target_file = $target_path. basename($_FILES['uploadimg']['name']);
$base_url = base_url();
$img_title = $this->input->post('imgname');
$this->upload->initialize('upload', $this->set_config_option());
// $img = $this->upload->do_upload();
}
Please help me...
The model isn't receiving the $_FILES object. Why you separate the upload proccess in 2 files (model & controller?, you store something in the database?). In the codeiniter documentation: https://ellislab.com/codeigniter/user-guide/libraries/file_uploading.html is all in the same file (controller).
Try following the example or try to add in the controller:
$this->upload_model->Doupload($_FILES);
and in the model:
public function Doupload($file){
$target_path = 'uploads/';
$target_file = $target_path. basename($file['uploadimg']['name']);
I guess you load the library with: $this->load->library('upload'); or by autoload config class. Hope it helps!
Add this to your ajax request and if that helps :)
And i assume you using form/multipart
xhr: function() {
var myXhr = $.ajaxSettings.xhr();
return myXhr;
},
I'm having this function inside my Album_Model:
public function upload($album_id, $album){
$album= strtolower($album);
$upload_config = array(
'upload_path' => './uploads/'.$album,
'allowed_types' => 'jpg|jpeg|gif|png',
'max_size' => '2000',
'max_width' => '680',
'max_height' => '435',
);
$this->load->library('upload', $upload_config);
// create an album if not already exist in uploads dir
// wouldn't make more sence if this part is done if there are no errors and right before the upload ??
if (!is_dir('uploads')) {
mkdir('./uploads', 0777, true);
}
if (!is_dir('uploads/'.$album)) {
mkdir('./uploads/'.$album, 0777, true);
}
if (!$this->upload->do_upload('imgfile')) {
// upload failed
return array('error' => $this->upload->display_errors('<span>', '</span>'));
} else {
// upload success
$upload_data = $this->upload->data();
return true;
}
}
So what this basicly does is to upload images to an album. Also if the folder album does not exist already, it creates a new album.
I was doing some tests and found out something that might be a small bug. While I was forcing my form to do some invalid upload attempts and the upload fails, as expected, but the album folder (suppose the album folder doesn't exist) is still created.
Whouldn't make more sence to create the album folder if there are no erros and right before uploading the image and if yes how can I fix this??
You have set a flag for checking the directory existence. I have changed your code to make it work as per your need.
<?php
public function upload($album_id, $album)
{
$album = strtolower($album);
$upload_config = array('upload_path' => './uploads/' . $album, 'allowed_types' =>
'jpg|jpeg|gif|png', 'max_size' => '2000', 'max_width' => '680', 'max_height' =>
'435', );
$this->load->library('upload', $upload_config);
// create an album if not already exist in uploads dir
// wouldn't make more sence if this part is done if there are no errors and right before the upload ??
if (!is_dir('uploads'))
{
mkdir('./uploads', 0777, true);
}
$dir_exist = true; // flag for checking the directory exist or not
if (!is_dir('uploads/' . $album))
{
mkdir('./uploads/' . $album, 0777, true);
$dir_exist = false; // dir not exist
}
else{
}
if (!$this->upload->do_upload('imgfile'))
{
// upload failed
//delete dir if not exist before upload
if(!$dir_exist)
rmdir('./uploads/' . $album);
return array('error' => $this->upload->display_errors('<span>', '</span>'));
} else
{
// upload success
$upload_data = $this->upload->data();
return true;
}
}
?>
THE ACCEPTED ANSWER IS NOT THE RIGHT WAY!!!
The right way is to extend the Upload library
The code:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* File Uploading Class Extension
*
* #package CodeIgniter
* #subpackage Libraries
* #category Uploads
* #author Harrison Emmanuel (Eharry.me)
* #link https://www.eharry.me/blog/post/my-codeigniter-upload-extension/
*/
class MY_Upload extends CI_Upload {
/**
* Validate Upload Path
*
* Verifies that it is a valid upload path with proper permissions.
*
* #return bool
*/
public function validate_upload_path()
{
if ($this->upload_path === '')
{
$this->set_error('upload_no_filepath', 'error');
return FALSE;
}
if (realpath($this->upload_path) !== FALSE)
{
$this->upload_path = str_replace('\\', '/', realpath($this->upload_path));
}
if ( ! is_dir($this->upload_path))
{
// EDIT: make directory and try again
if ( ! mkdir ($this->upload_path, 0777, TRUE))
{
$this->set_error('upload_no_filepath', 'error');
return FALSE;
}
}
if ( ! is_really_writable($this->upload_path))
{
// EDIT: change directory mode
if ( ! chmod($this->upload_path, 0777))
{
$this->set_error('upload_not_writable', 'error');
return FALSE;
}
}
$this->upload_path = preg_replace('/(.+?)\/*$/', '\\1/', $this->upload_path);
return TRUE;
}
}
How to use:
Simply create application/libraries/MY_Upload.php and paste the code above in it.
That's all!
More info:
The GitHub Gist.
My blog post on Eharry.me
NOTE:
This extension is compatible with CodeIgniter 3.x and 2.x versions.
The way you have it it will always make the directory if it does not exist.
To answer your question.. yes, it would make more sense, to create the folder right before uploading.
Try putting this:
if (!is_dir('uploads')) {
mkdir('./uploads', 0777, true);
}
if (!is_dir('uploads/'.$album)) {
mkdir('./uploads/'.$album, 0777, true);
}
Inside this:
if (!$this->upload->do_upload('imgfile')) {
// upload failed
return array('error' => $this->upload->display_errors('<span>', '</span>'));
} else {
// put if statements here.
// upload success
$upload_data = $this->upload->data();
return true;
}
So it would look like this:
if (!$this->upload->do_upload('imgfile')) {
// upload failed
return array('error' => $this->upload->display_errors('<span>', '</span>'));
} else {
if (!is_dir('uploads')) {
mkdir('./uploads', 0777, true);
}
if (!is_dir('uploads/'.$album)) {
mkdir('./uploads/'.$album, 0777, true);
}
// upload success
$upload_data = $this->upload->data();
return true;
}
If I understand you correctly this should do what you want.
Hope it helps.