Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Tue, Feb 25, 5:42 AM

in-portal

Index: branches/5.2.x/core/kernel/utility/formatters/upload_formatter.php
===================================================================
--- branches/5.2.x/core/kernel/utility/formatters/upload_formatter.php (revision 15533)
+++ branches/5.2.x/core/kernel/utility/formatters/upload_formatter.php (revision 15534)
@@ -1,680 +1,680 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class kUploadFormatter extends kFormatter
{
var $DestinationPath;
var $FullPath;
/**
* File helper reference
*
* @var FileHelper
*/
var $fileHelper = NULL;
/**
* Creates formatter instance
*
* @access public
*/
public function __construct()
{
parent::__construct();
$this->fileHelper = $this->Application->recallObject('FileHelper');
if ( $this->DestinationPath ) {
$this->FullPath = FULL_PATH . $this->DestinationPath;
}
}
/**
* Initializes upload folder
*
* @param Array $options
* @return void
* @access protected
*/
protected function _initUploadFolder($options)
{
if ( getArrayValue($options, 'upload_dir') ) {
$this->DestinationPath = $options['upload_dir'];
$this->FullPath = FULL_PATH . $this->DestinationPath;
}
}
/**
* Processes file uploads from form
*
* @param mixed $value
* @param string $field_name
* @param kDBItem $object
* @return mixed
* @access public
*/
public function Parse($value, $field_name, &$object)
{
if ( !$this->Application->isAdmin ) {
// this allows to revert htmlspecialchars call for each field submitted on front-end
$value = is_array($value) ? array_map('htmlspecialchars_decode', $value) : htmlspecialchars_decode($value);
}
$ret = !is_array($value) ? $value : '';
$options = $object->GetFieldOptions($field_name);
$this->_initUploadFolder($options);
// SWF Uploader: BEGIN
if ( is_array($value) && isset($value['json']) ) {
$files_info = $this->_decodeJSON($value['json'], $options);
$this->Application->StoreVar($object->getFileInfoVariableName($field_name), serialize($files_info));
return getArrayValue($value, 'upload');
}
// SWF Uploader: END
if ( getArrayValue($value, 'upload') && getArrayValue($value, 'error') == UPLOAD_ERR_NO_FILE ) {
// file was not uploaded this time, but was uploaded before, then use previously uploaded file (from db)
return getArrayValue($value, 'upload');
}
if ( is_array($value) && count($value) > 1 && $value['size'] ) {
if ( is_array($value) && (int)$value['error'] === UPLOAD_ERR_OK ) {
$max_filesize = isset($options['max_size']) ? $options['max_size'] : MAX_UPLOAD_SIZE;
// we can get mime type based on file content and no use one, provided by the client
// $value['type'] = kUtil::mimeContentType($value['tmp_name']);
if ( getArrayValue($options, 'file_types') && !$this->extensionMatch($value['name'], $options['file_types']) ) {
// match by file extensions
$error_params = Array (
'file_name' => $value['name'],
'file_types' => $options['file_types'],
);
$object->SetError($field_name, 'bad_file_format', 'la_error_InvalidFileFormat', $error_params);
}
elseif ( getArrayValue($options, 'allowed_types') && !in_array($value['type'], $options['allowed_types']) ) {
// match by mime type provided by web-browser
$error_params = Array (
'file_type' => $value['type'],
'allowed_types' => $options['allowed_types'],
);
$object->SetError($field_name, 'bad_file_format', 'la_error_InvalidFileFormat', $error_params);
}
elseif ( $value['size'] > $max_filesize ) {
$object->SetError($field_name, 'bad_file_size', 'la_error_FileTooLarge');
}
elseif ( !is_writable($this->FullPath) ) {
$object->SetError($field_name, 'cant_save_file', 'la_error_cant_save_file');
}
else {
$real_name = $this->_getRealFilename($value['name'], $options, $object);
$file_name = $this->FullPath . $real_name;
$storage_format = isset($options['storage_format']) ? $options['storage_format'] : false;
if ( $storage_format ) {
$image_helper = $this->Application->recallObject('ImageHelper');
/* @var $image_helper ImageHelper */
move_uploaded_file($value['tmp_name'], $value['tmp_name'] . '.jpg'); // add extension, so ResizeImage can work
$url = $image_helper->ResizeImage($value['tmp_name'] . '.jpg', $storage_format);
$tmp_name = preg_replace('/^' . preg_quote($this->Application->BaseURL(), '/') . '/', '/', $url);
$moved = rename($tmp_name, $file_name);
}
else {
$moved = move_uploaded_file($value['tmp_name'], $file_name);
}
if ( !$moved ) {
$object->SetError($field_name, 'cant_save_file', 'la_error_cant_save_file');
}
else {
@chmod($file_name, 0666);
if ( getArrayValue($options, 'size_field') ) {
$object->SetDBField($options['size_field'], $value['size']);
}
if ( getArrayValue($options, 'orig_name_field') ) {
$object->SetDBField($options['orig_name_field'], $value['name']);
}
if ( getArrayValue($options, 'content_type_field') ) {
$object->SetDBField($options['content_type_field'], $value['type']);
}
$ret = getArrayValue($options, 'upload_dir') ? $real_name : $this->DestinationPath . $real_name;
// delete previous file, when new file is uploaded under same field
/*$previous_file = isset($value['upload']) ? $value['upload'] : false;
if ($previous_file && file_exists($this->FullPath.$previous_file)) {
unlink($this->FullPath.$previous_file);
}*/
}
}
}
else {
$object->SetError($field_name, 'cant_save_file', 'la_error_cant_save_file');
}
}
if ( (count($value) > 1) && $value['error'] && ($value['error'] != UPLOAD_ERR_NO_FILE) ) {
$object->SetError($field_name, 'cant_save_file', 'la_error_cant_save_file', $value);
}
return $ret;
}
/**
* Checks, that given file name has on of provided file extensions
*
* @param string $filename
* @param string $file_types
* @return bool
* @access protected
*/
protected function extensionMatch($filename, $file_types)
{
if ( preg_match_all('/\*\.(.*?)(;|$)/', $file_types, $regs) ) {
$file_extension = mb_strtolower( pathinfo($filename, PATHINFO_EXTENSION) );
$file_extensions = array_map('mb_strtolower', $regs[1]);
return in_array($file_extension, $file_extensions);
}
return true;
}
/**
* Decodes JSON information about uploaded files
*
* @param string $json
* @param Array $options
* @return Array
* @access protected
*/
protected function _decodeJSON($json, $options)
{
if ( !$json ) {
return Array ();
}
$ret = Array ();
$files_info = explode('|', $json);
$max_files = $this->_getMaxFiles($options);
foreach ($files_info as $file_info) {
$file_info = (array)json_decode($file_info);
if ( $file_info['deleted'] ) {
$ret[$file_info['name']] = $file_info;
}
elseif ( $max_files ) {
$ret[$file_info['name']] = $file_info;
$max_files--;
}
}
uasort($ret, Array ($this, '_sortFiles'));
return $ret;
}
/**
* Resorts uploaded files according to given file order
*
* @param $file_a
* @param $file_b
* @return int
* @access protected
*/
protected function _sortFiles($file_a, $file_b)
{
$file_a_order = isset($file_a['order']) ? (int)$file_a['order'] : 0;
$file_b_order = isset($file_b['order']) ? (int)$file_b['order'] : 0;
if ( $file_a_order == $file_b_order ) {
return 0;
}
return ($file_a_order < $file_b_order) ? -1 : 1;
}
/**
* Returns maximal allowed file count per field
*
* @param Array $options
* @return int
* @access protected
*/
protected function _getMaxFiles($options)
{
if ( !isset($options['multiple']) ) {
return 1;
}
return $options['multiple'] == false ? 1 : $options['multiple'];
}
/**
* Processes uploaded files
*
* @param kDBItem $object
* @param string $field_name
* @param int $id
* @return Array
*/
public function processFlashUpload($object, $field_name, $id = null)
{
$value = $object->GetDBField($field_name);
$options = $object->GetFieldOptions($field_name);
$this->_initUploadFolder($options);
$files_info = $this->Application->RecallVar($object->getFileInfoVariableName($field_name, $id));
if ( !$files_info ) {
$this->Application->RemoveVar($object->getFileInfoVariableName($field_name, $id));
return Array ();
}
$files_info = unserialize($files_info);
$live_files = $value ? explode('|', $value) : Array ();
// don't rename file into file, that will be deleted
$files_to_delete = $this->_getFilesToDelete($object);
foreach ($files_info as $file_name => $file_info) {
if ( $file_info['deleted'] ) {
// user deleted live file
$live_files = array_diff($live_files, Array ($file_name));
}
elseif ( $file_info['temp'] == 1 ) {
// user uploaded new file to temp folder
// 1. get unique filename for live folder
$real_name = $this->_getRealFilename($file_name, $options, $object, $files_to_delete);
$file_name = $this->FullPath . $real_name;
// 2. move file from temp folder to live folder
$tmp_file = WRITEABLE . '/tmp/' . $file_info['id'] . '_' . $file_info['name'];
rename($tmp_file, $file_name);
// 3. add to resulting file list
@chmod($file_name, 0666);
$live_files[] = getArrayValue($options, 'upload_dir') ? $real_name : $this->DestinationPath . $real_name;
}
}
$this->Application->RemoveVar($object->getFileInfoVariableName($field_name, $id));
$object->SetDBField($field_name, implode('|', $live_files));
if ( $object->GetOriginalField($field_name, true) != $object->GetField($field_name) ) {
return Array ($field_name);
}
return Array ();
}
/**
* Returns final filename after applying storage-engine specific naming
*
* @param string $file_name
* @param Array $options
* @param kDBItem $object
* @param Array $files_to_delete
* @return string
* @access protected
*/
protected function _getRealFilename($file_name, $options, $object, $files_to_delete = Array ())
{
$real_name = $this->getStorageEngineFile($file_name, $options, $object->Prefix);
$real_name = $this->getStorageEngineFolder($real_name, $options) . $real_name;
return $this->fileHelper->ensureUniqueFilename($this->FullPath, $real_name, $files_to_delete);
}
/**
* Returns list of files, that user marked for deletion
*
* @param kDBItem $object
* @return Array
* @access protected
*/
protected function _getFilesToDelete($object)
{
$var_name = $object->getPendingActionVariableName();
$schedule = $this->Application->RecallVar($var_name);
if ( !$schedule ) {
return Array ();
}
$ret = Array ();
$schedule = unserialize($schedule);
foreach ($schedule as $data) {
if ( $data['action'] == 'delete' ) {
$ret[] = $data['file'];
}
}
return $ret;
}
/**
* Allows to determine single-file format based on multi-file format
*
* @param string $format
* @return string
* @access protected
*/
protected function getSingleFormat($format)
{
$single_mapping = Array (
'file_urls' => 'full_url',
'file_paths' => 'full_path',
'file_sizes' => 'file_size',
'files_resized' => 'resize',
'files_json' => 'file_json',
'img_sizes' => 'img_size',
'wms' => 'wm',
);
return $single_mapping[$format];
}
/**
* Return formatted file url,path or size (or same for multiple files)
*
* @param string $value
* @param string $field_name
* @param kDBItem|kDBList $object
* @param string $format
* @return string
*/
function Format($value, $field_name, &$object, $format = NULL)
{
if ( is_null($value) ) {
return '';
}
$options = $object->GetFieldOptions($field_name);
if ( !isset($format) ) {
$format = isset($options['format']) ? $options['format'] : false;
}
if ( $format && preg_match('/(file_urls|file_paths|file_names|file_sizes|img_sizes|files_resized|files_json|wms)(.*)/', $format, $regs) ) {
if ( $format == 'files_json' ) {
$value = $this->_mergeFilesFromSession($value, $field_name, $object);
}
if ( !$value || $format == 'file_names' ) {
// storage format matches display format OR no value
return $value;
}
$ret = Array ();
$files = explode('|', $value);
$format = $this->getSingleFormat($regs[1]) . $regs[2];
foreach ($files as $a_file) {
$ret[] = $this->GetFormatted($a_file, $field_name, $object, $format);
}
return implode('|', $ret);
}
$tc_value = $this->TypeCast($value, $options);
if ( ($tc_value === false) || ($tc_value != $value) ) {
// for leaving badly formatted date on the form
return $value;
}
// force direct links for case, when non-swf uploader is used
return $this->GetFormatted($tc_value, $field_name, $object, $format, true);
}
/**
* Merges filenames from session into database filenames list
*
* @param string $value
* @param string $field_name
* @param kDBItem $object
* @return string
*/
protected function _mergeFilesFromSession($value, $field_name, $object)
{
$files_info = $this->Application->RecallVar($object->getFileInfoVariableName($field_name));
if ( $files_info ) {
$temp_files = array_keys(unserialize($files_info));
$live_files = $value ? explode('|', $value) : Array ();
$value = implode('|', array_merge($live_files, $temp_files));
}
return $value;
}
/**
* Return formatted file url,path or size
*
* @param string $value
* @param string $field_name
* @param kDBItem $object
* @param string $format
* @param bool $force_direct_links
* @return string
*/
function GetFormatted($value, $field_name, &$object, $format = NULL, $force_direct_links = NULL)
{
- if ( !$format ) {
+ if ( !$format || !$value ) {
return $value;
}
$options = $object->GetFieldOptions($field_name);
$upload_dir = isset($options['include_path']) && $options['include_path'] ? '' : $this->getUploadDir($options);
if ( preg_match('/resize:([\d]*)x([\d]*)/', $format, $regs) ) {
$image_helper = $this->Application->recallObject('ImageHelper');
/* @var $image_helper ImageHelper */
return $image_helper->ResizeImage($value ? FULL_PATH . str_replace('/', DIRECTORY_SEPARATOR, $upload_dir) . $value : '', $format);
}
switch ($format) {
case 'full_url':
if ( isset($force_direct_links) ) {
$direct_links = $force_direct_links;
}
else {
$direct_links = isset($options['direct_links']) ? $options['direct_links'] : false;
}
if ( $direct_links ) {
return $this->fileHelper->pathToUrl(FULL_PATH . $upload_dir . $value);
}
else {
$url_params = Array (
'no_amp' => 1, 'pass' => 'm,'.$object->Prefix,
$object->Prefix . '_event' => 'OnViewFile',
'file' => rawurlencode($value), 'field' => $field_name
);
return $this->Application->HREF('', '', $url_params);
}
break;
case 'full_path':
return FULL_PATH . str_replace('/', DIRECTORY_SEPARATOR, $upload_dir) . $value;
break;
case 'file_size':
return filesize(FULL_PATH . str_replace('/', DIRECTORY_SEPARATOR, $upload_dir) . $value);
break;
case 'img_size':
$image_helper = $this->Application->recallObject('ImageHelper');
/* @var $image_helper ImageHelper */
$image_info = $image_helper->getImageInfo(FULL_PATH . str_replace('/', DIRECTORY_SEPARATOR, $upload_dir) . $value);
return $image_info ? $image_info[3] : '';
break;
case 'file_json':
// get info about 1 file as JSON-encoded object
$files_info = $this->Application->RecallVar($object->getFileInfoVariableName($field_name));
$files_info = $files_info ? unserialize($files_info) : Array ();
if ( isset($files_info[$value]) ) {
// file that was uploaded, but not saved to database
return json_encode($files_info[$value]);
}
$file_info = Array (
'id' => 'uploaded_' . crc32($value),
'name' => $value,
'size' => $this->GetFormatted($value, $field_name, $object, 'file_size'),
'deleted' => 0,
'temp' => 0,
);
return json_encode($file_info);
break;
}
return sprintf($format, $value);
}
/**
* Creates & returns folder, based on storage engine specified in field options
*
* @param string $file_name
* @param array $options
* @return string
* @access protected
*/
protected function getStorageEngineFolder($file_name, $options)
{
$storage_engine = (string)getArrayValue($options, 'storage_engine');
if ( !$storage_engine ) {
return '';
}
switch ($storage_engine) {
case StorageEngine::HASH:
$folder_path = kUtil::getHashPathForLevel($file_name);
break;
case StorageEngine::TIMESTAMP:
$folder_path = adodb_date('Y-m/d/');
break;
default:
throw new Exception('Unknown storage engine "<strong>' . $storage_engine . '</strong>".');
break;
}
return $folder_path;
}
/**
* Applies prefix & suffix to uploaded filename, based on storage engine in field options
*
* @param string $name
* @param array $options
* @param string $unit_prefix
* @return string
* @access protected
*/
protected function getStorageEngineFile($name, $options, $unit_prefix)
{
$prefix = $this->getStorageEngineFilePart(getArrayValue($options, 'filename_prefix'), $unit_prefix);
$suffix = $this->getStorageEngineFilePart(getArrayValue($options, 'filename_suffix'), $unit_prefix);
$parts = pathinfo($name);
return ($prefix ? $prefix . '_' : '') . $parts['filename'] . ($suffix ? '_' . $suffix : '') . '.' . $parts['extension'];
}
/**
* Creates prefix/suffix to join with uploaded file
*
* Added "u" before user_id to keep this value after FileHelper::ensureUniqueFilename method call
*
* @param string $option
* @param string $unit_prefix
* @return string
* @access protected
*/
protected function getStorageEngineFilePart($option, $unit_prefix)
{
$replace_from = Array (
StorageEngine::PS_DATE_TIME, StorageEngine::PS_PREFIX, StorageEngine::PS_USER
);
$replace_to = Array (
adodb_date('Ymd-His'), $unit_prefix, 'u' . $this->Application->RecallVar('user_id')
);
return str_replace($replace_from, $replace_to, $option);
}
public function getUploadDir($options)
{
return isset($options['upload_dir']) ? $options['upload_dir'] : $this->DestinationPath;
}
}
class kPictureFormatter extends kUploadFormatter
{
public function __construct()
{
$this->NakeLookupPath = IMAGES_PATH; // used ?
$this->DestinationPath = kUtil::constOn('ADMIN') ? IMAGES_PENDING_PATH : IMAGES_PATH;
parent::__construct();
}
/**
* Return formatted file url,path or size
*
* @param string $value
* @param string $field_name
* @param kDBItem $object
* @param string $format
* @param bool $force_direct_links
* @return string
*/
function GetFormatted($value, $field_name, &$object, $format = NULL, $force_direct_links = NULL)
{
if ( $format == 'img_size' ) {
$options = $object->GetFieldOptions($field_name);
$img_path = FULL_PATH . '/' . $this->getUploadDir($options) . $value;
$image_info = getimagesize($img_path);
return ' ' . $image_info[3];
}
return parent::GetFormatted($value, $field_name, $object, $format, $force_direct_links);
}
}
\ No newline at end of file

Event Timeline