How to set minimum upload size in codeigniter - codeigniter
I want to set minimum width and height for uploading images in codeigniter.
The code is shown below.
$config['max_width'] = '480';
$config['max_height'] = '270';
$this->upload->do_upload()
I have set maximum cut off for this but how to set minimum ??
Copy your Upload.php from system/libraries and paste on application/libraries. Then,
introduce 2 new variables.
public $max_width = 0;
public $max_height = 0;
public $min_width = 0; // new
public $min_height = 0; // new
Add these to the initialize function so that you can pass values through a $config variable.
Locate is_allowed_dimensions function and modify it.
if ($this->min_width > 0 AND $D['0'] < $this->min_width)
{
return FALSE;
}
if ($this->min_height > 0 AND $D['1'] < $this->min_height)
{
return FALSE;
}
Check the upload language file and alter the upload_invalid_dimensions key accordingly to fit your case.
Have not tested this, but should work :)
Go to system/validation. And then open file FileRules.php
Paste this code :
public function min_dims(?string $blank, string $params): bool
{
// Grab the file name off the top of the $params
// after we split it.
$params = explode(',', $params);
$name = array_shift($params);
if (! ($files = $this->request->getFileMultiple($name))) {
$files = [$this->request->getFile($name)];
}
foreach ($files as $file) {
if ($file === null) {
return false;
}
if ($file->getError() === UPLOAD_ERR_NO_FILE) {
return true;
}
// Get Parameter sizes
$allowedWidth = $params[0] ?? 0;
$allowedHeight = $params[1] ?? 0;
// Get uploaded image size
$info = getimagesize($file->getTempName());
$fileWidth = $info[0];
$fileHeight = $info[1];
if ($fileWidth < $allowedWidth || $fileHeight < $allowedHeight) {
return false;
}
}
return true;
}
And, in your controller use min_dims[field_name,1100,1100]. The first
parameter is the field name. The second is
the width, and the third is the height
Good Luck!
Here is the working fix, additionally you need to specify min_height and min_width while you init
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class CI_Upload {
public $max_size = 0;
public $max_width = 0;
public $max_height = 0;
public $min_width = 0;
public $min_height = 0;
public $max_filename = 0;
public $allowed_types = "";
public $file_temp = "";
public $file_name = "";
public $orig_name = "";
public $file_type = "";
public $file_size = "";
public $file_ext = "";
public $upload_path = "";
public $overwrite = FALSE;
public $encrypt_name = FALSE;
public $is_image = FALSE;
public $image_width = '';
public $image_height = '';
public $image_type = '';
public $image_size_str = '';
public $error_msg = array();
public $mimes = array();
public $remove_spaces = TRUE;
public $xss_clean = FALSE;
public $temp_prefix = "temp_file_";
public $client_name = '';
protected $_file_name_override = '';
/**
* Constructor
*
* #access public
*/
public function __construct($props = array())
{
if (count($props) > 0)
{
$this->initialize($props);
}
log_message('debug', "Upload Class Initialized");
}
// --------------------------------------------------------------------
/**
* Initialize preferences
*
* #param array
* #return void
*/
public function initialize($config = array())
{
$defaults = array(
'max_size' => 0,
'max_width' => 0,
'max_height' => 0,
'min_width' => 0,
'min_height' => 0,
'max_filename' => 0,
'allowed_types' => "",
'file_temp' => "",
'file_name' => "",
'orig_name' => "",
'file_type' => "",
'file_size' => "",
'file_ext' => "",
'upload_path' => "",
'overwrite' => FALSE,
'encrypt_name' => FALSE,
'is_image' => FALSE,
'image_width' => '',
'image_height' => '',
'image_type' => '',
'image_size_str' => '',
'error_msg' => array(),
'mimes' => array(),
'remove_spaces' => TRUE,
'xss_clean' => FALSE,
'temp_prefix' => "temp_file_",
'client_name' => ''
);
foreach ($defaults as $key => $val)
{
if (isset($config[$key]))
{
$method = 'set_'.$key;
if (method_exists($this, $method))
{
$this->$method($config[$key]);
}
else
{
$this->$key = $config[$key];
}
}
else
{
$this->$key = $val;
}
}
// if a file_name was provided in the config, use it instead of the user input
// supplied file name for all uploads until initialized again
$this->_file_name_override = $this->file_name;
}
// --------------------------------------------------------------------
/**
* Perform the file upload
*
* #return bool
*/
public function do_upload($field = 'userfile')
{
// Is $_FILES[$field] set? If not, no reason to continue.
if ( ! isset($_FILES[$field]))
{
$this->set_error('upload_no_file_selected');
return FALSE;
}
// Is the upload path valid?
if ( ! $this->validate_upload_path())
{
// errors will already be set by validate_upload_path() so just return FALSE
return FALSE;
}
// Was the file able to be uploaded? If not, determine the reason why.
if ( ! is_uploaded_file($_FILES[$field]['tmp_name']))
{
$error = ( ! isset($_FILES[$field]['error'])) ? 4 : $_FILES[$field]['error'];
switch($error)
{
case 1: // UPLOAD_ERR_INI_SIZE
$this->set_error('upload_file_exceeds_limit');
break;
case 2: // UPLOAD_ERR_FORM_SIZE
$this->set_error('upload_file_exceeds_form_limit');
break;
case 3: // UPLOAD_ERR_PARTIAL
$this->set_error('upload_file_partial');
break;
case 4: // UPLOAD_ERR_NO_FILE
$this->set_error('upload_no_file_selected');
break;
case 6: // UPLOAD_ERR_NO_TMP_DIR
$this->set_error('upload_no_temp_directory');
break;
case 7: // UPLOAD_ERR_CANT_WRITE
$this->set_error('upload_unable_to_write_file');
break;
case 8: // UPLOAD_ERR_EXTENSION
$this->set_error('upload_stopped_by_extension');
break;
default : $this->set_error('upload_no_file_selected');
break;
}
return FALSE;
}
// Set the uploaded data as class variables
$this->file_temp = $_FILES[$field]['tmp_name'];
$this->file_size = $_FILES[$field]['size'];
$this->_file_mime_type($_FILES[$field]);
$this->file_type = preg_replace("/^(.+?);.*$/", "\\1", $this->file_type);
$this->file_type = strtolower(trim(stripslashes($this->file_type), '"'));
$this->file_name = $this->_prep_filename($_FILES[$field]['name']);
$this->file_ext = $this->get_extension($this->file_name);
$this->client_name = $this->file_name;
// Is the file type allowed to be uploaded?
if ( ! $this->is_allowed_filetype())
{
$this->set_error('upload_invalid_filetype');
return FALSE;
}
// if we're overriding, let's now make sure the new name and type is allowed
if ($this->_file_name_override != '')
{
$this->file_name = $this->_prep_filename($this->_file_name_override);
// If no extension was provided in the file_name config item, use the uploaded one
if (strpos($this->_file_name_override, '.') === FALSE)
{
$this->file_name .= $this->file_ext;
}
// An extension was provided, lets have it!
else
{
$this->file_ext = $this->get_extension($this->_file_name_override);
}
if ( ! $this->is_allowed_filetype(TRUE))
{
$this->set_error('upload_invalid_filetype');
return FALSE;
}
}
// Convert the file size to kilobytes
if ($this->file_size > 0)
{
$this->file_size = round($this->file_size/1024, 2);
}
// Is the file size within the allowed maximum?
if ( ! $this->is_allowed_filesize())
{
$this->set_error('upload_invalid_filesize');
return FALSE;
}
// Are the image dimensions within the allowed size?
// Note: This can fail if the server has an open_basdir restriction.
if ( ! $this->is_allowed_dimensions())
{
$this->set_error('upload_invalid_dimensions');
return FALSE;
}
// Sanitize the file name for security
$this->file_name = $this->clean_file_name($this->file_name);
// Truncate the file name if it's too long
if ($this->max_filename > 0)
{
$this->file_name = $this->limit_filename_length($this->file_name, $this->max_filename);
}
// Remove white spaces in the name
if ($this->remove_spaces == TRUE)
{
$this->file_name = preg_replace("/\s+/", "_", $this->file_name);
}
/*
* Validate the file name
* This function appends an number onto the end of
* the file if one with the same name already exists.
* If it returns false there was a problem.
*/
$this->orig_name = $this->file_name;
if ($this->overwrite == FALSE)
{
$this->file_name = $this->set_filename($this->upload_path, $this->file_name);
if ($this->file_name === FALSE)
{
return FALSE;
}
}
/*
* Run the file through the XSS hacking filter
* This helps prevent malicious code from being
* embedded within a file. Scripts can easily
* be disguised as images or other file types.
*/
if ($this->xss_clean)
{
if ($this->do_xss_clean() === FALSE)
{
$this->set_error('upload_unable_to_write_file');
return FALSE;
}
}
/*
* Move the file to the final destination
* To deal with different server configurations
* we'll attempt to use copy() first. If that fails
* we'll use move_uploaded_file(). One of the two should
* reliably work in most environments
*/
if ( ! #copy($this->file_temp, $this->upload_path.$this->file_name))
{
if ( ! #move_uploaded_file($this->file_temp, $this->upload_path.$this->file_name))
{
$this->set_error('upload_destination_error');
return FALSE;
}
}
/*
* Set the finalized image dimensions
* This sets the image width/height (assuming the
* file was an image). We use this information
* in the "data" function.
*/
$this->set_image_properties($this->upload_path.$this->file_name);
return TRUE;
}
// --------------------------------------------------------------------
/**
* Finalized Data Array
*
* Returns an associative array containing all of the information
* related to the upload, allowing the developer easy access in one array.
*
* #return array
*/
public function data()
{
return array (
'file_name' => $this->file_name,
'file_type' => $this->file_type,
'file_path' => $this->upload_path,
'full_path' => $this->upload_path.$this->file_name,
'raw_name' => str_replace($this->file_ext, '', $this->file_name),
'orig_name' => $this->orig_name,
'client_name' => $this->client_name,
'file_ext' => $this->file_ext,
'file_size' => $this->file_size,
'is_image' => $this->is_image(),
'image_width' => $this->image_width,
'image_height' => $this->image_height,
'image_type' => $this->image_type,
'image_size_str' => $this->image_size_str,
);
}
// --------------------------------------------------------------------
/**
* Set Upload Path
*
* #param string
* #return void
*/
public function set_upload_path($path)
{
// Make sure it has a trailing slash
$this->upload_path = rtrim($path, '/').'/';
}
// --------------------------------------------------------------------
/**
* Set the file name
*
* This function takes a filename/path as input and looks for the
* existence of a file with the same name. If found, it will append a
* number to the end of the filename to avoid overwriting a pre-existing file.
*
* #param string
* #param string
* #return string
*/
public function set_filename($path, $filename)
{
if ($this->encrypt_name == TRUE)
{
mt_srand();
$filename = md5(uniqid(mt_rand())).$this->file_ext;
}
if ( ! file_exists($path.$filename))
{
return $filename;
}
$filename = str_replace($this->file_ext, '', $filename);
$new_filename = '';
for ($i = 1; $i < 100; $i++)
{
if ( ! file_exists($path.$filename.$i.$this->file_ext))
{
$new_filename = $filename.$i.$this->file_ext;
break;
}
}
if ($new_filename == '')
{
$this->set_error('upload_bad_filename');
return FALSE;
}
else
{
return $new_filename;
}
}
// --------------------------------------------------------------------
/**
* Set Maximum File Size
*
* #param integer
* #return void
*/
public function set_max_filesize($n)
{
$this->max_size = ((int) $n < 0) ? 0: (int) $n;
}
// --------------------------------------------------------------------
/**
* Set Maximum File Name Length
*
* #param integer
* #return void
*/
public function set_max_filename($n)
{
$this->max_filename = ((int) $n < 0) ? 0: (int) $n;
}
// --------------------------------------------------------------------
/**
* Set Maximum Image Width
*
* #param integer
* #return void
*/
public function set_max_width($n)
{
$this->max_width = ((int) $n < 0) ? 0: (int) $n;
}
public function set_min_width($n)
{
$this->min_width = ((int) $n < 0) ? 0: (int) $n;
}
// --------------------------------------------------------------------
/**
* Set Maximum Image Height
*
* #param integer
* #return void
*/
public function set_max_height($n)
{
$this->max_height = ((int) $n < 0) ? 0: (int) $n;
}
public function set_min_height($n)
{
$this->min_height = ((int) $n < 0) ? 0: (int) $n;
}
// --------------------------------------------------------------------
/**
* Set Allowed File Types
*
* #param string
* #return void
*/
public function set_allowed_types($types)
{
if ( ! is_array($types) && $types == '*')
{
$this->allowed_types = '*';
return;
}
$this->allowed_types = explode('|', $types);
}
// --------------------------------------------------------------------
/**
* Set Image Properties
*
* Uses GD to determine the width/height/type of image
*
* #param string
* #return void
*/
public function set_image_properties($path = '')
{
if ( ! $this->is_image())
{
return;
}
if (function_exists('getimagesize'))
{
if (FALSE !== ($D = #getimagesize($path)))
{
$types = array(1 => 'gif', 2 => 'jpeg', 3 => 'png');
$this->image_width = $D['0'];
$this->image_height = $D['1'];
$this->image_type = ( ! isset($types[$D['2']])) ? 'unknown' : $types[$D['2']];
$this->image_size_str = $D['3']; // string containing height and width
}
}
}
// --------------------------------------------------------------------
/**
* Set XSS Clean
*
* Enables the XSS flag so that the file that was uploaded
* will be run through the XSS filter.
*
* #param bool
* #return void
*/
public function set_xss_clean($flag = FALSE)
{
$this->xss_clean = ($flag == TRUE) ? TRUE : FALSE;
}
// --------------------------------------------------------------------
/**
* Validate the image
*
* #return bool
*/
public function is_image()
{
// IE will sometimes return odd mime-types during upload, so here we just standardize all
// jpegs or pngs to the same file type.
$png_mimes = array('image/x-png');
$jpeg_mimes = array('image/jpg', 'image/jpe', 'image/jpeg', 'image/pjpeg');
if (in_array($this->file_type, $png_mimes))
{
$this->file_type = 'image/png';
}
if (in_array($this->file_type, $jpeg_mimes))
{
$this->file_type = 'image/jpeg';
}
$img_mimes = array(
'image/gif',
'image/jpeg',
'image/png',
);
return (in_array($this->file_type, $img_mimes, TRUE)) ? TRUE : FALSE;
}
// --------------------------------------------------------------------
/**
* Verify that the filetype is allowed
*
* #return bool
*/
public function is_allowed_filetype($ignore_mime = FALSE)
{
if ($this->allowed_types == '*')
{
return TRUE;
}
if (count($this->allowed_types) == 0 OR ! is_array($this->allowed_types))
{
$this->set_error('upload_no_file_types');
return FALSE;
}
$ext = strtolower(ltrim($this->file_ext, '.'));
if ( ! in_array($ext, $this->allowed_types))
{
return FALSE;
}
// Images get some additional checks
$image_types = array('gif', 'jpg', 'jpeg', 'png', 'jpe');
if (in_array($ext, $image_types))
{
if (getimagesize($this->file_temp) === FALSE)
{
return FALSE;
}
}
if ($ignore_mime === TRUE)
{
return TRUE;
}
$mime = $this->mimes_types($ext);
if (is_array($mime))
{
if (in_array($this->file_type, $mime, TRUE))
{
return TRUE;
}
}
elseif ($mime == $this->file_type)
{
return TRUE;
}
return FALSE;
}
// --------------------------------------------------------------------
/**
* Verify that the file is within the allowed size
*
* #return bool
*/
public function is_allowed_filesize()
{
if ($this->max_size != 0 AND $this->file_size > $this->max_size)
{
return FALSE;
}
else
{
return TRUE;
}
}
// --------------------------------------------------------------------
/**
* Verify that the image is within the allowed width/height
*
* #return bool
*/
public function is_allowed_dimensions()
{
if ( ! $this->is_image())
{
return TRUE;
}
if (function_exists('getimagesize'))
{
$D = #getimagesize($this->file_temp);
if ($this->max_width > 0 AND $D['0'] > $this->max_width)
{
return FALSE;
}
if ($this->max_height > 0 AND $D['1'] > $this->max_height)
{
return FALSE;
}
if ($D['0'] < $this->min_width)
{
return FALSE;
}
if ($D['1'] < $this->min_height)
{
return FALSE;
}
return TRUE;
}
return TRUE;
}
// --------------------------------------------------------------------
/**
* 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');
return FALSE;
}
if (function_exists('realpath') AND #realpath($this->upload_path) !== FALSE)
{
$this->upload_path = str_replace("\\", "/", realpath($this->upload_path));
}
if ( ! #is_dir($this->upload_path))
{
$this->set_error('upload_no_filepath');
return FALSE;
}
if ( ! is_really_writable($this->upload_path))
{
$this->set_error('upload_not_writable');
return FALSE;
}
$this->upload_path = preg_replace("/(.+?)\/*$/", "\\1/", $this->upload_path);
return TRUE;
}
// --------------------------------------------------------------------
/**
* Extract the file extension
*
* #param string
* #return string
*/
public function get_extension($filename)
{
$x = explode('.', $filename);
return '.'.end($x);
}
// --------------------------------------------------------------------
/**
* Clean the file name for security
*
* #param string
* #return string
*/
public function clean_file_name($filename)
{
$bad = array(
"<!--",
"-->",
"'",
"<",
">",
'"',
'&',
'$',
'=',
';',
'?',
'/',
"%20",
"%22",
"%3c", // <
"%253c", // <
"%3e", // >
"%0e", // >
"%28", // (
"%29", // )
"%2528", // (
"%26", // &
"%24", // $
"%3f", // ?
"%3b", // ;
"%3d" // =
);
$filename = str_replace($bad, '', $filename);
return stripslashes($filename);
}
// --------------------------------------------------------------------
/**
* Limit the File Name Length
*
* #param string
* #return string
*/
public function limit_filename_length($filename, $length)
{
if (strlen($filename) < $length)
{
return $filename;
}
$ext = '';
if (strpos($filename, '.') !== FALSE)
{
$parts = explode('.', $filename);
$ext = '.'.array_pop($parts);
$filename = implode('.', $parts);
}
return substr($filename, 0, ($length - strlen($ext))).$ext;
}
// --------------------------------------------------------------------
/**
* Runs the file through the XSS clean function
*
* This prevents people from embedding malicious code in their files.
* I'm not sure that it won't negatively affect certain files in unexpected ways,
* but so far I haven't found that it causes trouble.
*
* #return void
*/
public function do_xss_clean()
{
$file = $this->file_temp;
if (filesize($file) == 0)
{
return FALSE;
}
if (function_exists('memory_get_usage') && memory_get_usage() && ini_get('memory_limit') != '')
{
$current = ini_get('memory_limit') * 1024 * 1024;
// There was a bug/behavioural change in PHP 5.2, where numbers over one million get output
// into scientific notation. number_format() ensures this number is an integer
// http://bugs.php.net/bug.php?id=43053
$new_memory = number_format(ceil(filesize($file) + $current), 0, '.', '');
ini_set('memory_limit', $new_memory); // When an integer is used, the value is measured in bytes. - PHP.net
}
// If the file being uploaded is an image, then we should have no problem with XSS attacks (in theory), but
// IE can be fooled into mime-type detecting a malformed image as an html file, thus executing an XSS attack on anyone
// using IE who looks at the image. It does this by inspecting the first 255 bytes of an image. To get around this
// CI will itself look at the first 255 bytes of an image to determine its relative safety. This can save a lot of
// processor power and time if it is actually a clean image, as it will be in nearly all instances _except_ an
// attempted XSS attack.
if (function_exists('getimagesize') && #getimagesize($file) !== FALSE)
{
if (($file = #fopen($file, 'rb')) === FALSE) // "b" to force binary
{
return FALSE; // Couldn't open the file, return FALSE
}
$opening_bytes = fread($file, 256);
fclose($file);
// These are known to throw IE into mime-type detection chaos
// <a, <body, <head, <html, <img, <plaintext, <pre, <script, <table, <title
// title is basically just in SVG, but we filter it anyhow
if ( ! preg_match('/<(a|body|head|html|img|plaintext|pre|script|table|title)[\s>]/i', $opening_bytes))
{
return TRUE; // its an image, no "triggers" detected in the first 256 bytes, we're good
}
else
{
return FALSE;
}
}
if (($data = #file_get_contents($file)) === FALSE)
{
return FALSE;
}
$CI =& get_instance();
return $CI->security->xss_clean($data, TRUE);
}
// --------------------------------------------------------------------
/**
* Set an error message
*
* #param string
* #return void
*/
public function set_error($msg)
{
$CI =& get_instance();
$CI->lang->load('upload');
if (is_array($msg))
{
foreach ($msg as $val)
{
$msg = ($CI->lang->line($val) == FALSE) ? $val : $CI->lang->line($val);
$this->error_msg[] = $msg;
log_message('error', $msg);
}
}
else
{
$msg = ($CI->lang->line($msg) == FALSE) ? $msg : $CI->lang->line($msg);
$this->error_msg[] = $msg;
log_message('error', $msg);
}
}
// --------------------------------------------------------------------
/**
* Display the error message
*
* #param string
* #param string
* #return string
*/
public function display_errors($open = '<p>', $close = '</p>')
{
$str = '';
foreach ($this->error_msg as $val)
{
$str .= $open.$val.$close;
}
return $str;
}
// --------------------------------------------------------------------
/**
* List of Mime Types
*
* This is a list of mime types. We use it to validate
* the "allowed types" set by the developer
*
* #param string
* #return string
*/
public function mimes_types($mime)
{
global $mimes;
if (count($this->mimes) == 0)
{
if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
{
include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php');
}
elseif (is_file(APPPATH.'config/mimes.php'))
{
include(APPPATH.'config//mimes.php');
}
else
{
return FALSE;
}
$this->mimes = $mimes;
unset($mimes);
}
return ( ! isset($this->mimes[$mime])) ? FALSE : $this->mimes[$mime];
}
// --------------------------------------------------------------------
/**
* Prep Filename
*
* Prevents possible script execution from Apache's handling of files multiple extensions
* http://httpd.apache.org/docs/1.3/mod/mod_mime.html#multipleext
*
* #param string
* #return string
*/
protected function _prep_filename($filename)
{
if (strpos($filename, '.') === FALSE OR $this->allowed_types == '*')
{
return $filename;
}
$parts = explode('.', $filename);
$ext = array_pop($parts);
$filename = array_shift($parts);
foreach ($parts as $part)
{
if ( ! in_array(strtolower($part), $this->allowed_types) OR $this->mimes_types(strtolower($part)) === FALSE)
{
$filename .= '.'.$part.'_';
}
else
{
$filename .= '.'.$part;
}
}
$filename .= '.'.$ext;
return $filename;
}
// --------------------------------------------------------------------
/**
* File MIME type
*
* Detects the (actual) MIME type of the uploaded file, if possible.
* The input array is expected to be $_FILES[$field]
*
* #param array
* #return void
*/
protected function _file_mime_type($file)
{
// We'll need this to validate the MIME info string (e.g. text/plain; charset=us-ascii)
$regexp = '/^([a-z\-]+\/[a-z0-9\-\.\+]+)(;\s.+)?$/';
/* Fileinfo extension - most reliable method
*
* Unfortunately, prior to PHP 5.3 - it's only available as a PECL extension and the
* more convenient FILEINFO_MIME_TYPE flag doesn't exist.
*/
if (function_exists('finfo_file'))
{
$finfo = finfo_open(FILEINFO_MIME);
if (is_resource($finfo)) // It is possible that a FALSE value is returned, if there is no magic MIME database file found on the system
{
$mime = #finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
/* According to the comments section of the PHP manual page,
* it is possible that this function returns an empty string
* for some files (e.g. if they don't exist in the magic MIME database)
*/
if (is_string($mime) && preg_match($regexp, $mime, $matches))
{
$this->file_type = $matches[1];
return;
}
}
}
/* This is an ugly hack, but UNIX-type systems provide a "native" way to detect the file type,
* which is still more secure than depending on the value of $_FILES[$field]['type'], and as it
* was reported in issue #750 (https://github.com/EllisLab/CodeIgniter/issues/750) - it's better
* than mime_content_type() as well, hence the attempts to try calling the command line with
* three different functions.
*
* Notes:
* - the DIRECTORY_SEPARATOR comparison ensures that we're not on a Windows system
* - many system admins would disable the exec(), shell_exec(), popen() and similar functions
* due to security concerns, hence the function_exists() checks
*/
if (DIRECTORY_SEPARATOR !== '\\')
{
$cmd = 'file --brief --mime ' . escapeshellarg($file['tmp_name']) . ' 2>&1';
if (function_exists('exec'))
{
/* This might look confusing, as $mime is being populated with all of the output when set in the second parameter.
* However, we only neeed the last line, which is the actual return value of exec(), and as such - it overwrites
* anything that could already be set for $mime previously. This effectively makes the second parameter a dummy
* value, which is only put to allow us to get the return status code.
*/
$mime = #exec($cmd, $mime, $return_status);
if ($return_status === 0 && is_string($mime) && preg_match($regexp, $mime, $matches))
{
$this->file_type = $matches[1];
return;
}
}
if ( (bool) #ini_get('safe_mode') === FALSE && function_exists('shell_exec'))
{
$mime = #shell_exec($cmd);
if (strlen($mime) > 0)
{
$mime = explode("\n", trim($mime));
if (preg_match($regexp, $mime[(count($mime) - 1)], $matches))
{
$this->file_type = $matches[1];
return;
}
}
}
if (function_exists('popen'))
{
$proc = #popen($cmd, 'r');
if (is_resource($proc))
{
$mime = #fread($proc, 512);
#pclose($proc);
if ($mime !== FALSE)
{
$mime = explode("\n", trim($mime));
if (preg_match($regexp, $mime[(count($mime) - 1)], $matches))
{
$this->file_type = $matches[1];
return;
}
}
}
}
}
// Fall back to the deprecated mime_content_type(), if available (still better than $_FILES[$field]['type'])
if (function_exists('mime_content_type'))
{
$this->file_type = #mime_content_type($file['tmp_name']);
if (strlen($this->file_type) > 0) // It's possible that mime_content_type() returns FALSE or an empty string
{
return;
}
}
$this->file_type = $file['type'];
}
// --------------------------------------------------------------------
}
Related
error in controller.php laravel (array_key_exists())
when I want to save changes in laravel, see this error : /** * Store a newly created resource in storage. * * #param \Illuminate\Http\Request $request * #return array|\Illuminate\Http\Response */ public function arrangeRoleItem($content, $module_name) { if (array_key_exists(1, $content )) { //Module Show $module_show = 1; } else { $module_show = 0; } if (array_key_exists(2, $content)) { // Show $show = 1; } else { $show = 0; } if (array_key_exists(3, $content)) { // Create $create = 1; } else { $create = 0; } if (array_key_exists(4, $content)) { // Edit $edit = 1; } else { $edit = 0; } } error: Arguments "array_key_exists() expects parameter 2 to be array, null given" thanks for responses.
Your $content variable is null value but array_key_exists function expects second parameter is array You need to set default value like this: /** * Arrange role item * * #param array $content * #param string $module_name * #return boolean $bool */ public function arrangeRoleItem($content = [], $module_name)
Migrate session from memcached to redis without logging users out in laravel
We're using Memcached to store Laravel's cookie-based session at the moment but want to use Redis throughout for session and cache for consistency. Is there a way to migrate all user sessions from Memcached to Redis without logging out the users?
I was able to migrate the sessions without logging out the users. I created an artisan command for the purpose: <?php namespace App\Console\Commands; use \Memcached; use \Redis; use Illuminate\Console\Command; class MigrateSessionToRedis extends Command { /** * The name and signature of the console command. * * #var string */ protected $signature = 'migrate:session'; /** * The console command description. * * #var string */ protected $description = 'Migrate sessions from Memcached to Redis'; /** * Create a new command instance. * * #return void */ public function __construct() #NOSONAR { parent::__construct(); } /** * Execute the console command. * * #return mixed */ public function handle() { $this->info('Starting session migration..'); $memcached = new Memcached(); $memcached->addServer(env('MEMCACHED_HOST'), 11211); $sessions = $this->getMemcachedKeys(env('MEMCACHED_HOST')); if (! is_array($sessions)) { $this->error('Could not retrieve sessions from Memcached'); exit(1); } foreach ($sessions as $session) { $value = $memcached->get($session); if ($value) { $object = unserialize($value); $valueForRedis = serialize(serialize($object)); // Set session in Redis with session expiry lifetime Redis::set("{$session}", $valueForRedis, 'EX', config('session.lifetime')); } } $this->info('Finished session migration.'); } /** * Get all memcached keys. Special function because getAllKeys() is broken since memcached 1.4.23. * Should only be needed on php 5.6 * * cleaned up version of code found on Stackoverflow.com by Maduka Jayalath * * #return array|int - all retrieved keys (or negative number on error) */ private function getMemcachedKeys($host = '127.0.0.1', $port = 11211) #NOSONAR { $mem = #fsockopen($host, $port); if ($mem === false) { return -1; } // retrieve distinct slab $r = #fwrite($mem, 'stats items' . chr(10)); if ($r === false) { return -2; } $slab = []; while (($l = #fgets($mem, 1024)) !== false) { // finished? $l = trim($l); if ($l == 'END') { break; } $m = []; // <STAT items:22:evicted_nonzero 0> $r = preg_match('/^STAT\sitems\:(\d+)\:/', $l, $m); if ($r != 1) { return -3; } $a_slab = $m[1]; if (!array_key_exists($a_slab, $slab)) { $slab[$a_slab] = []; } } reset($slab); foreach ($slab as $a_slab_key => &$a_slab) { $r = #fwrite($mem, 'stats cachedump ' . $a_slab_key . ' 100' . chr(10)); if ($r === false) { return -4; } while (($l = #fgets($mem, 1024)) !== false) { // finished? $l = trim($l); if ($l == 'END') { break; } $m = []; // ITEM 42 [118 b; 1354717302 s] $r = preg_match('/^ITEM\s([^\s]+)\s/', $l, $m); if ($r != 1) { return -5; } $a_key = $m[1]; $a_slab[] = $a_key; } } // close the connection #fclose($mem); unset($mem); $keys = []; reset($slab); foreach ($slab as &$a_slab) { reset($a_slab); foreach ($a_slab as &$a_key) { $keys[] = $a_key; } } unset($slab); return $keys; } } Hope it can help others.
Below just example how to make this kind of migration. Try it that way: <?php $host = '127.0.0.1'; $port = null; $oldPrefix = 'sess_'; $newPrefix = 'sess_'; $sessionDir = '/var/lib/php/session/'; $m = new \Redis(); $m->connect($host, $port); // $m = new \Memcached(); // $m->addServer($host, $port); $sessions = scandir($sessionDir); if (!$sessions) { die('nothing to migrate'); } foreach ($sessions as $s) { if (in_array($s, ['.', '..'])) { continue; } $sessionName = str_replace($oldPrefix, '', $s); $sessionContents = file_get_contents($sessionDir.$s); if (!$m->set($newPrefix.$sessionName, $sessionContents)) { die(sprintf('Could not migrate session %s'.PHP_EOL, $newPrefix.$sessionName)); } echo '.'; } die(PHP_EOL); But I guess hat users will be logged out.
Laravel S3 retreiving a Video to Stream
I'm storing videos to Amazon S3 via my Laravel app. That works great. But I can't "stream" them. This is the URL for example: https://website.com/video/342.qt?api_token=a5a18c9f-f5f6-5d66-85e3-aaaaaaa, what should return this movie from S3 called '212.DdsqoK1PlL.qt' It returns this output when calling the URL: That's the video, but I was expecting it to run directly in the browser, like this video does: https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4 The route calls this function, retrieving the non-public file from the S3-disk: public function document(Document $document) { return Storage::disk('s3')->get($document->path); } The only difference between the example URL that works and mine is that the example is MP4 and mine .QT, but I tried MP4 also and go the same output in the browser; so no autoplaying video. I guess the movie that plays directly is streaming the video?.. My website is running on Ubuntu and installed also sudo apt-get install vlc.
I personally am opposed to the idea of redirecting to an S3 URL. I mask all my URLs through a Laravel php wrapper server-side. This is the code I use to do so if anyone else encounters similar issues. This code is written for streaming a video from S3 with Laravel 5.6 (and includes HTTP_RANGE support so it works on iOS too). I use the class below, placed at App/Http/Responses. To use this class, create a method that does this (this is like a getFile method): $filestream = new \App\Http\Responses\S3FileStream('file_path_and_name_within_bucket', 'disk_bucket_name', 'output_file_name_when_downloaded'); return $filestream->output(); With any luck, you should be streaming in no time (without revealing an S3 URL)! S3FileStream.php: <?php namespace Http\Responses; use Exception; use Illuminate\Filesystem\FilesystemAdapter; use Illuminate\Http\Response; use Illuminate\Support\Arr; use Illuminate\Support\Str; use Storage; use Symfony\Component\HttpFoundation\StreamedResponse; class S3FileStream { /** * #var \League\Flysystem\AwsS3v3\AwsS3Adapter */ private $adapter; /** * Name of adapter * * #var string */ private $adapterName; /** * Storage disk * * #var FilesystemAdapter */ private $disk; /** * #var int file end byte */ private $end; /** * #var string */ private $filePath; /** * Human-known filename * * #var string|null */ private $humanName; /** * #var bool storing if request is a range (or a full file) */ private $isRange = false; /** * #var int|null length of bytes requested */ private $length = null; /** * #var array */ private $returnHeaders = []; /** * #var int file size */ private $size; /** * #var int start byte */ private $start; /** * S3FileStream constructor. * #param string $filePath * #param string $adapter * #param string $humanName */ public function __construct(string $filePath, string $adapter = 's3', ?string $humanName = null) { $this->filePath = $filePath; $this->adapterName = $adapter; $this->disk = Storage::disk($this->adapterName); $this->adapter = $this->disk->getAdapter(); $this->humanName = $humanName; //Set to zero until setHeadersAndStream is called $this->start = 0; $this->size = 0; $this->end = 0; } /** * Output file to client. */ public function output() { return $this->setHeadersAndStream(); } /** * Output headers to client. * #return Response|StreamedResponse */ protected function setHeadersAndStream() { if (!$this->disk->exists($this->filePath)) { report(new Exception('S3 File Not Found in S3FileStream - ' . $this->adapterName . ' - ' . $this->disk->path($this->filePath))); return response('File Not Found', 404); } $this->start = 0; $this->size = $this->disk->size($this->filePath); $this->end = $this->size - 1; $this->length = $this->size; $this->isRange = false; //Set headers $this->returnHeaders = [ 'Last-Modified' => $this->disk->lastModified($this->filePath), 'Accept-Ranges' => 'bytes', 'Content-Type' => $this->disk->mimeType($this->filePath), 'Content-Disposition' => 'inline; filename=' . ($this->humanName ?? basename($this->filePath) . '.' . Arr::last(explode('.', $this->filePath))), 'Content-Length' => $this->length, ]; //Handle ranges here if (!is_null(request()->server('HTTP_RANGE'))) { $cStart = $this->start; $cEnd = $this->end; $range = Str::after(request()->server('HTTP_RANGE'), '='); if (strpos($range, ',') !== false) { return response('416 Requested Range Not Satisfiable', 416, [ 'Content-Range' => 'bytes */' . $this->size, ]); } if (substr($range, 0, 1) == '-') { $cStart = $this->size - intval(substr($range, 1)) - 1; } else { $range = explode('-', $range); $cStart = intval($range[0]); $cEnd = (isset($range[1]) && is_numeric($range[1])) ? intval($range[1]) : $cEnd; } $cEnd = min($cEnd, $this->size - 1); if ($cStart > $cEnd || $cStart > $this->size - 1) { return response('416 Requested Range Not Satisfiable', 416, [ 'Content-Range' => 'bytes */' . $this->size, ]); } $this->start = intval($cStart); $this->end = intval($cEnd); $this->length = min($this->end - $this->start + 1, $this->size); $this->returnHeaders['Content-Length'] = $this->length; $this->returnHeaders['Content-Range'] = 'bytes ' . $this->start . '-' . $this->end . '/' . $this->size; $this->isRange = true; } return $this->stream(); } /** * Stream file to client. * #throws Exception * #return StreamedResponse */ protected function stream(): StreamedResponse { $this->adapter->getClient()->registerStreamWrapper(); // Create a stream context to allow seeking $context = stream_context_create([ 's3' => [ 'seekable' => true, ], ]); // Open a stream in read-only mode if (!($stream = fopen("s3://{$this->adapter->getBucket()}/{$this->filePath}", 'rb', false, $context))) { throw new Exception('Could not open stream for reading export [' . $this->filePath . ']'); } if (isset($this->start) && $this->start > 0) { fseek($stream, $this->start, SEEK_SET); } $remainingBytes = $this->length ?? $this->size; $chunkSize = 100; $video = response()->stream( function () use ($stream, $remainingBytes, $chunkSize) { while (!feof($stream) && $remainingBytes > 0) { $toGrab = min($chunkSize, $remainingBytes); echo fread($stream, $toGrab); $remainingBytes -= $toGrab; flush(); } fclose($stream); }, ($this->isRange ? 206 : 200), $this->returnHeaders ); return $video; } }
Like I said on the comments section. I think you should use S3 url (temporary, or public). You have some options here: Use laravel temporary url; Set your file as public + get url; For more information: https://laravel.com/docs/5.5/filesystem#storing-files To set your file visibility as public: Storage::setVisibility('file.jpg', 'public') Temporary URL: $url = Storage::temporaryUrl( 'file1.jpg', Carbon::now()->addMinutes(5) ); If your file is public, you can use: Storage::url('file1.jpg');
How to recive email with laravel?
Is there a way to recover emails from a gmail account through laravel ? I want to create an inbox mail, but directly from an acount of gmail or outlook. Thanks for help.
David, Follow below some code that I use to read emails. I believe that can helps you: /** * Get last UID on Emails table * * return integer */ private function getLastUID() { // I have a model Email and I try to get the higher uid on database return Email::max('uid'); } /** * Open Imap instance * * #return resource */ private function startEmail() { return imap_open(env('IMAP'), env('IMAP_EMAIL'), env('IMAP_PASSWORD'), OP_READONLY); } /** * Get Emails from Imap instance * * #return array */ private function getTodayEmails() { $mailbox = $this->startEmail(); $today = Carbon::now()->format('j-M-Y'); //I only search for todays emails, since I have a cron job that runs this task every hour (For my purpose I don't need to check it every minute) $inbox = imap_search($mailbox,'SINCE '.$today); /* If there is no email */ if ($inbox === false) return false; //Sort to insert the new email first rsort($inbox); $emails = []; foreach($inbox as $box) { /* get information specific to this email */ $overview = imap_fetch_overview($mailbox, $box, 0); $header = imap_headerinfo($mailbox , $box); $uid = imap_uid($mailbox , $box); // Here I check if the email $uid is already on my database, if no, I save it. If yes I break the conditional. // I highly believe that you have to work on this conditional and in your Model. The rest is working well (at least for me! :) ) if ($uid > $this->getLastUID()) { $emails[$box]['uid'] = $uid; $emails[$box]['date'] = (isset($header->udate)) ? date('Y-m-d H:i:s', $header->udate) : null; $emails[$box]['subject'] = (isset($overview[0]->subject)) ? $overview[0]->subject : null; $emails[$box]['from'] = (isset($header->from[0])) ? $this->extractEmail($header->from[0]) : null; $emails[$box]['from_name'] = (isset($header->from[0]->personal)) ? $header->from[0]->personal : null; $emails[$box]['to'] = (isset($header->to[0])) ? $this->extractEmail($header->to[0]) : null; $emails[$box]['to_name'] = (isset($header->to[0]->personal)) ? $header->to[0]->personal : null; $emails[$box]['reply_to'] = (isset($header->reply_to[0])) ? $this->extractEmail($header->reply_to[0]) : null; $emails[$box]['reply_name'] = (isset($header->reply_to[0]->personal)) ? $header->reply_to[0]->personal : null; /* output the email body */ $emails[$box]['message'] = $this->getBody($uid, $mailbox); } else { break; } imap_close($mailbox); return $emails; } /** * Extract email from Imap Instance * * #param object $email * * #return bool|string */ private function extractEmail($email) { if (isset($email->mailbox) && isset($email->host)) return $email->mailbox.'#'.$email->host; return false; } /** * Get body message * * #param integer $uid * #param Imap Instance $imap * * #return bool */ private function getBody($uid, $imap) { $body = $this->getPart($imap, $uid, "TEXT/HTML"); // if HTML body is empty, try getting text body if ($body == "") { $body = $this->getPart($imap, $uid, "TEXT/PLAIN"); } return $body; } /** * Treat body message of email * * #param Imap Instance $imap * #param integer $uid * #param string $mimetype * #param bool $structure * #param bool $partNumber * * #return bool|string */ private function getPart($imap, $uid, $mimetype, $structure = false, $partNumber = false) { if (!$structure) { $structure = imap_fetchstructure($imap, $uid, FT_UID); } if ($structure) { if ($mimetype == $this->getMimeType($structure)) { if (!$partNumber) { $partNumber = 1; } $text = imap_fetchbody($imap, $uid, $partNumber, FT_UID); switch ($structure->encoding) { case 3: return imap_base64($text); case 4: return imap_qprint($text); default: return $text; } } // multipart if ($structure->type == 1) { foreach ($structure->parts as $index => $subStruct) { $prefix = ""; if ($partNumber) { $prefix = $partNumber . "."; } $data = $this->getPart($imap, $uid, $mimetype, $subStruct, $prefix . ($index + 1)); if ($data) { return $data; } } } } return false; } /** * Get Mimetype of part * * #param $structure * * #return string */ private function getMimeType($structure) { $primaryMimetype = array("TEXT", "MULTIPART", "MESSAGE", "APPLICATION", "AUDIO", "IMAGE", "VIDEO", "OTHER"); if ($structure->subtype) { return $primaryMimetype[(int)$structure->type] . "/" . $structure->subtype; } return "TEXT/PLAIN"; } On the .env you must insert: IMAP={imap.gmail.com:993/ssl/novalidate-cert}INBOX (or you can use {imap.gmail.com:993/imap/ssl}INBOX) IMAP_EMAIL=<Your GMAIL> IMAP_PASSWORD=<PASSWORD> Although you can use some libraries, like https://github.com/barbushin/php-imap. I really believe that it is easy to go straight with raw php (http://php.net/manual/en/book.imap.php). You can get more information on: https://davidwalsh.name/gmail-php-imap (Where most of the functions are from, btw)
You can use GMAIL API https://developers.google.com/gmail/api/quickstart/php You can search or filter files using the messages.list and threads.list methods https://developers.google.com/gmail/api/guides/filtering GET https://www.googleapis.com/gmail/v1/users/me/messages?q="in:sent after:2014/01/01 before:2014/01/30"
why we use $this__("Some text") instead simple echo magento
I am working with magento and have a question in mind that why we use $this__("Some text") instead simple echo magento. can anyone ?
When you call echo $this->__("some text"); You can start by looking at Mage_Core_Helper_Abstract /** * Translate * * #return string */ public function __() { $args = func_get_args(); $expr = new Mage_Core_Model_Translate_Expr(array_shift($args), $this->_getModuleName()); array_unshift($args, $expr); return Mage::app()->getTranslator()->translate($args); } Next is Mage_Core_Model_App /** * Retrieve translate object * * #return Mage_Core_Model_Translate */ public function getTranslator() { if (!$this->_translator) { $this->_translator = Mage::getSingleton('core/translate'); } return $this->_translator; } Which is handed to Mage_Core_Model_Translate /** * Translate * * #param array $args * #return string */ public function translate($args) { $text = array_shift($args); if (is_string($text) && ''==$text || is_null($text) || is_bool($text) && false===$text || is_object($text) && ''==$text->getText()) { return ''; } if ($text instanceof Mage_Core_Model_Translate_Expr) { $code = $text->getCode(self::SCOPE_SEPARATOR); $module = $text->getModule(); $text = $text->getText(); $translated = $this->_getTranslatedString($text, $code); } else { if (!empty($_REQUEST['theme'])) { $module = 'frontend/default/'.$_REQUEST['theme']; } else { $module = 'frontend/default/default'; } $code = $module.self::SCOPE_SEPARATOR.$text; $translated = $this->_getTranslatedString($text, $code); } //array_unshift($args, $translated); //$result = #call_user_func_array('sprintf', $args); $result = #vsprintf($translated, $args); if ($result === false) { $result = $translated; } if ($this->_translateInline && $this->getTranslateInline()) { if (strpos($result, '{{{')===false || strpos($result, '}}}')===false || strpos($result, '}}{{')===false) { $result = '{{{'.$result.'}}{{'.$translated.'}}{{'.$text.'}}{{'.$module.'}}}'; } } return $result; } which returns the resulting text. This is a quick walkthrough of how everything would be handled, you should view the classes themselves to get a more in-depth understanding. In simple when you call echo $this->__('some text') it look up same text in CSV file which is located in app>locale or app>design>frontend>YOUR_PACKAGE>YOUR_THEME_NAME>locale>translate.csv file if the same word exist then it translate a word means it is very useful in multi-language website
$this->__("Some text") Used for translation purpose