Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F1246938
upload_formatter.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Fri, Nov 21, 12:41 PM
Size
19 KB
Mime Type
text/x-php
Expires
Sun, Nov 23, 12:41 PM (1 d, 8 h)
Engine
blob
Format
Raw Data
Handle
810343
Attached To
rINP In-Portal
upload_formatter.php
View Options
<?php
/**
* @version $Id: upload_formatter.php 15677 2013-01-17 18:52:50Z alex $
* @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
||
!
$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
);
}
}
Event Timeline
Log In to Comment