file uploading and creating upload folders with Codeigniter - php

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.

Related

Image Upload to database reference original name

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.

cakePHP 3.0 uploading images

I want to upload images in my cakephp 3.0 app. But I get the error message:
Notice (8): Undefined index: Images [APP/Controller/ImagesController.php, line 55]
Are there already some examples for uploading files (multiple files at once) in cakePHP 3.0? Because I can only find examples for cakePHP 2.x !
I think I need to add a custom validation method in my ImagesTable.php? But I can't get it to work.
ImagesTable
public function initialize(array $config) {
$validator
->requirePresence('image_path', 'create')
->notEmpty('image_path')
->add('processImageUpload', 'custom', [
'rule' => 'processImageUpload'
])
}
public function processImageUpload($check = array()) {
if(!is_uploaded_file($check['image_path']['tmp_name'])){
return FALSE;
}
if (!move_uploaded_file($check['image_path']['tmp_name'], WWW_ROOT . 'img' . DS . 'images' . DS . $check['image_path']['name'])){
return FALSE;
}
$this->data[$this->alias]['image_path'] = 'images' . DS . $check['image_path']['name'];
return TRUE;
}
ImagesController
public function add()
{
$image = $this->Images->newEntity();
if ($this->request->is('post')) {
$image = $this->Images->patchEntity($image, $this->request->data);
$data = $this->request->data['Images'];
//var_dump($this->request->data);
if(!$data['image_path']['name']){
unset($data['image_path']);
}
// var_dump($this->request->data);
if ($this->Images->save($image)) {
$this->Flash->success('The image has been saved.');
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error('The image could not be saved. Please, try again.');
}
}
$images = $this->Images->Images->find('list', ['limit' => 200]);
$projects = $this->Images->Projects->find('list', ['limit' => 200]);
$this->set(compact('image', 'images', 'projects'));
$this->set('_serialize', ['image']);
}
Image add.ctp
<?php
echo $this->Form->input('image_path', [
'label' => 'Image',
'type' => 'file'
]
);
?>
Image Entity
protected $_accessible = [
'image_path' => true,
];
In your view file, add like this, in my case Users/dashboard.ctp
<div class="ChImg">
<?php
echo $this->Form->create($particularRecord, ['enctype' => 'multipart/form-data']);
echo $this->Form->input('upload', ['type' => 'file']);
echo $this->Form->button('Update Details', ['class' => 'btn btn-lg btn-success1 btn-block padding-t-b-15']);
echo $this->Form->end();
?>
</div>
In your controller add like this, In my case UsersController
if (!empty($this->request->data)) {
if (!empty($this->request->data['upload']['name'])) {
$file = $this->request->data['upload']; //put the data into a var for easy use
$ext = substr(strtolower(strrchr($file['name'], '.')), 1); //get the extension
$arr_ext = array('jpg', 'jpeg', 'gif'); //set allowed extensions
$setNewFileName = time() . "_" . rand(000000, 999999);
//only process if the extension is valid
if (in_array($ext, $arr_ext)) {
//do the actual uploading of the file. First arg is the tmp name, second arg is
//where we are putting it
move_uploaded_file($file['tmp_name'], WWW_ROOT . '/upload/avatar/' . $setNewFileName . '.' . $ext);
//prepare the filename for database entry
$imageFileName = $setNewFileName . '.' . $ext;
}
}
$getFormvalue = $this->Users->patchEntity($particularRecord, $this->request->data);
if (!empty($this->request->data['upload']['name'])) {
$getFormvalue->avatar = $imageFileName;
}
if ($this->Users->save($getFormvalue)) {
$this->Flash->success('Your profile has been sucessfully updated.');
return $this->redirect(['controller' => 'Users', 'action' => 'dashboard']);
} else {
$this->Flash->error('Records not be saved. Please, try again.');
}
}
Before using this, create a folder in webroot named upload/avatar.
Note: The input('Name Here'), is used in
$this->request->data['upload']['name']
you can print it if you want to see the array result.
Its works like a charm in CakePHP 3.x
Now that everyone makes advertisement for his plugins here, let me do this as well. I've checked the Uploadable behavior linked in the other question, it's pretty simple and half done it seems.
If you want a complete solution that is made to scale on enterprise level check FileStorage out. It has some features I haven't seen in any other implementations yet like taking care of ensuring your won't run into file system limitations in the case you get really many files. It works together with Imagine to process the images. You can use each alone or in combination, this follows SoC.
It is completely event based, you can change everything by implementing your own event listeners. It will require some intermediate level of experience with CakePHP.
There is a quick start guide to see how easy it is to implement it. The following code is taken from it, it's a complete example, please see the quick start guide, it's more detailed.
class Products extends Table {
public function initialize() {
parent::initialize();
$this->hasMany('Images', [
'className' => 'ProductImages',
'foreignKey' => 'foreign_key',
'conditions' => [
'Documents.model' => 'ProductImage'
]
]);
$this->hasMany('Documents', [
'className' => 'FileStorage.FileStorage',
'foreignKey' => 'foreign_key',
'conditions' => [
'Documents.model' => 'ProductDocument'
]
]);
}
}
class ProductsController extends ApController {
// Upload an image
public function upload($productId = null) {
if (!$this->request->is('get')) {
if ($this->Products->Images->upload($productId, $this->request->data)) {
$this->Session->set(__('Upload successful!');
}
}
}
}
class ProductImagesTable extends ImageStorageTable {
public function uploadImage($productId, $data) {
$data['adapter'] = 'Local';
$data['model'] = 'ProductImage',
$data['foreign_key'] = $productId;
$entity = $this->newEntity($data);
return $this->save($data);
}
public function uploadDocument($productId, $data) {
$data['adapter'] = 'Local';
$data['model'] = 'ProductDocument',
$data['foreign_key'] = $productId;
$entity = $this->newEntity($data);
return $this->save($data);
}
}
Maybe the following would help. It's a behavior who helps you to upload files very easy!
http://cakemanager.org/docs/utils/1.0/behaviors/uploadable/
Let me know if you struggle.
Greetz
/*Path to Images folder*/
$dir = WWW_ROOT . 'img' .DS. 'thumbnail';
/*Explode the name and ext*/
$f = explode('.',$data['image']['name']);
$ext = '.'.end($f);
/*Generate a Name in my case i use ID & slug*/
$filename = strtolower($id."-".$slug);
/*Associate the name to the extension */
$image = $filename.$ext;
/*Initialize you object and update you table in my case videos*/
$Videos->image = $image;
if ($this->Videos->save($Videos)) {
/*Save image in the thumbnail folders and replace if exist */
move_uploaded_file($data['image']['tmp_name'],$dir.DS.$filename.'_o'.$ext);
unlink($dir.DS.$filename.'_o'.$ext);
}
<?php
namespace App\Controller\Component;
use Cake\Controller\Component;
use Cake\Controller\ComponentRegistry;
use Cake\Network\Exception\InternalErrorException;
use Cake\Utility\Text;
/**
* Upload component
*/
class UploadRegCompanyComponent extends Component
{
public $max_files = 1;
public function send( $data )
{
if ( !empty( $data ) )
{
if ( count( $data ) > $this->max_files )
{
throw new InternalErrorException("Error Processing Request. Max number files accepted is {$this->max_files}", 1);
}
foreach ($data as $file)
{
$filename = $file['name'];
$file_tmp_name = $file['tmp_name'];
$dir = WWW_ROOT.'img'.DS.'uploads/reg_companies';
$allowed = array('png', 'jpg', 'jpeg');
if ( !in_array( substr( strrchr( $filename , '.') , 1 ) , $allowed) )
{
throw new InternalErrorException("Error Processing Request.", 1);
}
elseif( is_uploaded_file( $file_tmp_name ) )
{
move_uploaded_file($file_tmp_name, $dir.DS.Text::uuid().'-'.$filename);
}
}
}
}
}
We're using https://github.com/josegonzalez/cakephp-upload with great success in our production app, and has done so for quite some time.
Has awesome support for using "Flysystem" (https://flysystem.thephpleague.com/) as well - which is abstractions from specific file system(s) - so moving from normal local file system to S3 is a no-brainer, or Dropbox or whatever place you want :-)
You can find related (high quality) plugins on file uploading right here: https://github.com/FriendsOfCake/awesome-cakephp#files - I've used "Proffer" with success as well, and it's by no means "almost done" or anything alike - both has all my recommendations and is in my eyes production ready!

CodeIgniter File Upload - Fat models skin controllers

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);
}

CakePHP file upload on 000webhost

I am trying to get my app to be able to handle uploads. This is the add action in DealsController.php.
<?php
public function add() {
if ($this->request->is('post')) {
$this->request->data['Deal']['user_id'] = $this->Auth->user('id');
$this->Deal->create();
if ($this->Deal->uploadFile($this->request->data['Deal']['pic'])){
$file = $this->request->data['Deal']['pic'];
$this->request->data['Deal']['pic'] = $this->request->data['Deal']['pic']['name'];
if ($this->Deal->save($this->request->data)) {
$this->Session->setFlash(__('Your deal has been saved. %s', h(serialize($file)) ));
return $this->redirect(array('action' => 'index'));
}
$this->Session->setFlash(__('Unable to add your deal. %s', h(serialize($file)) ));
return $this->redirect(array('action' => 'index'));
}
$this->Session->setFlash(__('Unable to upload the file. Please try again. %s', h(serialize($this->request->data['Deal']['pic']))));
}
}
The uploadFile function is defined in the model in Deal.php
<?php
public function uploadFile( $check ) {
$uploadData = array_shift($check);
if ( $uploadData['size'] == 0 || $uploadData['error'] !== 0) {
return false;
}
$uploadFolder = 'files'. DS .'your_directory';
$fileName = time() . '.pdf';
$uploadPath = $uploadFolder . DS . $fileName;
if( !file_exists($uploadFolder) ){
mkdir($uploadFolder);
}
if (move_uploaded_file($uploadData['tmp_name'], $uploadPath)) {
$this->set('pic', $fileName);
return true;
}
return false;
}
`uploadFile` keeps returning false and I get my
Unable to upload the file. Please try again.
a:5:{s:4:"name";s:7:"012.PDF";s:4:"type";s:15:"application/pdf";s:8:"tmp_name";s:14:"/tmp/phpw0uVGS";s:5:"error";i:0;s:4:"size";i:70118;}
flash. Which is confusing, since it makes it look like the file was actually uploaded to a temp dir. I tried different paths for move_uploaded_file but nothing worked. Does this have something to do with file permissions? It couldn't be file-size, since my upload file was only about 80 KB.
Solution: Don't try to code it yourself. Use one of the already existing file upload plugins for CakePHP, which will handle all the ins and outs behind the scenes, with minimal coding on your part.
I personally use https://github.com/josegonzalez/upload

CodeIgniter Image Upload Not Working and No Errors

Okay so I've been messing with this for a couple hours now, reading the docs and browsing forums but I cannot find out why this upload form isn't working.
The entire form works perfectly, data saves to the DB and everything. But I just added an image upload input and it doesn't work! I have followed the exact tutorial in the docs, as well as several others.
Here is the code that processes the form submit ($this->page_m is my model):
public function edit ($id = NULL)
{
// Fetch a page or set a new one
if ($id) {
$this->data['page'] = $this->page_m->get($id);
count($this->data['page']) || $this->data['errors'][] = 'page could not be found';
}
else {
$this->data['page'] = $this->page_m->get_new();
}
// Pages for dropdown
$this->data['pages_no_parents'] = $this->page_m->get_no_parents();
// Process the form
if ($this->form_validation->run('page_rules') == TRUE) {
$data = $this->page_m->array_from_post(array(
'title',
'slug',
'body',
'template',
'parent_id'
));
if(!empty($_FILES['userfile'])) {
$this->do_upload();
}
$this->page_m->save($data, $id);
redirect('admin/page');
}
// Load the view
$this->data['subview'] = 'admin/page/edit';
$this->load->view('admin/_layout_main', $this->data);
}
and here is the code that processes the photo upload, which is called right after the $this->form_validation->run() check:
//upload a slider photo
public function do_upload() {
$config = array(
'allowed_types' => 'jpg|jpeg|gif|png',
'upload_path' => site_url('uploads/')
);
$this->load->library('upload');
$this->upload->initialize($config);
$field_name = "userfile";
if ( ! $this->upload->do_upload($field_name)) {
$this->data['error'] = array('error' => $this->upload->display_errors());
$this->data['subview'] = 'admin/page/edit';
$this->load->view('admin/_layout_main', $this->data);
} else {
return true;
}
}
I have purposely made this upload script as simple and basic as possible for debugging purposes, but still I have had no success in getting this form to upload properly.
After I get the upload working I need to save the image name in my database table, but that is besides the point right now. I just need to get this actually uploading.
SOLVED -- INVALID UPLOAD DIRECTORY
To debug your script you should try and echo out the value returned by $this->upload->display_errors();
Try changing your do_upload() methods last if{} else {} statement to the following:
if ( ! $this->upload->do_upload($field_name)) {
// return the error message and kill the script
echo $this->upload->display_errors(); die();
$this->data['error'] = array('error' => $this->upload->display_errors());
$this->data['subview'] = 'admin/page/edit';
$this->load->view('admin/_layout_main', $this->data);
} else {
return true;
}
Hopefully this will help you find out what is causing the problem.
same problem with mine, I resolve that by upgrading CodeIgniter,
my old version is 3.1.2, then i just upgrade to CI-3.1.3,
just replace the system folder in root folder,
after that, the problem resolve in live server,
i hope my suggest is useful to use

Categories