codeigniter load external config file - codeigniter

I'm working with CodeIgniter and I’d like to load one or more config files located in an external folder, shared by different CI installation.
Is it possible?
I tried to extend the Loader Class, and call the new method:
$this -> load -> external_config(‘MY\EXTERNAL\PATH’);
Load is successful, but i can’t retrieve config items in my controller, because in MY_Loader class the core\Loader config property is not visible, and i can’t merge it with the new loaded values.
This is my code:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class MY_Loader extends CI_Loader {
/**
* List of all loaded config files
*
* #var array
*/
var $is_config_loaded = array();
/**
* List of all loaded config values
*
* #var array
*/
//var $ext_config = array();
function __construct(){
parent::__construct();
}
/**
* Loads an external config file
*
* #param string
* #param bool
* #param bool
* #return void
*/
public function external_config($file = '', $use_sections = FALSE, $fail_gracefully = FALSE)
{
$file = ($file == '') ? 'config' : str_replace('.php', '', $file);
$found = FALSE;
$loaded = FALSE;
$check_locations = defined('ENVIRONMENT')
? array(ENVIRONMENT.'/'.$file, $file)
: array($file);
foreach ($check_locations as $location)
{
$file_path = $file.'.php';
if (in_array($file_path, $this->is_config_loaded, TRUE))
{
$loaded = TRUE;
continue 2;
}
if (file_exists($file_path))
{
$found = TRUE;
break;
}
}
if ($found === FALSE)
{
if ($fail_gracefully === TRUE)
{
return FALSE;
}
show_error('The configuration file '.$file.'.php does not exist.');
}
else{
include($file_path);
if ( ! isset($config) OR ! is_array($config))
{
if ($fail_gracefully === TRUE)
{
return FALSE;
}
show_error('Your '.$file_path.' file does not appear to contain a valid configuration array.');
}
if ($use_sections === TRUE)
{
if (isset($this->ext_config[$file]))
{
$this->ext_config[$file] = array_merge($this->ext_config[$file], $config);
}
else
{
$this->ext_config[$file] = $config;
}
}
else
{
$this->ext_config = array_merge($this->ext_config, $config);
}
$this->is_config_loaded[] = $file_path;
unset($config);
$loaded = TRUE;
log_message('debug', 'Config file loaded: '.$file_path);
}
return TRUE;
}
}
I found in core\Config.php a property
var $_config_paths = array(APPPATH);
With the paths in wich look for config files.
How can i add paths to the array without chance the core classe code?
Any ideas?
Thank you very much!!!

CodeIgniter makes assumptions about the config file being loaded, its location, its file ext etc. You may load other files that is: from the same directory (support seems to be limited to this usage scenario).
However, you can (looking at the chapter https://ellislab.com/codeigniter/user-guide/libraries/config.html (Setting a Config Item)) iterate your file values and set them like so
(todo: add some checks if file exists, is readable, no decoding errors etcetera)
$myConfigValues = json_decode(file_get_contents($configKeyValuesFromOuterSpace));
foreach($myConfigValues as $key => $value){
$CI->config->set_item('item_name', 'item_value');
}
As for the exposure of the config object, in the loader you may anytime examine its public parts in more or less subtle manners, by using the code igniter singleton instance retrieval method:
$CI =& get_instance();
die(print_r($CI->config,true));
This will be a CI_Config object. You may also create a MY_Config extension.

Related

ErrorException in AssetController.php line 21: Trying to get property of non-object

I have this code source that i'm trying to use in one of my projects, it worked with laravel 5.2. This the function in the assetController:
namespace App\Http\Controllers;
use App\Setting;
use File;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class AssetController extends Controller
{
/**
* List all image from image directory
*/
public function getAsset()
{
//Get Admin Images
$adminImages = array();
//get image file array
$images_dir = Setting::where('name', 'images_dir')->first();
$folderContentAdmin = File::files($images_dir->value);
//check the allowed file extension and make the allowed file array
$allowedExt = Setting::where('name', 'images_allowedExtensions')->first();
$temp = explode('|', $allowedExt->value);
foreach ($folderContentAdmin as $key => $item)
{
if( ! is_array($item))
{
//check the file extension
$ext = pathinfo($item, PATHINFO_EXTENSION);
//prep allowed extensions array
if (in_array($ext, $temp))
{
array_push($adminImages, $item);
}
}
}
//Get User Images
$userImages = array();
$userID = Auth::user()->id;
$images_uploadDir = Setting::where('name', 'images_uploadDir')->first();
if (is_dir( $images_uploadDir->value . "/" .$userID ))
{
$folderContentUser = File::files($images_uploadDir->value . "/" .$userID );
if ($folderContentUser)
{
foreach ($folderContentUser as $key => $item)
{
if ( ! is_array($item))
{
//check the file extension
$ext = pathinfo($item, PATHINFO_EXTENSION);
//prep allowed extensions array
//$temp = explode("|", $this->config->item('images_allowedExtensions'));
if (in_array($ext, $temp))
{
array_push($userImages, $item);
}
}
}
}
}
//var_dump($folderContent);
//var_dump($adminImages);
return view('assets/images', compact('adminImages', 'userImages'));
}
The problem is in the line 21 :
//get image file array
$images_dir = Setting::where('name', 'images_dir')->first();
$folderContentAdmin = File::files($images_dir->value);
From my research I find out that the reason is because the setting table is empty which it is true.
Please tell me if there is another cause to that problem if it's not the case I need a solution because I don't have a way to fill that table except doing it from the database itself (phpmyAdmin)

Saving multiple images for one product using one to many in codeigniter

I am new in code igniter.
Here is what I am trying to do. I have lists of products stored in database table name products. For each products i need to insert multiple images. I have created two tables, products and productimage. I have made the product_id of table productimage the foreign key, referencing the product_id of table products. Now i want to save the datas from form. Here is what i did previously Saving images in a single row by imploding
But it became quite difficult for me to manage CRUD(like editing and deleting pictures).
So i am trying to do the above mentioned way. I am not finding the way to start. Can anyone please instruct me, how can I start?
Okay now I have done some coding here. This is my controller:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Products extends CI_Controller{
public function __construct()
{
parent::__construct();
$this->load->model('product_model');
$this->load->helper(array('form','url'));
//Codeigniter : Write Less Do More
}
public function index()
{
$data['products']=$this->product_model->get_product();
$this->load->view('/landing_page',$data);
}
public function create()
{
#code
$this->load->helper('form');
$this->load->library('form_validation');
$this->form_validation->set_rules('product_name','Product_Name','required');
if($this->form_validation->run()=== FALSE)
{
$this->load->view('products/create');
}
else {
$this->product_model->set_product();
$data['products']=$this->product_model->get_product();
redirect('/');
}
}
}
This is my model:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Product_model extends CI_Model{
public function __construct()
{
$this->load->database();
parent::__construct();
//Codeigniter : Write Less Do More
}
public function get_product()
{
#code
$query=$this->db->get('products');
return $query->result_array();
}
public function set_product($id=0)
{
#code
// if($this->input->post('userSubmit')){
$picture=array();
$count=count($_FILES['picture']['name']);
//Check whether user upload picture
if(!empty($_FILES['picture']['name'])){
foreach($_FILES as $value)
{
for($s=0; $s<=$count-1; $s++)
{
$_FILES['picture']['name']=$value['name'][$s];
$_FILES['picture']['type'] = $value['type'][$s];
$_FILES['picture']['tmp_name'] = $value['tmp_name'][$s];
$_FILES['picture']['error'] = $value['error'][$s];
$_FILES['picture']['size'] = $value['size'][$s];
$config['upload_path'] = 'uploads/images/';
$config['allowed_types'] = 'jpg|jpeg|png|gif';
$config['file_name'] = $_FILES['picture']['name'];
//Load upload library and initialize configuration
$this->load->library('upload',$config);
$this->upload->initialize($config);
// print_r($value['name'][$s]);exit;
if($this->upload->do_upload('picture')){
$uploadData = $this->upload->data();
$picture[] = $uploadData['file_name'];
}
else{
$picture = '';
}
}
}
}//end of first if
else{
$picture = '';
}
$data=array(
'product_name'=>$this->input->post('product_name')
);
$picture=array(
'product_id'=>$this->db->get('products',$id),
'picture_image'=>$picture
);
if ($id==0)
{
return $this->db->insert('products',$data);
return $this->db->insert('images',$picture);
}
else {
$this->db->where('id',$id);
return $this->db->update('products',$data);
return $this->db->update('images',$picture);
}
}
}
Noe the case is when my form opens i am being able to fill product name and upload image files. When i submit it doesn't throws any errors too. But only product name is stored in products table and nothing happens to images table. No any images are inserted. Neither any error is thrown by browser. Simply images
table is empty. What's the problem here?
Let me help you with the Controller .. You need to check for all the uploaded files. They are $_FILES. Loop through the array, upload them on the server and than call a model function to add them in your product Images table
If CI Upload is too tricky for you. Use the following Controller function
public function upload_images()
{
// following IF statement only checks if the user is logged in or not
if($this->session->userdata['id'] && $this->session->userdata['type']=='user')
{
if($_FILES)
{
// check whether there are files uploaded / posted
if(isset($_FILES['files'])){
$data['errors']= array();
$extensions = array("jpeg","jpg","png");
//Loop through the uploaded files
foreach($_FILES['files']['tmp_name'] as $key => $tmp_name ){
$file_name = $key.$_FILES['files']['name'][$key];
$file_size =$_FILES['files']['size'][$key];
$file_tmp =$_FILES['files']['tmp_name'][$key];
$i=1;
if($file_size > 2097152){
$data['errors'][$i]='File '.$i.' size must be less than 2 MB';
$i++;
}
// Set upload destination directory
$desired_dir="uploads";
if(empty($data['errors'])==true){
if(is_dir($desired_dir)==false){
mkdir("$desired_dir", 0700); // Create directory if it does not exist
}
if(is_dir("$desired_dir/".$file_name)==false){
// Upload the file.
move_uploaded_file($file_tmp,"uploads/".$file_name);
// Call a function from model to save the name of the image in images table along with entity id
$this->post_model->addImage('property_images',$file_name,$this->uri->segment(3));
}else{ //rename the file if another one exist
$new_dir="uploads/".$file_name.time();
rename($file_tmp,$new_dir) ;
}
}else{
$data['contact']=$this->admin_model->getContactDetails();
$data['images']=$this->post_model->getPropertyImages($this->uri->segment(3));
//load views
}
}
if(empty($data['errors']))
{
redirect(base_url().'dashboard');
}
else
{
$data['contact']=$this->admin_model->getContactDetails();
$data['images']=$this->post_model->getPropertyImages($this->uri->segment(3));
//load views
}
}
}
else
{
//Load view
}
}
else
{
redirect(base_url().'user/login');
}
}
Incase anyone is having the same problem then here is the solution. Just do this in your upload function.(code by my friend Amani Ben azzouz)
public function set_product($id=0){
$picture=array();
$count=count($_FILES['picture']['name']);
//Check whether user upload picture
if(!empty($_FILES['picture']['name'])){
foreach($_FILES as $value){
for($s=0; $s<=$count-1; $s++){
$_FILES['picture']['name']=$value['name'][$s];
$_FILES['picture']['type'] = $value['type'][$s];
$_FILES['picture']['tmp_name'] = $value['tmp_name'][$s];
$_FILES['picture']['error'] = $value['error'][$s];
$_FILES['picture']['size'] = $value['size'][$s];
$config['upload_path'] = 'uploads/images/';
$config['allowed_types'] = 'jpg|jpeg|png|gif';
$config['file_name'] = $_FILES['picture']['name'];
//Load upload library and initialize configuration
$this->load->library('upload',$config);
$this->upload->initialize($config);
// print_r($value['name'][$s]);exit;
if($this->upload->do_upload('picture')){
$uploadData = $this->upload->data();
$picture[] = $uploadData['file_name'];
}
}
}
}//end of first if
$data=array('product_name'=>$this->input->post('product_name'));
if ($id==0){
$this->db->insert('products',$data);
$last_id = $this->db->insert_id();
if(!empty($picture)){
foreach($picture as $p_index=>$p_value) {
$this->db->insert('images', array('product_id'=>$last_id,'images'=>$p_value));
}
}
}
else {
$this->db->where('id',$id);
$this->db->update('products',$data);
if(!empty($picture)){
foreach($picture as $p_index=>$p_value) {
$this->db->update('images', array('product_id'=>$last_id,'images'=>$p_value) ); // --> this one?
}
}
}
}
This is for inserting and updating too. If you simply want do insert just delete the parameter passed as 'id' and cut that if and else part write a plain code of inside 'if'.
function contract_upload(){ // function to call from your view.
$data = array();
// If file upload form submitted
if(!empty($_FILES['files']['name']) AND !empty('user_id')){
$filesCount = count($_FILES['files']['name']);
for($i = 0; $i < $filesCount; $i++){
$_FILES['file']['name'] = $_FILES['files']['name'][$i];
$_FILES['file']['type'] = $_FILES['files']['type'][$i];
$_FILES['file']['tmp_name'] = $_FILES['files']['tmp_name'][$i];
$_FILES['file']['error'] = $_FILES['files']['error'][$i];
$_FILES['file']['size'] = $_FILES['files']['size'][$i];
// File upload configuration
$uploadPath = './uploads/contract/';
$config['upload_path'] = $uploadPath;
$config['allowed_types'] = 'jpg|jpeg|png|gif';
$config['encrypt_name'] = TRUE;
// Load and initialize upload library
$this->load->library('upload', $config);
$this->upload->initialize($config);
// Upload file to server
if($this->upload->do_upload('file')){
// Uploaded file data
$fileData = $this->upload->data();
$uploadData[$i]['file_name'] = $fileData['file_name'];
$uploadData[$i]['emp_id'] = $this->input->post('user_id');
}
}
if(!empty($uploadData)){
// Insert files data into the database
$insert = $this->Contract_model->insert($uploadData);
// Upload status message
$statusMsg = $insert?'Files uploaded successfully.':'Some problem occurred, please try again.';
$this->session->set_flashdata('messageactive', $statusMsg);
}
}
redirect('contract'); // redirect link, where do you want to redirect after successful uploading of the file.
}
// Model Function
public function insert($data = array()){
$insert = $this->db->insert_batch('employee_contract_files', $data); // table name and the data you want to insert into database.
return $insert?true:false;
}
Remember one thing, you should write your HTML as below:
<input type="file" name="files[]" multiple />

fine-uploader PHP Server Side Merge

I'm been experimenting with Fine Uploader. I am really interested in the chunking and resume features, but I'm experiencing difficulties putting the files back together server side;
What I've found is that I have to allow for a blank file extension on the server side to allow the upload of the chunks, otherwise the upload will fail with unknown file type. It uploads the chunks fine with file names such as "blob" and "blob63" (no file extension) however is does not merge them back at completion of upload.
Any help or pointers would be appreciated.
$('#edit-file-uploader').fineUploader({
request: {
endpoint: 'upload.php'
},
multiple: false,
validation:{
allowedExtentions: ['stl', 'obj', '3ds', 'zpr', 'zip'],
sizeLimit: 104857600 // 100mb * 1024 (kb) * 1024 (bytes)
},
text: {
uploadButton: 'Select File'
},
autoUpload: false,
chunking: {
enabled: true
},
callbacks: {
onComplete: function(id, fileName, responseJSON) {
if (responseJSON.success) {
/** some code here **??
}
}
});
And this is the server side script (PHP):
// list of valid extensions, ex. array("stl", "xml", "bmp")
$allowedExtensions = array("stl", "");
// max file size in bytes
$sizeLimit = null;
$uploader = new qqFileUploader($allowedExtensions, $sizeLimit);
// Call handleUpload() with the name of the folder, relative to PHP's getcwd()
$result = $uploader->handleUpload('uploads/');
// to pass data through iframe you will need to encode all html tags
echo htmlspecialchars(json_encode($result), ENT_NOQUOTES);
/******************************************/
/**
* Handle file uploads via XMLHttpRequest
*/
class qqUploadedFileXhr {
/**
* Save the file to the specified path
* #return boolean TRUE on success
*/
public function save($path) {
$input = fopen("php://input", "r");
$temp = tmpfile();
$realSize = stream_copy_to_stream($input, $temp);
fclose($input);
if ($realSize != $this->getSize()){
return false;
}
$target = fopen($path, "w");
fseek($temp, 0, SEEK_SET);
stream_copy_to_stream($temp, $target);
fclose($target);
return true;
}
/**
* Get the original filename
* #return string filename
*/
public function getName() {
return $_GET['qqfile'];
}
/**
* Get the file size
* #return integer file-size in byte
*/
public function getSize() {
if (isset($_SERVER["CONTENT_LENGTH"])){
return (int)$_SERVER["CONTENT_LENGTH"];
} else {
throw new Exception('Getting content length is not supported.');
}
}
}
/**
* Handle file uploads via regular form post (uses the $_FILES array)
*/
class qqUploadedFileForm {
/**
* Save the file to the specified path
* #return boolean TRUE on success
*/
public function save($path) {
return move_uploaded_file($_FILES['qqfile']['tmp_name'], $path);
}
/**
* Get the original filename
* #return string filename
*/
public function getName() {
return $_FILES['qqfile']['name'];
}
/**
* Get the file size
* #return integer file-size in byte
*/
public function getSize() {
return $_FILES['qqfile']['size'];
}
}
/**
* Class that encapsulates the file-upload internals
*/
class qqFileUploader {
private $allowedExtensions;
private $sizeLimit;
private $file;
private $uploadName;
/**
* #param array $allowedExtensions; defaults to an empty array
* #param int $sizeLimit; defaults to the server's upload_max_filesize setting
*/
function __construct(array $allowedExtensions = null, $sizeLimit = null){
if($allowedExtensions===null) {
$allowedExtensions = array();
}
if($sizeLimit===null) {
$sizeLimit = $this->toBytes(ini_get('upload_max_filesize'));
}
$allowedExtensions = array_map("strtolower", $allowedExtensions);
$this->allowedExtensions = $allowedExtensions;
$this->sizeLimit = $sizeLimit;
$this->checkServerSettings();
if(!isset($_SERVER['CONTENT_TYPE'])) {
$this->file = false;
} else if (strpos(strtolower($_SERVER['CONTENT_TYPE']), 'multipart/') === 0) {
$this->file = new qqUploadedFileForm();
} else {
$this->file = new qqUploadedFileXhr();
}
}
/**
* Get the name of the uploaded file
* #return string
*/
public function getUploadName(){
if( isset( $this->uploadName ) )
return $this->uploadName;
}
/**
* Get the original filename
* #return string filename
*/
public function getName(){
if ($this->file)
return $this->file->getName();
}
/**
* Internal function that checks if server's may sizes match the
* object's maximum size for uploads
*/
private function checkServerSettings(){
$postSize = $this->toBytes(ini_get('post_max_size'));
$uploadSize = $this->toBytes(ini_get('upload_max_filesize'));
if ($postSize < $this->sizeLimit || $uploadSize < $this->sizeLimit){
$size = max(1, $this->sizeLimit / 1024 / 1024) . 'M';
die(json_encode(array('error'=>'increase post_max_size and upload_max_filesize to ' . $size)));
}
}
/**
* Convert a given size with units to bytes
* #param string $str
*/
private function toBytes($str){
$val = trim($str);
$last = strtolower($str[strlen($str)-1]);
switch($last) {
case 'g': $val *= 1024;
case 'm': $val *= 1024;
case 'k': $val *= 1024;
}
return $val;
}
/**
* Handle the uploaded file
* #param string $uploadDirectory
* #param string $replaceOldFile=true
* #returns array('success'=>true) or array('error'=>'error message')
*/
function handleUpload($uploadDirectory, $replaceOldFile = FALSE){
if (!is_writable($uploadDirectory)){
return array('error' => "Server error. Upload directory isn't writable.");
}
if (!$this->file){
return array('error' => 'No files were uploaded.');
}
$size = $this->file->getSize();
if ($size == 0) {
return array('error' => 'File is empty');
}
if ($size > $this->sizeLimit) {
return array('error' => 'File is too large');
}
$pathinfo = pathinfo($this->file->getName());
$filename = $pathinfo['filename'];
//$filename = md5(uniqid());
$ext = #$pathinfo['extension']; // hide notices if extension is empty
if($this->allowedExtensions && !in_array(strtolower($ext), $this->allowedExtensions)){
$these = implode(', ', $this->allowedExtensions);
return array('error' => 'File has an invalid extension, it should be one of '. $these . '.');
}
$ext = ($ext == '') ? $ext : '.' . $ext;
if(!$replaceOldFile){
/// don't overwrite previous files that were uploaded
while (file_exists($uploadDirectory . DIRECTORY_SEPARATOR . $filename . $ext)) {
$filename .= rand(10, 99);
}
}
$this->uploadName = $filename . $ext;
if ($this->file->save($uploadDirectory . DIRECTORY_SEPARATOR . $filename . $ext)){
return array('success'=>true);
} else {
return array('error'=> 'Could not save uploaded file.' .
'The upload was cancelled, or server error encountered');
}
}
}
In order to handle chunked requests, you MUST store each chunk separately in your filesystem.
How you name these chunks or where you store them is up to you, but I suggest you name them using the UUID provided by Fine Uploader and append the part number parameter included with each chunked request. After the last chunk has been sent, combine all chunks into one file, with the proper name, and return a standard success response as described in the Fine Uploader documentation. The original name of the file is, by default, passed in a qqfilename parameter with each request. This is also discussed in the docs and the blog.
It doesn't look like you've made any attempt to handle chunks server-side. There is a PHP example in the Widen/fine-uploader-server repo that you can use. Also, the documentation has a "server-side" section that explains how to handle chunking in detail. I'm guessing you did not read this. Have a look.) in the Widen/fine-uploader-server repo that you can use. Also, the documentation has a "server-side" section that explains how to handle chunking in detail. I'm guessing you did not read this. Have a look.
Note that, starting with Fine Uploader 3.8 (set to release VERY soon) you will be able to delegate all server-side upload handling to Amazon S3, as Fine Uploader will provide tight integration with S3 that sends all of your files directly to your bucket from the browser without you having to worry about constructing a policy document, making REST API calls, handling responses from S3, etc. I mention this as using S3 means that you never have to worry about handling things like chunked requests on your server again.

Override set_message multiple times

How can we override the error message to be displayed, multiple times for a single validation rule.
I am trying to do that in the following code, but it shows the error message which is set at the end, i.e., 'b'
What I have tried to do here is, display error 'a' for 'first_name' and error 'b' for last_name.
<?php
/*
This program will test whether we could override the codeingiter error messages from the validation helper.
We are going to use the 'set_message' function.
*/
class Message_override extends CI_Controller{
public function __construct(){
parent::__construct();
$this->load->helper('url');
}
public function index(){
$this->load->view('message_override_view');
}
public function display_error(){
$this->load->library('form_validation');
$this->form_validation->set_message('numeric','a');
$this->form_validation->set_rules('txt_first_name', 'First Name', 'numeric');
$this->form_validation->set_message('numeric','b');
$this->form_validation->set_rules('txt_last_name', 'Last Name', 'numeric');
if($this->form_validation->run()==FALSE)
{
print_r(validation_errors());
}
else
{
echo '<pre>';
print_r($_POST);
}
}
}
?>
CodeIgniter doesn't support multiple error messages for the same rule natively, but there's a couple of workarounds you may try:
As #HashemQolami suggests, you can use multiple callback functions and set a different error message for each one:
$this->form_validation->set_rules('txt_first_name', 'First Name', 'callback_numeric_a');
$this->form_validation->set_rules('txt_last_name', 'Last Name', 'callback_numeric_b');
The drawback for this method is that obviously it's not modular but rather repetitive as you'd need to define multiple functions in your controller like this one
public function numeric_a($str){
$this->form_validation->set_message('numeric_a', 'a');
return $this->numeric($str);
}
Another workaround I've used is set the message of the rule as %s in the language file and then setting the custom message as the label of the field
$lang['numeric'] = '%s';
$this->form_validation->set_rules('txt_first_name', 'a', 'numeric');
$this->form_validation->set_rules('txt_last_name', 'b', 'numeric');
The drawback here is that it basically messes up the error messaging system since you'd have to define the label for each field and would only work correctly with one validation rule per field. Still I have found it useful in contact forms where you basically just need to validate the presence of some required fields.
Now since I've found myself in need for a better implementation for this feature, your post inspired me to put together a simple extension to the form validation class, unfortunately I had to "hack" the main execute method since there's no special function for retrieving the error messages.
I added a method set_custom_message() to set a custom message for a rule to a specific field or to an array of fields.
$this->form_validation->set_custom_message('txt_first_name','numeric','a');
$this->form_validation->set_custom_message('txt_last_name','numeric','b');
//Example passing an array of fields
$this->form_validation->set_custom_message(array('txt_first_name','txt_last_name'),'numeric','c');
Here's the code for the extended class in case someone else is interested:
Note that this is based on the form validation class included in CodeIgniter v2.1.4
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
* MY_Form_validation Class
*
* Extends Form_Validation library
*
* Adds custom message support.
*
*/
class MY_Form_validation extends CI_Form_validation {
protected $_custom_messages = array();
public function set_custom_message($field = '', $rule = '', $message = '' ){
if(is_array($field)){
foreach($field as $id){
$this->_custom_messages[$id][$rule] = $message;
}
return;
}
$this->_custom_messages[$field][$rule] = $message;
return;
}
protected function _execute($row, $rules, $postdata = NULL, $cycles = 0)
{
// If the $_POST data is an array we will run a recursive call
if (is_array($postdata))
{
foreach ($postdata as $key => $val)
{
$this->_execute($row, $rules, $val, $cycles);
$cycles++;
}
return;
}
// --------------------------------------------------------------------
// If the field is blank, but NOT required, no further tests are necessary
$callback = FALSE;
if ( ! in_array('required', $rules) AND is_null($postdata))
{
// Before we bail out, does the rule contain a callback?
if (preg_match("/(callback_\w+(\[.*?\])?)/", implode(' ', $rules), $match))
{
$callback = TRUE;
$rules = (array('1' => $match[1]));
}
else
{
return;
}
}
// --------------------------------------------------------------------
// Isset Test. Typically this rule will only apply to checkboxes.
if (is_null($postdata) AND $callback == FALSE)
{
if (in_array('isset', $rules, TRUE) OR in_array('required', $rules))
{
// Set the message type
$type = (in_array('required', $rules)) ? 'required' : 'isset';
if(array_key_exists($row['field'],$this->_custom_messages) &&
array_key_exists($type,$this->_custom_messages[$row['field']])){
$line = $this->_custom_messages[$row['field']][$type];
}else{
if ( ! isset($this->_error_messages[$type]))
{
if (FALSE === ($line = $this->CI->lang->line($type)))
{
$line = 'The field was not set';
}
}
else
{
$line = $this->_error_messages[$type];
}
}
// Build the error message
$message = sprintf($line, $this->_translate_fieldname($row['label']));
// Save the error message
$this->_field_data[$row['field']]['error'] = $message;
if ( ! isset($this->_error_array[$row['field']]))
{
$this->_error_array[$row['field']] = $message;
}
}
return;
}
// --------------------------------------------------------------------
// Cycle through each rule and run it
foreach ($rules As $rule)
{
$_in_array = FALSE;
// We set the $postdata variable with the current data in our master array so that
// each cycle of the loop is dealing with the processed data from the last cycle
if ($row['is_array'] == TRUE AND is_array($this->_field_data[$row['field']]['postdata']))
{
// We shouldn't need this safety, but just in case there isn't an array index
// associated with this cycle we'll bail out
if ( ! isset($this->_field_data[$row['field']]['postdata'][$cycles]))
{
continue;
}
$postdata = $this->_field_data[$row['field']]['postdata'][$cycles];
$_in_array = TRUE;
}
else
{
$postdata = $this->_field_data[$row['field']]['postdata'];
}
// --------------------------------------------------------------------
// Is the rule a callback?
$callback = FALSE;
if (substr($rule, 0, 9) == 'callback_')
{
$rule = substr($rule, 9);
$callback = TRUE;
}
// Strip the parameter (if exists) from the rule
// Rules can contain a parameter: max_length[5]
$param = FALSE;
if (preg_match("/(.*?)\[(.*)\]/", $rule, $match))
{
$rule = $match[1];
$param = $match[2];
}
// Call the function that corresponds to the rule
if ($callback === TRUE)
{
if ( ! method_exists($this->CI, $rule))
{
continue;
}
// Run the function and grab the result
$result = $this->CI->$rule($postdata, $param);
// Re-assign the result to the master data array
if ($_in_array == TRUE)
{
$this->_field_data[$row['field']]['postdata'][$cycles] = (is_bool($result)) ? $postdata : $result;
}
else
{
$this->_field_data[$row['field']]['postdata'] = (is_bool($result)) ? $postdata : $result;
}
// If the field isn't required and we just processed a callback we'll move on...
if ( ! in_array('required', $rules, TRUE) AND $result !== FALSE)
{
continue;
}
}
else
{
if ( ! method_exists($this, $rule))
{
// If our own wrapper function doesn't exist we see if a native PHP function does.
// Users can use any native PHP function call that has one param.
if (function_exists($rule))
{
$result = $rule($postdata);
if ($_in_array == TRUE)
{
$this->_field_data[$row['field']]['postdata'][$cycles] = (is_bool($result)) ? $postdata : $result;
}
else
{
$this->_field_data[$row['field']]['postdata'] = (is_bool($result)) ? $postdata : $result;
}
}
else
{
log_message('debug', "Unable to find validation rule: ".$rule);
}
continue;
}
$result = $this->$rule($postdata, $param);
if ($_in_array == TRUE)
{
$this->_field_data[$row['field']]['postdata'][$cycles] = (is_bool($result)) ? $postdata : $result;
}
else
{
$this->_field_data[$row['field']]['postdata'] = (is_bool($result)) ? $postdata : $result;
}
}
// Did the rule test negatively? If so, grab the error.
if ($result === FALSE)
{
if(array_key_exists($row['field'],$this->_custom_messages) &&
array_key_exists($rule,$this->_custom_messages[$row['field']])){
$line = $this->_custom_messages[$row['field']][$rule];
}else{
if ( ! isset($this->_error_messages[$rule]))
{
if (FALSE === ($line = $this->CI->lang->line($rule)))
{
$line = 'Unable to access an error message corresponding to your field name.';
}
}
else
{
$line = $this->_error_messages[$rule];
}
}
// Is the parameter we are inserting into the error message the name
// of another field? If so we need to grab its "field label"
if (isset($this->_field_data[$param]) AND isset($this->_field_data[$param]['label']))
{
$param = $this->_translate_fieldname($this->_field_data[$param]['label']);
}
// Build the error message
$message = sprintf($line, $this->_translate_fieldname($row['label']), $param);
// Save the error message
$this->_field_data[$row['field']]['error'] = $message;
if ( ! isset($this->_error_array[$row['field']]))
{
$this->_error_array[$row['field']] = $message;
}
return;
}
}
}
// END MY Form Validation Class
/* End of file MY_Form_validation.php */
/* Location: ./application/libraries/MY_Form_validation.php */
}

Codeigniter - form validation doesn't work for files

i need to set a input file as required into my Codeigniter Controller.
This is my form_validation:
$this->form_validation->set_rules('copertina','Foto principale','required|xss_clean');
and this is the form:
<?php echo form_open_multipart('admin/canile/nuovo'); ?>
<li class="even">
<label for="copertina">Foto principale <span>*</span></label>
<div class="input"><input type="file" name="copertina" value="<?php echo set_value('copertina'); ?>" id="copertina" /></div>
</li>
<?php echo form_close(); ?>
But after the submit the form say that the file is not set, so the required clausole fails...how can i fix it?
File upload data is not stored in the $_POST array, so cannot be validated using CodeIgniter's form_validation library. File uploads are available to PHP using the $_FILES array.
It maybe possible to directly manipulate the $_POST array using data from the $_FILES array, before running form validation, but I haven't tested this. It's probably best to just check the upload library process for errors.
In addition, it is not possible, for security reasons, to (re-)set the value on page reload.
To make validation to work for files you have to check whether is it empty.
like,
if (empty($_FILES['photo']['name']))
{
$this->form_validation->set_rules('userfile', 'Document', 'required');
}
you can solve it by overriding the Run function of CI_Form_Validation
copy this function in a class which extends CI_Form_Validation .
This function will override the parent class function . Here i added only a extra check which can handle file also
/**
* Run the Validator
*
* This function does all the work.
*
* #access public
* #return bool
*/
function run($group = '') {
// Do we even have any data to process? Mm?
if (count($_POST) == 0) {
return FALSE;
}
// Does the _field_data array containing the validation rules exist?
// If not, we look to see if they were assigned via a config file
if (count($this->_field_data) == 0) {
// No validation rules? We're done...
if (count($this->_config_rules) == 0) {
return FALSE;
}
// Is there a validation rule for the particular URI being accessed?
$uri = ($group == '') ? trim($this->CI->uri->ruri_string(), '/') : $group;
if ($uri != '' AND isset($this->_config_rules[$uri])) {
$this->set_rules($this->_config_rules[$uri]);
} else {
$this->set_rules($this->_config_rules);
}
// We're we able to set the rules correctly?
if (count($this->_field_data) == 0) {
log_message('debug', "Unable to find validation rules");
return FALSE;
}
}
// Load the language file containing error messages
$this->CI->lang->load('form_validation');
// Cycle through the rules for each field, match the
// corresponding $_POST or $_FILES item and test for errors
foreach ($this->_field_data as $field => $row) {
// Fetch the data from the corresponding $_POST or $_FILES array and cache it in the _field_data array.
// Depending on whether the field name is an array or a string will determine where we get it from.
if ($row['is_array'] == TRUE) {
if (isset($_FILES[$field])) {
$this->_field_data[$field]['postdata'] = $this->_reduce_array($_FILES, $row['keys']);
} else {
$this->_field_data[$field]['postdata'] = $this->_reduce_array($_POST, $row['keys']);
}
} else {
if (isset($_POST[$field]) AND $_POST[$field] != "") {
$this->_field_data[$field]['postdata'] = $_POST[$field];
} else if (isset($_FILES[$field]) AND $_FILES[$field] != "") {
$this->_field_data[$field]['postdata'] = $_FILES[$field];
}
}
$this->_execute($row, explode('|', $row['rules']), $this->_field_data[$field]['postdata']);
}
// Did we end up with any errors?
$total_errors = count($this->_error_array);
if ($total_errors > 0) {
$this->_safe_form_data = TRUE;
}
// Now we need to re-set the POST data with the new, processed data
$this->_reset_post_array();
// No errors, validation passes!
if ($total_errors == 0) {
return TRUE;
}
// Validation fails
return FALSE;
}
Have you looked at this ->
http://codeigniter.com/user_guide/libraries/file_uploading.html
<?php
class Upload extends CI_Controller {
function __construct()
{
parent::__construct();
$this->load->helper(array('form', 'url'));
}
function index()
{
$this->load->view('upload_form', array('error' => ' ' ));
}
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);
if ( ! $this->upload->do_upload())
{
$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);
}
}
}
?>
Update as per comment:
You can check using plain php if you like ...
$errors_file = array(
0=>'Success!',
1=>'The uploaded file exceeds the upload_max_filesize directive in php.ini',
2=>'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form',
3=>'The uploaded file was only partially uploaded',
4=>'No file was uploaded',
6=>'Missing a temporary folder',
7=>'Cannot write file to disk'
);
if($_FILES['form_input_file_name']['error'] == 4) {
echo 'No file uploaded';
}
if($_FILES['form_input_file_name']['error'] == 0) {
echo 'File uploaded... no errors';
}

Resources