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.
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"
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'];
}
// --------------------------------------------------------------------
}
Does anybody know how to get Magento to use the actual base URL of images instead of the cached ones?
Using Magento Community V 1.6.2.0
If I look at the URL of a product image you get something like this…
/media/catalog/product/cache/1/image/390x/5e06319eda06f020e43594a9c230972d/1/1/1101012001-J-1Front-Man/.jpg
I need for it to be more like:
/media/catalog/product/1101012001-J-1Front-Man/.jpg
Reason is that I'm using the M2EPro extension which allows you to sync products for sale/sold in Magento with eBay/Amazon. Problem is that eBay does not allow image URLs that are longer that 150 characters. The MD5 hash and other mixed in variables (that I believe originate at /app/code/core/Mage/Catalog/Helper/Image.php) make the URL too long for it to be usable for many of my images.
When M2EPro runs it pulls the cached image (because that is what Magento designates as the main image). I believe that I need to have only the absolute URL referenced and have not been able to put this all together yet.
I have seen lots and lots of similar questions that span years with no definite answer on this one. If I find the answer first I will post here, but any help is really, really appreciated!
Current code from Image.php file mentioned above:
$this->_baseFile = $baseFile;
// build new filename (most important params)
$path = array(
Mage::getSingleton('catalog/product_media_config')->getBaseMediaPath(),
Mage::app()->getStore()->getId(),
$path[] = $this->getDestinationSubdir()
);
if((!empty($this->_width)) || (!empty($this->_height)))
$path[] = "{$this->_width}x{$this->_height}";
// add misk params as a hash
$miscParams = array(
($this->_keepAspectRatio ? '' : 'non') . 'proportional',
($this->_keepFrame ? '' : 'no') . 'frame',
($this->_keepTransparency ? '' : 'no') . 'transparency',
($this->_constrainOnly ? 'do' : 'not') . 'constrainonly',
$this->_rgbToString($this->_backgroundColor),
'angle' . $this->_angle,
'quality' . $this->_quality
);
// if has watermark add watermark params to hash
if ($this->getWatermarkFile()) {
$miscParams[] = $this->getWatermarkFile();
$miscParams[] = $this->getWatermarkImageOpacity();
$miscParams[] = $this->getWatermarkPosition();
$miscParams[] = $this->getWatermarkWidth();
$miscParams[] = $this->getWatermarkHeigth();
}
$path[] = md5(implode('_', $miscParams));
// append prepared filename
$this->_newFile = implode('/', $path) . $file; // the $file contains heading slash
return $this;
}
public function getBaseFile()
{
return $this->_baseFile;
}
public function getNewFile()
{
return $this->_newFile;
}
/**
* #return Mage_Catalog_Model_Product_Image
*/
public function setImageProcessor($processor)
{
$this->_processor = $processor;
return $this;
}
/**
* #return Varien_Image
*/
public function getImageProcessor()
{
if( !$this->_processor ) {
// var_dump($this->_checkMemory());
// if (!$this->_checkMemory()) {
// $this->_baseFile = null;
// }
$this->_processor = new Varien_Image($this->getBaseFile());
}
$this->_processor->keepAspectRatio($this->_keepAspectRatio);
$this->_processor->keepFrame($this->_keepFrame);
$this->_processor->keepTransparency($this->_keepTransparency);
$this->_processor->constrainOnly($this->_constrainOnly);
$this->_processor->backgroundColor($this->_backgroundColor);
$this->_processor->quality($this->_quality);
return $this->_processor;
}
/**
* #see Varien_Image_Adapter_Abstract
* #return Mage_Catalog_Model_Product_Image
*/
public function resize()
{
if (is_null($this->getWidth()) && is_null($this->getHeight())) {
return $this;
}
$this->getImageProcessor()->resize($this->_width, $this->_height);
return $this;
}
/**
* #return Mage_Catalog_Model_Product_Image
*/
public function rotate($angle)
{
$angle = intval($angle);
$this->getImageProcessor()->rotate($angle);
return $this;
}
/**
* Set angle for rotating
*
* This func actually affects only the cache filename.
*
* #param int $angle
* #return Mage_Catalog_Model_Product_Image
*/
public function setAngle($angle)
{
$this->_angle = $angle;
return $this;
}
/**
* Add watermark to image
* size param in format 100x200
*
* #param string $file
* #param string $position
* #param string $size
* #param int $width
* #param int $heigth
* #param int $imageOpacity
* #return Mage_Catalog_Model_Product_Image
*/
public function setWatermark($file, $position=null, $size=null, $width=null, $heigth=null, $imageOpacity=null)
{
if ($this->_isBaseFilePlaceholder)
{
return $this;
}
if ($file) {
$this->setWatermarkFile($file);
} else {
return $this;
}
if ($position)
$this->setWatermarkPosition($position);
if ($size)
$this->setWatermarkSize($size);
if ($width)
$this->setWatermarkWidth($width);
if ($heigth)
$this->setWatermarkHeigth($heigth);
if ($imageOpacity)
$this->setImageOpacity($imageOpacity);
$filePath = $this->_getWatermarkFilePath();
if($filePath) {
$this->getImageProcessor()
->setWatermarkPosition( $this->getWatermarkPosition() )
->setWatermarkImageOpacity( $this->getWatermarkImageOpacity() )
->setWatermarkWidth( $this->getWatermarkWidth() )
->setWatermarkHeigth( $this->getWatermarkHeigth() )
->watermark($filePath);
}
return $this;
}
/**
* #return Mage_Catalog_Model_Product_Image
*/
public function saveFile()
{
$filename = $this->getNewFile();
$this->getImageProcessor()->save($filename);
Mage::helper('core/file_storage_database')->saveFile($filename);
return $this;
}
/**
* #return string
*/
public function getUrl()
{
$baseDir = Mage::getBaseDir('media');
$path = str_replace($baseDir . DS, "", $this->_newFile);
return Mage::getBaseUrl('media') . str_replace(DS, '/', $path);
}
public function push()
{
$this->getImageProcessor()->display();
}
/**
* #return Mage_Catalog_Model_Product_Image
*/
public function setDestinationSubdir($dir)
{
$this->_destinationSubdir = $dir;
return $this;
}
/**
* #return string
*/
public function getDestinationSubdir()
{
return $this->_destinationSubdir;
}
public function isCached()
{
return $this->_fileExists($this->_newFile);
}
/**
* Set watermark file name
*
* #param string $file
* #return Mage_Catalog_Model_Product_Image
*/
public function setWatermarkFile($file)
{
$this->_watermarkFile = $file;
return $this;
}
/**
* Get watermark file name
*
* #return string
*/
public function getWatermarkFile()
{
return $this->_watermarkFile;
}
/**
* Get relative watermark file path
* or false if file not found
*
* #return string | bool
*/
protected function _getWatermarkFilePath()
{
$filePath = false;
if (!$file = $this->getWatermarkFile())
{
return $filePath;
}
$baseDir = Mage::getSingleton('catalog/product_media_config')->getBaseMediaPath();
if( $this->_fileExists($baseDir . '/watermark/stores/' . Mage::app()->getStore()->getId() . $file) ) {
$filePath = $baseDir . '/watermark/stores/' . Mage::app()->getStore()->getId() . $file;
} elseif ( $this->_fileExists($baseDir . '/watermark/websites/' . Mage::app()->getWebsite()->getId() . $file) ) {
$filePath = $baseDir . '/watermark/websites/' . Mage::app()->getWebsite()->getId() . $file;
} elseif ( $this->_fileExists($baseDir . '/watermark/default/' . $file) ) {
$filePath = $baseDir . '/watermark/default/' . $file;
} elseif ( $this->_fileExists($baseDir . '/watermark/' . $file) ) {
$filePath = $baseDir . '/watermark/' . $file;
} else {
$baseDir = Mage::getDesign()->getSkinBaseDir();
if( $this->_fileExists($baseDir . $file) ) {
$filePath = $baseDir . $file;
}
}
return $filePath;
}
I guess you can use
echo Mage::getModel('catalog/product_media_config')
->getMediaUrl( $product->getImage() );
You can also use getSmallImage() or getThumbnail() methods instead.
What version of M2e Pro are you using, my current version is 6 and it has an option to use base image as opposed to gallery. Works great in my magento 1.6.2.0 if you have your base image at least 500 pixals