Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Sat, Feb 22, 12:03 AM

in-portal

Index: branches/5.2.x/core/units/helpers/file_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/file_helper.php (revision 16128)
+++ branches/5.2.x/core/units/helpers/file_helper.php (revision 16129)
@@ -1,463 +1,484 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 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 FileHelper extends kHelper {
/**
* Puts existing item images (from sub-item) to virtual fields (in main item)
*
* @param kCatDBItem $object
* @return void
* @access public
*/
public function LoadItemFiles(&$object)
{
$max_file_count = $this->Application->ConfigValue($object->Prefix.'_MaxImageCount'); // file count equals to image count (temporary measure)
$sql = 'SELECT *
FROM '.TABLE_PREFIX.'CatalogFiles
WHERE ResourceId = '.$object->GetDBField('ResourceId').'
ORDER BY FileId ASC
LIMIT 0, '.(int)$max_file_count;
$item_files = $this->Conn->Query($sql);
$file_counter = 1;
foreach ($item_files as $item_file) {
$file_path = $item_file['FilePath'];
$object->SetDBField('File'.$file_counter, $file_path);
$object->SetOriginalField('File'.$file_counter, $file_path);
$object->SetFieldOption('File'.$file_counter, 'original_field', $item_file['FileName']);
$file_counter++;
}
}
/**
* Saves newly uploaded images to external image table
*
* @param kCatDBItem $object
* @return void
* @access public
*/
public function SaveItemFiles(&$object)
{
$table_name = $this->Application->getUnitOption('#file', 'TableName');
$max_file_count = $this->Application->getUnitOption($object->Prefix, 'FileCount'); // $this->Application->ConfigValue($object->Prefix.'_MaxImageCount');
$this->CheckFolder(FULL_PATH . ITEM_FILES_PATH);
$i = 0;
while ($i < $max_file_count) {
$field = 'File'.($i + 1);
$field_options = $object->GetFieldOptions($field);
$file_path = $object->GetDBField($field);
if ($file_path) {
if (isset($field_options['original_field'])) {
$key_clause = 'FileName = '.$this->Conn->qstr($field_options['original_field']).' AND ResourceId = '.$object->GetDBField('ResourceId');
if ($object->GetDBField('Delete'.$field)) {
// if item was cloned, then new filename is in db (not in $image_src)
$sql = 'SELECT FilePath
FROM '.$table_name.'
WHERE '.$key_clause;
$file_path = $this->Conn->GetOne($sql);
if (@unlink(FULL_PATH.ITEM_FILES_PATH.$file_path)) {
$sql = 'DELETE FROM '.$table_name.'
WHERE '.$key_clause;
$this->Conn->Query($sql);
}
}
else {
// image record found -> update
$fields_hash = Array (
'FilePath' => $file_path,
);
$this->Conn->doUpdate($fields_hash, $table_name, $key_clause);
}
}
else {
// record not found -> create
$fields_hash = Array (
'ResourceId' => $object->GetDBField('ResourceId'),
'FileName' => $field,
'Status' => STATUS_ACTIVE,
'FilePath' => $file_path,
);
$this->Conn->doInsert($fields_hash, $table_name);
$field_options['original_field'] = $field;
$object->SetFieldOptions($field, $field_options);
}
}
$i++;
}
}
/**
* Preserves cloned item images/files to be rewritten with original item images/files
*
* @param Array $field_values
* @return void
* @access public
*/
public function PreserveItemFiles(&$field_values)
{
foreach ($field_values as $field_name => $field_value) {
if ( !is_array($field_value) ) {
continue;
}
if ( isset($field_value['upload']) && ($field_value['error'] == UPLOAD_ERR_NO_FILE) ) {
// this is upload field, but nothing was uploaded this time
unset($field_values[$field_name]);
}
}
}
/**
* Determines what image/file fields should be created (from post or just dummy fields for 1st upload)
*
* @param string $prefix
* @param bool $is_image
* @return void
* @access public
*/
public function createItemFiles($prefix, $is_image = false)
{
$items_info = $this->Application->GetVar($prefix);
if ($items_info) {
list (, $fields_values) = each($items_info);
$this->createUploadFields($prefix, $fields_values, $is_image);
}
else {
$this->createUploadFields($prefix, Array(), $is_image);
}
}
/**
* Dynamically creates virtual fields for item for each image/file field in submit
*
* @param string $prefix
* @param Array $fields_values
* @param bool $is_image
* @return void
* @access public
*/
public function createUploadFields($prefix, $fields_values, $is_image = false)
{
$field_options = Array (
'type' => 'string',
'max_len' => 240,
'default' => '',
);
if ($is_image) {
$field_options['formatter'] = 'kPictureFormatter';
$field_options['include_path'] = 1;
$field_options['allowed_types'] = Array ('image/jpeg', 'image/pjpeg', 'image/png', 'image/x-png', 'image/gif', 'image/bmp');
$field_prefix = 'Image';
}
else {
$field_options['formatter'] = 'kUploadFormatter';
$field_options['upload_dir'] = ITEM_FILES_PATH;
$field_options['allowed_types'] = Array ('application/pdf', 'application/msexcel', 'application/msword', 'application/mspowerpoint');
$field_prefix = 'File';
}
$fields = $this->Application->getUnitOption($prefix, 'Fields');
$virtual_fields = $this->Application->getUnitOption($prefix, 'VirtualFields');
$image_count = 0;
foreach ($fields_values as $field_name => $field_value) {
if (preg_match('/^('.$field_prefix.'[\d]+|Primary'.$field_prefix.')$/', $field_name)) {
$fields[$field_name] = $field_options;
$virtual_fields[$field_name] = $field_options;
$this->_createCustomFields($prefix, $field_name, $virtual_fields, $is_image);
$image_count++;
}
}
if (!$image_count) {
// no images found in POST -> create default image fields
$image_count = $this->Application->ConfigValue($prefix.'_MaxImageCount');
if ($is_image) {
$created_count = 1;
$image_names = Array ('Primary' . $field_prefix => '');
while ($created_count < $image_count) {
$image_names[$field_prefix . $created_count] = '';
$created_count++;
}
}
else {
$created_count = 0;
$image_names = Array ();
while ($created_count < $image_count) {
$image_names[$field_prefix . ($created_count + 1)] = '';
$created_count++;
}
}
if ($created_count) {
$this->createUploadFields($prefix, $image_names, $is_image);
}
return ;
}
$this->Application->setUnitOption($prefix, $field_prefix.'Count', $image_count);
$this->Application->setUnitOption($prefix, 'Fields', $fields);
$this->Application->setUnitOption($prefix, 'VirtualFields', $virtual_fields);
}
/**
* Adds ability to create more virtual fields associated with main image/file
*
* @param string $prefix
* @param string $field_name
* @param Array $virtual_fields
* @param bool $is_image
* @return void
* @access protected
*/
protected function _createCustomFields($prefix, $field_name, &$virtual_fields, $is_image = false)
{
$virtual_fields['Delete' . $field_name] = Array ('type' => 'int', 'default' => 0);
if ( $is_image ) {
$virtual_fields[$field_name . 'Alt'] = Array ('type' => 'string', 'default' => '');
}
}
/**
* Downloads file to user
*
* @param string $filename
* @return void
* @access public
*/
public function DownloadFile($filename)
{
$this->Application->setContentType(kUtil::mimeContentType($filename), false);
header('Content-Disposition: attachment; filename="' . basename($filename) . '"');
header('Content-Length: ' . filesize($filename));
readfile($filename);
flush();
}
/**
* Creates folder with given $path
*
* @param string $path
* @return bool
* @access public
*/
public function CheckFolder($path)
{
$result = true;
if (!file_exists($path) || !is_dir($path)) {
$parent_path = preg_replace('#(/|\\\)[^/\\\]+(/|\\\)?$#', '', rtrim($path , '/\\'));
$result = $this->CheckFolder($parent_path);
if ($result) {
$result = mkdir($path);
if ($result) {
chmod($path, 0777);
// don't commit any files from created folder
if (file_exists(FULL_PATH . '/CVS')) {
$cvsignore = fopen($path . '/.cvsignore', 'w');
fwrite($cvsignore, '*.*');
fclose($cvsignore);
chmod($path . '/.cvsignore', 0777);
}
}
else {
trigger_error('Cannot create directory "<strong>' . $path . '</strong>"', E_USER_WARNING);
return false;
}
}
}
return $result;
}
/**
* Copies all files and directories from $source to $destination directory. Create destination directory, when missing.
*
* @param string $source
* @param string $destination
* @return bool
* @access public
*/
public function copyFolderRecursive($source, $destination)
{
if ( substr($source, -1) == DIRECTORY_SEPARATOR ) {
$source = substr($source, 0, -1);
$destination .= DIRECTORY_SEPARATOR . basename($source);
}
$iterator = new DirectoryIterator($source);
/* @var $file_info DirectoryIterator */
$result = $this->CheckFolder($destination);
foreach ($iterator as $file_info) {
if ( $file_info->isDot() ) {
continue;
}
$file = $file_info->getFilename();
if ( $file_info->isDir() ) {
$result = $this->copyFolderRecursive($file_info->getPathname(), $destination . DIRECTORY_SEPARATOR . $file);
}
else {
$result = copy($file_info->getPathname(), $destination . DIRECTORY_SEPARATOR . $file);
}
if (!$result) {
trigger_error('Cannot create file/directory "<strong>' . $destination . DIRECTORY_SEPARATOR . $file . '</strong>"', E_USER_WARNING);
break;
}
}
return $result;
}
/**
* Copies all files from $source to $destination directory. Create destination directory, when missing.
*
* @param string $source
* @param string $destination
* @return bool
* @access public
*/
public function copyFolder($source, $destination)
{
if ( substr($source, -1) == DIRECTORY_SEPARATOR ) {
$source = substr($source, 0, -1);
$destination .= DIRECTORY_SEPARATOR . basename($source);
}
$iterator = new DirectoryIterator($source);
/* @var $file_info DirectoryIterator */
$result = $this->CheckFolder($destination);
foreach ($iterator as $file_info) {
if ( $file_info->isDot() || !$file_info->isFile() ) {
continue;
}
$file = $file_info->getFilename();
$result = copy($file_info->getPathname(), $destination . DIRECTORY_SEPARATOR . $file);
if ( !$result ) {
trigger_error('Cannot create file "<strong>' . $destination . DIRECTORY_SEPARATOR . $file . '</strong>"', E_USER_WARNING);
break;
}
}
return $result;
}
/**
* Transforms given path to file into it's url, where each each component is encoded (excluding domain and protocol)
*
* @param string $url
* @return string
* @access public
*/
public function pathToUrl($url)
{
$url = str_replace(DIRECTORY_SEPARATOR, '/', preg_replace('/^' . preg_quote(FULL_PATH, '/') . '(.*)/', '\\1', $url, 1));
// TODO: why?
$url = implode('/', array_map('rawurlencode', explode('/', $url)));
return rtrim($this->Application->BaseURL(), '/') . $url;
}
/**
* Transforms given url to path to it
*
* @param string $url
* @return string
* @access public
*/
public function urlToPath($url)
{
$base_url = rtrim($this->Application->BaseURL(), '/');
// escape replacement patterns, like "\<number>"
$full_path = preg_replace('/(\\\[\d]+)/', '\\\\\1', FULL_PATH);
$path = preg_replace('/^' . preg_quote($base_url, '/') . '(.*)/', $full_path . '\\1', $url, 1);
return str_replace('/', DIRECTORY_SEPARATOR, kUtil::unescape($path, kUtil::ESCAPE_URL));
}
/**
+ * Makes given paths DocumentRoot agnostic.
+ *
+ * @param array $paths List of file paths.
+ *
+ * @return array
+ */
+ public function makeRelative(array $paths)
+ {
+ foreach ( $paths as $index => $path ) {
+ $replaced_count = 0;
+ $relative_path = preg_replace('/^' . preg_quote(FULL_PATH, '/') . '/', '', $path, 1, $replaced_count);
+
+ if ( $replaced_count === 1 ) {
+ $paths[$index] = $relative_path;
+ }
+ }
+
+ return $paths;
+ }
+
+ /**
* Ensures, that new file will not overwrite any of previously created files with same name
*
* @param string $path
* @param string $name
* @param Array $forbidden_names
* @return string
*/
public function ensureUniqueFilename($path, $name, $forbidden_names = Array ())
{
$parts = pathinfo($name);
$ext = '.' . $parts['extension'];
$filename = $parts['filename'];
$path = rtrim($path, '/');
$original_checked = false;
$new_name = $filename . $ext;
if ( $parts['dirname'] != '.' ) {
$path .= '/' . ltrim($parts['dirname'], '/');
}
// make sure target folder always exists, especially for cases,
// when storage engine folder is supplied as a part of $name
$this->CheckFolder($path);
while (file_exists($path . '/' . $new_name) || in_array($path . '/' . $new_name, $forbidden_names)) {
if ( preg_match('/(.*)_([0-9]*)(' . preg_quote($ext, '/') . ')/', $new_name, $regs) ) {
$new_name = $regs[1] . '_' . ((int)$regs[2] + 1) . $regs[3];
}
elseif ( $original_checked ) {
$new_name = $filename . '_1' . $ext;
}
$original_checked = true;
}
if ( $parts['dirname'] != '.' ) {
$new_name = $parts['dirname'] . '/' . $new_name;
}
return $new_name;
}
}
Index: branches/5.2.x/core/units/helpers/image_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/image_helper.php (revision 16128)
+++ branches/5.2.x/core/units/helpers/image_helper.php (revision 16129)
@@ -1,714 +1,720 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 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 ImageHelper extends kHelper {
/**
* File helper reference
*
* @var FileHelper
*/
var $fileHelper = null;
public function __construct()
{
parent::__construct();
ini_set('gd.jpeg_ignore_warning', 1);
$this->fileHelper = $this->Application->recallObject('FileHelper');
}
/**
* Parses format string into array
*
* @param string $format sample format: "resize:300x500;wm:inc/wm.png|c|-20"
* @return Array sample result: Array('max_width' => 300, 'max_height' => 500, 'wm_filename' => 'inc/wm.png', 'h_margin' => 'c', 'v_margin' => -20)
*/
function parseFormat($format)
{
$res = Array ();
$format_parts = explode(';', $format);
foreach ($format_parts as $format_part) {
if (preg_match('/^resize:(\d*)x(\d*)$/', $format_part, $regs)) {
$res['max_width'] = $regs[1];
$res['max_height'] = $regs[2];
}
elseif (preg_match('/^wm:([^\|]*)\|([^\|]*)\|([^\|]*)$/', $format_part, $regs)) {
$res['wm_filename'] = FULL_PATH.THEMES_PATH.'/'.$regs[1];
$res['h_margin'] = strtolower($regs[2]);
$res['v_margin'] = strtolower($regs[3]);
}
elseif (preg_match('/^crop:([^\|]*)\|([^\|]*)$/', $format_part, $regs)) {
$res['crop_x'] = strtolower($regs[1]);
$res['crop_y'] = strtolower($regs[2]);
}
elseif ($format_part == 'img_size' || $format_part == 'img_sizes') {
$res['image_size'] = true;
}
elseif (preg_match('/^fill:(.*)$/', $format_part, $regs)) {
$res['fill'] = $regs[1];
} elseif (preg_match('/^default:(.*)$/', $format_part, $regs)) {
$res['default'] = FULL_PATH.THEMES_PATH.'/'.$regs[1];
}
}
return $res;
}
/**
* Resized given image to required dimensions & saves resized image to "resized" subfolder in source image folder
*
* @param string $src_image full path to image (on server)
* @param mixed $max_width maximal allowed resized image width or false if no limit
* @param mixed $max_height maximal allowed resized image height or false if no limit
*
* @return string direct url to resized image
* @throws RuntimeException When image doesn't exist.
*/
function ResizeImage($src_image, $max_width, $max_height = false)
{
$image_size = false;
if (is_numeric($max_width)) {
$params['max_width'] = $max_width;
$params['max_height'] = $max_height;
}
else {
$params = $this->parseFormat($max_width);
if (array_key_exists('image_size', $params)) {
// image_size param shouldn't affect resized file name (crc part)
$image_size = $params['image_size'];
unset($params['image_size']);
}
}
if ((!$src_image || !file_exists($src_image)) && array_key_exists('default', $params) && !(defined('DBG_IMAGE_RECOVERY') && DBG_IMAGE_RECOVERY)) {
$src_image = $params['default'];
}
if ( !strlen($src_image) || !file_exists($src_image) ) {
throw new RuntimeException(sprintf('Image "%s" doesn\'t exist', $src_image));
}
if ($params['max_width'] > 0 || $params['max_height'] > 0) {
list ($params['target_width'], $params['target_height'], $needs_resize) = $this->GetImageDimensions($src_image, $params['max_width'], $params['max_height'], $params);
if (!is_numeric($params['max_width'])) {
$params['max_width'] = $params['target_width'];
}
if (!is_numeric($params['max_height'])) {
$params['max_height'] = $params['target_height'];
}
$src_path = dirname($src_image);
$transform_keys = Array ('crop_x', 'crop_y', 'fill', 'wm_filename');
- if ($needs_resize || array_intersect(array_keys($params), $transform_keys)) {
- // resize required OR watermarking required -> change resulting image name !
- $src_path_escaped = preg_replace('/(\\\[\d]+)/', '\\\\\1', $src_path); // escape replacement patterns, like "\<number>"
- $dst_image = preg_replace('/^'.preg_quote($src_path, '/').'(.*)\.(.*)$/', $src_path_escaped . DIRECTORY_SEPARATOR . 'resized\\1_' . crc32(serialize($params)) . '.\\2', $src_image);
+ // Resize required OR watermarking required -> change resulting image name !
+ if ( $needs_resize || array_intersect(array_keys($params), $transform_keys) ) {
+ // Escape replacement patterns, like "\<number>".
+ $src_path_escaped = preg_replace('/(\\\[\d]+)/', '\\\\\1', $src_path);
+ $params_hash = kUtil::crc32(serialize($this->fileHelper->makeRelative($params)));
+ $dst_image = preg_replace(
+ '/^' . preg_quote($src_path, '/') . '(.*)\.(.*)$/',
+ $src_path_escaped . DIRECTORY_SEPARATOR . 'resized\\1_' . $params_hash . '.\\2',
+ $src_image
+ );
$this->fileHelper->CheckFolder( dirname($dst_image) );
if (!file_exists($dst_image) || filemtime($src_image) > filemtime($dst_image)) {
// resized image not available OR should be recreated due source image change
$params['dst_image'] = $dst_image;
$image_resized = $this->ScaleImage($src_image, $params);
if (!$image_resized) {
// resize failed, because of server error
$dst_image = $src_image;
}
}
// resize/watermarking ok
$src_image = $dst_image;
}
}
if ($image_size) {
// return only image size (resized or not)
$image_info = $this->getImageInfo($src_image);
return $image_info ? $image_info[3] : '';
}
return $this->fileHelper->pathToUrl($src_image);
}
/**
* Proportionally resizes given image to destination dimensions
*
* @param string $src_image full path to source image (already existing)
* @param Array $params
* @return bool
*/
function ScaleImage($src_image, $params)
{
$image_info = $this->getImageInfo($src_image);
if (!$image_info) {
return false;
}
/*list ($params['max_width'], $params['max_height'], $resized) = $this->GetImageDimensions($src_image, $params['max_width'], $params['max_height'], $params);
if (!$resized) {
// image dimensions are smaller or equals to required dimensions
return false;
}*/
if (!$this->Application->ConfigValue('ForceImageMagickResize') && function_exists('imagecreatefromjpeg')) {
// try to resize using GD
$resize_map = Array (
'image/jpeg' => 'imagecreatefromjpeg:imagejpeg:jpg',
'image/gif' => 'imagecreatefromgif:imagegif:gif',
'image/png' => 'imagecreatefrompng:imagepng:png',
'image/bmp' => 'imagecreatefrombmp:imagejpeg:bmp',
'image/x-ms-bmp' => 'imagecreatefrombmp:imagejpeg:bmp',
);
$mime_type = $image_info['mime'];
if (!isset($resize_map[$mime_type])) {
return false;
}
list ($read_function, $write_function, $file_extension) = explode(':', $resize_map[$mime_type]);
// when source image has large dimensions (over 1MB filesize), then 16M is not enough
kUtil::setResourceLimit();
$src_image_rs = @$read_function($src_image);
if ($src_image_rs) {
$dst_image_rs = imagecreatetruecolor($params['target_width'], $params['target_height']); // resize target size
$preserve_transparency = ($file_extension == 'gif') || ($file_extension == 'png');
if ($preserve_transparency) {
// preserve transparency of PNG and GIF images
$dst_image_rs = $this->_preserveTransparency($src_image_rs, $dst_image_rs, $image_info[2]);
}
// 1. resize
imagecopyresampled($dst_image_rs, $src_image_rs, 0, 0, 0, 0, $params['target_width'], $params['target_height'], $image_info[0], $image_info[1]);
$watermark_size = 'target';
if (array_key_exists('crop_x', $params) || array_key_exists('crop_y', $params)) {
// 2.1. crop image to given size
$dst_image_rs =& $this->_cropImage($dst_image_rs, $params, $preserve_transparency ? $image_info[2] : false);
$watermark_size = 'max';
} elseif (array_key_exists('fill', $params)) {
// 2.2. fill image margins from resize with given color
$dst_image_rs =& $this->_applyFill($dst_image_rs, $params, $preserve_transparency ? $image_info[2] : false);
$watermark_size = 'max';
}
// 3. apply watermark
$dst_image_rs =& $this->_applyWatermark($dst_image_rs, $params[$watermark_size . '_width'], $params[$watermark_size . '_height'], $params);
if ($write_function == 'imagegif') {
return @$write_function($dst_image_rs, $params['dst_image']);
}
return @$write_function($dst_image_rs, $params['dst_image'], $write_function == 'imagepng' ? 0 : 100);
}
}
else {
// try to resize using ImageMagick
// TODO: implement crop and watermarking using imagemagick
exec('/usr/bin/convert '.$src_image.' -resize '.$params['target_width'].'x'.$params['target_height'].' '.$params['dst_image'], $shell_output, $exec_status);
return $exec_status == 0;
}
return false;
}
/**
* Preserve transparency for GIF and PNG images
*
* @param resource $src_image_rs
* @param resource $dst_image_rs
* @param int $image_type
* @return resource
*/
function _preserveTransparency($src_image_rs, $dst_image_rs, $image_type)
{
$transparent_index = imagecolortransparent($src_image_rs);
// if we have a specific transparent color
if ( $transparent_index >= 0 && $transparent_index < imagecolorstotal($src_image_rs) ) {
// get the original image's transparent color's RGB values
$transparent_color = imagecolorsforindex($src_image_rs, $transparent_index);
// allocate the same color in the new image resource
$transparent_index = imagecolorallocate($dst_image_rs, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']);
// completely fill the background of the new image with allocated color
imagefill($dst_image_rs, 0, 0, $transparent_index);
// set the background color for new image to transparent
imagecolortransparent($dst_image_rs, $transparent_index);
return $dst_image_rs;
}
// always make a transparent background color for PNGs that don't have one allocated already
if ( $image_type == IMAGETYPE_PNG ) {
// turn off transparency blending (temporarily)
imagealphablending($dst_image_rs, false);
// create a new transparent color for image
$transparent_color = imagecolorallocatealpha($dst_image_rs, 0, 0, 0, 127);
// completely fill the background of the new image with allocated color
imagefill($dst_image_rs, 0, 0, $transparent_color);
// restore transparency blending
imagesavealpha($dst_image_rs, true);
}
return $dst_image_rs;
}
/**
* Fills margins (if any) of resized are with given color
*
* @param resource $src_image_rs resized image resource
* @param Array $params crop parameters
* @param int|bool $image_type
* @return resource
*/
function &_applyFill(&$src_image_rs, $params, $image_type = false)
{
$x_position = round(($params['max_width'] - $params['target_width']) / 2); // center
$y_position = round(($params['max_height'] - $params['target_height']) / 2); // center
// crop resized image
$fill_image_rs = imagecreatetruecolor($params['max_width'], $params['max_height']);
if ($image_type !== false) {
$fill_image_rs = $this->_preserveTransparency($src_image_rs, $fill_image_rs, $image_type);
}
$fill = $params['fill'];
if (substr($fill, 0, 1) == '#') {
// hexdecimal color
$color = imagecolorallocate($fill_image_rs, hexdec( substr($fill, 1, 2) ), hexdec( substr($fill, 3, 2) ), hexdec( substr($fill, 5, 2) ));
}
else {
// for now we don't support color names, but we will in future
return $src_image_rs;
}
imagefill($fill_image_rs, 0, 0, $color);
imagecopy($fill_image_rs, $src_image_rs, $x_position, $y_position, 0, 0, $params['target_width'], $params['target_height']);
return $fill_image_rs;
}
/**
* Crop given image resource using given params and return resulting image resource
*
* @param resource $src_image_rs resized image resource
* @param Array $params crop parameters
* @param int|bool $image_type
* @return resource
*/
function &_cropImage(&$src_image_rs, $params, $image_type = false)
{
if ($params['crop_x'] == 'c') {
$x_position = round(($params['max_width'] - $params['target_width']) / 2); // center
}
elseif ($params['crop_x'] >= 0) {
$x_position = $params['crop_x']; // margin from left
}
else {
$x_position = $params['target_width'] - ($params['max_width'] - $params['crop_x']); // margin from right
}
if ($params['crop_y'] == 'c') {
$y_position = round(($params['max_height'] - $params['target_height']) / 2); // center
}
elseif ($params['crop_y'] >= 0) {
$y_position = $params['crop_y']; // margin from top
}
else {
$y_position = $params['target_height'] - ($params['max_height'] - $params['crop_y']); // margin from bottom
}
// crop resized image
$crop_image_rs = imagecreatetruecolor($params['max_width'], $params['max_height']);
if ($image_type !== false) {
$crop_image_rs = $this->_preserveTransparency($src_image_rs, $crop_image_rs, $image_type);
}
if (array_key_exists('fill', $params)) {
// fill image margins from resize with given color
$crop_image_rs =& $this->_applyFill($crop_image_rs, $params, $image_type);
}
imagecopy($crop_image_rs, $src_image_rs, $x_position, $y_position, 0, 0, $params['target_width'], $params['target_height']);
return $crop_image_rs;
}
/**
* Apply watermark (transparent PNG image) to given resized image resource
*
* @param resource $src_image_rs
* @param int $max_width
* @param int $max_height
* @param Array $params
* @return resource
*/
function &_applyWatermark(&$src_image_rs, $max_width, $max_height, $params)
{
$watermark_file = array_key_exists('wm_filename', $params) ? $params['wm_filename'] : false;
if (!$watermark_file || !file_exists($watermark_file)) {
// no watermark required, or provided watermark image is missing
return $src_image_rs;
}
$watermark_img_rs = imagecreatefrompng($watermark_file);
list ($watermark_width, $watermark_height) = $this->getImageInfo($watermark_file);
imagealphablending($src_image_rs, true);
if ($params['h_margin'] == 'c') {
$x_position = round($max_width / 2 - $watermark_width / 2); // center
}
elseif ($params['h_margin'] >= 0) {
$x_position = $params['h_margin']; // margin from left
}
else {
$x_position = $max_width - ($watermark_width - $params['h_margin']); // margin from right
}
if ($params['v_margin'] == 'c') {
$y_position = round($max_height / 2 - $watermark_height / 2); // center
}
elseif ($params['v_margin'] >= 0) {
$y_position = $params['v_margin']; // margin from top
}
else {
$y_position = $max_height - ($watermark_height - $params['v_margin']); // margin from bottom
}
imagecopy($src_image_rs, $watermark_img_rs, $x_position, $y_position, 0, 0, $watermark_width, $watermark_height);
return $src_image_rs;
}
/**
* Returns destination image size without actual resizing (useful for <img .../> HTML tag)
*
* @param string $src_image full path to source image (already existing)
* @param int $dst_width destination image width (in pixels)
* @param int $dst_height destination image height (in pixels)
* @param Array $params
* @return Array resized image dimensions (0 - width, 1 - height)
*/
function GetImageDimensions($src_image, $dst_width, $dst_height, $params)
{
$image_info = $this->getImageInfo($src_image);
if (!$image_info) {
return false;
}
$orig_width = $image_info[0];
$orig_height = $image_info[1];
$too_large = is_numeric($dst_width) ? ($orig_width > $dst_width) : false;
$too_large = $too_large || (is_numeric($dst_height) ? ($orig_height > $dst_height) : false);
if ($too_large) {
$width_ratio = $dst_width ? $dst_width / $orig_width : 1;
$height_ratio = $dst_height ? $dst_height / $orig_height : 1;
if (array_key_exists('crop_x', $params) || array_key_exists('crop_y', $params)) {
// resize by smallest inverted radio
$resize_by = $this->_getCropImageMinRatio($image_info, $dst_width, $dst_height);
if ($resize_by === false) {
return Array ($orig_width, $orig_height, false);
}
$ratio = $resize_by == 'width' ? $width_ratio : $height_ratio;
}
else {
$ratio = min($width_ratio, $height_ratio);
}
$width = ceil($orig_width * $ratio);
$height = ceil($orig_height * $ratio);
}
else {
$width = $orig_width;
$height = $orig_height;
}
return Array ($width, $height, $too_large);
}
/**
* Returns ratio type with smaller relation of original size to target size
*
* @param Array $image_info image information from "ImageHelper::getImageInfo"
* @param int $dst_width destination image width (in pixels)
* @param int $dst_height destination image height (in pixels)
* @return Array
*/
function _getCropImageMinRatio($image_info, $dst_width, $dst_height)
{
$width_ratio = $dst_width ? $image_info[0] / $dst_width : 1;
$height_ratio = $dst_height ? $image_info[1] / $dst_height : 1;
$minimal_ratio = min($width_ratio, $height_ratio);
if ($minimal_ratio < 1) {
// ratio is less then 1, image will be enlarged -> don't allow that
return false;
}
return $width_ratio < $height_ratio ? 'width' : 'height';
}
/**
* Returns image dimensions + checks if given file is existing image
*
* @param string $src_image full path to source image (already existing)
* @return mixed
*/
function getImageInfo($src_image)
{
if (!file_exists($src_image)) {
return false;
}
$image_info = @getimagesize($src_image);
if (!$image_info) {
trigger_error('Image <b>'.$src_image.'</b> <span class="debug_error">missing or invalid</span>', E_USER_WARNING);
return false;
}
return $image_info;
}
/**
* Returns maximal image size (width & height) among fields specified
*
* @param kDBItem $object
* @param string $fields
* @param string $format any format, that returns full url (e.g. files_resized:WxH, resize:WxH, full_url, full_urls)
* @return string
*/
function MaxImageSize(&$object, $fields, $format = null)
{
static $cached_sizes = Array ();
$cache_key = $object->getPrefixSpecial().'_'.$object->GetID();
if (!isset($cached_sizes[$cache_key])) {
$images = Array ();
$fields = explode(',', $fields);
foreach ($fields as $field) {
$image_data = $object->GetField($field, $format);
if (!$image_data) {
continue;
}
$images = array_merge($images, explode('|', $image_data));
}
$max_width = 0;
$max_height = 0;
$base_url = rtrim($this->Application->BaseURL(), '/');
foreach ($images as $image_url) {
$image_path = preg_replace('/^'.preg_quote($base_url, '/').'(.*)/', FULL_PATH.'\\1', $image_url);
$image_info = $this->getImageInfo($image_path);
$max_width = max($max_width, $image_info[0]);
$max_height = max($max_height, $image_info[1]);
}
$cached_sizes[$cache_key] = Array ($max_width, $max_height);
}
return $cached_sizes[$cache_key];
}
/**
* Puts existing item images (from sub-item) to virtual fields (in main item)
*
* @param kCatDBItem|kDBItem $object
*/
function LoadItemImages(&$object)
{
if (!$this->_canUseImages($object)) {
return ;
}
$max_image_count = $this->Application->ConfigValue($object->Prefix.'_MaxImageCount');
$sql = 'SELECT *
FROM '.TABLE_PREFIX.'CatalogImages
WHERE ResourceId = '.$object->GetDBField('ResourceId').'
ORDER BY Priority DESC
LIMIT 0, ' . (int)$max_image_count;
$item_images = $this->Conn->Query($sql);
$image_counter = 1;
foreach ($item_images as $item_image) {
$image_path = $item_image['ThumbPath'];
if ($item_image['DefaultImg'] == 1 || $item_image['Name'] == 'main') {
// process primary image separately
if ( $object->isField('PrimaryImage') ) {
$object->SetDBField('PrimaryImage', $image_path);
$object->SetOriginalField('PrimaryImage', $image_path);
$object->SetFieldOption('PrimaryImage', 'original_field', $item_image['Name']);
$this->_loadCustomFields($object, $item_image, 0);
}
continue;
}
if (abs($item_image['Priority'])) {
// use Priority as image counter, when specified
$image_counter = abs($item_image['Priority']);
}
if ( $object->isField('Image'.$image_counter) ) {
$object->SetDBField('Image'.$image_counter, $image_path);
$object->SetOriginalField('Image'.$image_counter, $image_path);
$object->SetFieldOption('Image'.$image_counter, 'original_field', $item_image['Name']);
$this->_loadCustomFields($object, $item_image, $image_counter);
}
$image_counter++;
}
}
/**
* Saves newly uploaded images to external image table
*
* @param kCatDBItem|kDBItem $object
*/
function SaveItemImages(&$object)
{
if (!$this->_canUseImages($object)) {
return ;
}
$table_name = $this->Application->getUnitOption('img', 'TableName');
$max_image_count = $this->Application->getUnitOption($object->Prefix, 'ImageCount'); // $this->Application->ConfigValue($object->Prefix.'_MaxImageCount');
$i = 0;
while ($i < $max_image_count) {
$field = $i ? 'Image'.$i : 'PrimaryImage';
$field_options = $object->GetFieldOptions($field);
$image_src = $object->GetDBField($field);
if ($image_src) {
if (isset($field_options['original_field'])) {
$key_clause = 'Name = '.$this->Conn->qstr($field_options['original_field']).' AND ResourceId = '.$object->GetDBField('ResourceId');
if ($object->GetDBField('Delete'.$field)) {
// if item was cloned, then new filename is in db (not in $image_src)
$sql = 'SELECT ThumbPath
FROM '.$table_name.'
WHERE '.$key_clause;
$image_src = $this->Conn->GetOne($sql);
if (@unlink(FULL_PATH.$image_src)) {
$sql = 'DELETE FROM '.$table_name.'
WHERE '.$key_clause;
$this->Conn->Query($sql);
}
}
else {
// image record found -> update
$fields_hash = Array (
'ThumbPath' => $image_src,
);
$this->_saveCustomFields($object, $fields_hash, $i);
$this->Conn->doUpdate($fields_hash, $table_name, $key_clause);
}
}
else {
// image record not found -> create
$fields_hash = Array (
'ResourceId' => $object->GetDBField('ResourceId'),
'Name' => $field,
'AltName' => $field,
'Enabled' => STATUS_ACTIVE,
'DefaultImg' => $i ? 0 : 1, // first image is primary, others not primary
'ThumbPath' => $image_src,
'Priority' => ($i == 0)? 0 : $i * (-1),
);
$this->_saveCustomFields($object, $fields_hash, $i);
$this->Conn->doInsert($fields_hash, $table_name);
$field_options['original_field'] = $field;
$object->SetFieldOptions($field, $field_options);
}
}
$i++;
}
}
/**
* Adds ability to load custom fields along with main image field
*
* @param kCatDBItem|kDBItem $object
* @param Array $fields_hash
* @param int $counter 0 - primary image, other number - additional image number
*/
function _loadCustomFields(&$object, $fields_hash, $counter)
{
$field_name = $counter ? 'Image' . $counter . 'Alt' : 'PrimaryImageAlt';
$object->SetDBField($field_name, (string)$fields_hash['AltName']);
}
/**
* Adds ability to save custom field along with main image save
*
* @param kCatDBItem|kDBItem $object
* @param Array $fields_hash
* @param int $counter 0 - primary image, other number - additional image number
*/
function _saveCustomFields(&$object, &$fields_hash, $counter)
{
$field_name = $counter ? 'Image' . $counter . 'Alt' : 'PrimaryImageAlt';
$fields_hash['AltName'] = (string)$object->GetDBField($field_name);
}
/**
* Checks, that item can use image upload capabilities
*
* @param kCatDBItem|kDBItem $object
* @return bool
*/
function _canUseImages(&$object)
{
$prefix = $object->Prefix == 'p' ? 'img' : $object->Prefix . '-img';
return $this->Application->prefixRegistred($prefix);
}
}
Index: branches/5.2.x/core/units/helpers/minifiers/minify_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/minifiers/minify_helper.php (revision 16128)
+++ branches/5.2.x/core/units/helpers/minifiers/minify_helper.php (revision 16129)
@@ -1,315 +1,315 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2010 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 MinifyHelper extends kHelper {
/**
* Debug mode mark
*
* @var bool
*/
var $debugMode = false;
/**
* Folder, that contains produced CSS/JS files
*
* @var string
* @access protected
*/
protected $resourceFolder = '';
public function __construct()
{
parent::__construct();
$this->debugMode = $this->Application->isDebugMode(false);
$this->resourceFolder = WRITEABLE . '/cache';
}
/**
* When used as non-block tag, then compress given files and return url to result
*
* @param Array $params
* @return string
* @access public
*/
public function CompressScriptTag($params)
{
// put to queue
if ( array_key_exists('to', $params) ) {
$files = $this->Application->GetVar($params['to'], '');
$this->Application->SetVar($params['to'], $files . '|' . $params['files']);
return '';
}
if ( array_key_exists('from', $params) ) {
// get from queue
$files = $this->Application->GetVar($params['from']);
}
else {
// get from tag
$files = $params['files'];
}
$files = $this->_getTemplatePaths( array_map('trim', explode('|', $files)) );
if ( !$files ) {
trigger_error('No files specified for compression.', E_USER_NOTICE);
return '';
}
$extension = pathinfo($files[0], PATHINFO_EXTENSION);
$save_as = isset($params['save_as']) ? $params['save_as'] : false;
$dst_file = $this->resourceFolder . DIRECTORY_SEPARATOR . ($this->debugMode ? 'd' : 'c') . '_';
+ /** @var FileHelper $file_helper */
+ $file_helper = $this->Application->recallObject('FileHelper');
+
if ( $save_as ) {
$dst_file .= $save_as . ( strpos($save_as, '.') === false ? '.' . $extension : '' );
}
else {
- $dst_file .= $this->_getHash($files) . '.' . $extension;
+ $dst_file .= $this->_getHash($file_helper->makeRelative($files)) . '.' . $extension;
}
$was_compressed = file_exists($dst_file);
if ( !$was_compressed || ($this->debugMode && filemtime($dst_file) < $this->_getMaxFileDate($files)) ) {
$string = '';
$path_length = strlen(FULL_PATH) + 1;
foreach ($files as $file) {
if ( !file_exists($file) ) {
continue;
}
// add filename before for easier debugging
if ( $this->debugMode ) {
$string .= '/* === File: ' . substr($file, $path_length) . ' === */' . "\n";
$string .= '/* ' . str_repeat('=', strlen(substr($file, $path_length)) + 14) . ' */' . "\n\n";
}
// add file content
$string .= file_get_contents($file) . "\n\n";
}
// replace templates base
if ( isset($params['templates_base']) ) {
$templates_base = $params['templates_base'];
}
else {
$templates_base = $this->Application->ProcessParsedTag('m', 'TemplatesBase', Array ());
}
$templates_base = preg_replace('/^' . preg_quote($this->Application->BaseURL(), '/') . '/', BASE_PATH . '/', $templates_base);
$string = str_replace('@templates_base@', rtrim($templates_base, '/'), $string);
if ( !$this->debugMode ) {
// don't compress merged js/css file in debug mode to allow js/css debugging
$this->compressString($string, $extension);
}
// save compressed file
file_put_contents($dst_file, $string);
}
- $file_helper = $this->Application->recallObject('FileHelper');
- /* @var $file_helper FileHelper */
-
return $file_helper->pathToUrl($dst_file) . '?ts=' . adodb_date('Y-m-d_H:i:s', filemtime($dst_file));
}
/**
* Returns maximal modification date across given files
*
* @param Array $files
* @return int
* @access protected
*/
protected function _getMaxFileDate($files)
{
$ret = 0;
foreach ($files as $file) {
if ( file_exists($file) ) {
$ret = max($ret, filemtime($file));
}
}
return $ret;
}
/**
* Returns hash string based on given files
*
* @param Array $files
* @return int
* @access protected
*/
protected function _getHash($files)
{
$hash = $files;
if ($this->Application->isAdmin) {
array_unshift($hash, 'A:1');
}
else {
array_unshift($hash, 'A:0;T:' . $this->Application->GetVar('m_theme'));
}
- return crc32( implode('|', $hash) );
+ return kUtil::crc32(implode('|', $hash));
}
/**
* Deletes compression info file
*
* @todo also delete all listed there files
* @access public
*/
public function delete()
{
$iterator = new DirectoryIterator($this->resourceFolder);
/* @var $file_info DirectoryIterator */
foreach ($iterator as $file_info) {
if ( !$file_info->isDir() && preg_match('/^(c|d)_.*.(css|js)$/', $file_info->getFilename()) ) {
unlink( $file_info->getPathname() );
}
}
}
/**
* Compress $string based on $extension
*
* @param string $string
* @param string $extension
* @return void
* @access protected
*/
public function compressString(&$string, $extension)
{
$vars = kUtil::getConfigVars();
if ( !array_key_exists('CompressionEngine', $vars) ) {
// compression method not specified - use none
return;
}
switch ( $vars['CompressionEngine'] ) {
case 'yui':
$this->compressViaJava($string, $extension);
break;
case 'php':
$this->compressViaPHP($string, $extension);
break;
}
}
/**
* Compresses string using YUI compressor (uses Java)
*
* @param string $string
* @param string $extension
* @return void
* @access protected
*/
protected function compressViaJava(&$string, $extension)
{
$tmp_file = tempnam('/tmp', 'to_compress_');
file_put_contents($tmp_file, $string);
$command = 'java -jar ' . dirname(__FILE__) . DIRECTORY_SEPARATOR . 'yuicompressor-2.4.2.jar --type ' . $extension . ' --charset utf-8 ' . $tmp_file;
$string = shell_exec($command);
unlink($tmp_file);
}
/**
* Compresses string using PHP compressor
*
* @param string $string
* @param string $extension
* @return void
* @access protected
*/
protected function compressViaPHP(&$string, $extension)
{
$minifier = $this->Application->makeClass($extension == 'js' ? 'JsMinifyHelper' : 'CssMinifyHelper');
/* @var $minifier JsMinifyHelper */
$string = $minifier->minify($string);
}
/**
* Get full paths on disk for each of given templates
*
* @param Array $templates
* @return Array
* @access protected
*/
protected function _getTemplatePaths($templates)
{
$ret = Array ();
$reg_exp = '/^' . preg_quote($this->Application->BaseURL(), '/') . '(.*)/';
foreach ($templates as $template) {
if ( !$template ) {
continue;
}
if ( preg_match($reg_exp, $template, $regs) ) {
// full url (from current domain) to a file
$ret[] = FULL_PATH . '/' . $regs[1];
}
elseif ( strpos($template, '{module_path}') !== false ) {
$ret = array_merge($ret, $this->_moduleInclude($template));
}
else {
$ret[] = $this->Application->TemplatesCache->GetRealFilename($template);
}
}
return $ret;
}
/**
*
* @param string $template
* @return Array
* @access protected
*/
protected function _moduleInclude($template)
{
$ret = $included = Array ();
foreach ($this->Application->ModuleInfo as $module_name => $module_data) {
if ( $module_name == 'In-Portal' ) {
continue;
}
$module_prefix = $this->Application->isAdmin ? mb_strtolower($module_name) . '/' : $module_data['TemplatePath'];
if ( in_array($module_prefix, $included) ) {
continue;
}
$ret[] = $this->Application->TemplatesCache->GetRealFilename(str_replace('{module_path}', $module_prefix, $template));
$included[] = $module_prefix;
}
return $ret;
}
- }
\ No newline at end of file
+ }

Event Timeline