Page MenuHomeIn-Portal Phabricator

image_event_handler.php
No OneTemporary

File Metadata

Created
Sun, Sep 28, 12:44 AM

image_event_handler.php

<?php
/**
* @version $Id: image_event_handler.php 12960 2009-12-20 13:11:53Z alex $
* @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 ImageEventHandler extends kDBEventHandler {
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnCleanImages' => Array ('subitem' => true),
'OnCleanResizedImages' => Array ('subitem' => true),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
function mapEvents()
{
parent::mapEvents(); // ensure auto-adding of approve/decine and so on events
$image_events = Array(
'OnAfterCopyToTemp'=>'ImageAction',
'OnBeforeDeleteFromLive'=>'ImageAction',
'OnBeforeCopyToLive'=>'ImageAction',
'OnBeforeItemDelete'=>'ImageAction',
'OnAfterClone'=>'ImageAction',
);
$this->eventMethods = array_merge($this->eventMethods, $image_events);
}
/**
* Get's special of main item for linking with subitem
*
* @param kEvent $event
* @return string
*/
function getMainSpecial(&$event)
{
if ($event->Special == 'list' && !$this->Application->isAdmin) {
// ListImages aggregated tag uses this special
return '';
}
return parent::getMainSpecial($event);
}
function customProcessing(&$event, $type)
{
$object =& $event->GetObject();
switch ($type)
{
case 'before' :
if ($object->GetDBField('LocalImage'))
{
$object->SetDBField('Url', '');
}
else
{
$object->SetDBField('LocalPath', '');
}
if ($object->GetDBField('LocalThumb'))
{
$object->SetDBField('ThumbUrl', '');
}
else
{
$object->SetDBField('ThumbPath', '');
}
if ($object->GetDBField('SameImages'))
{
$object->SetDBField('LocalImage', 1);
$object->SetDBField('LocalPath', '');
$object->SetDBField('Url', '');
}
break;
case 'after' :
if ($object->GetDBField('DefaultImg') )
{
$sql = 'UPDATE '.$object->TableName.' SET DefaultImg=0 WHERE ResourceId='.
$object->GetDBField('ResourceId').' AND ImageId<>'.
$object->GetId();
$res = $this->Conn->Query($sql);
}
break;
default:
}
}
function ImageAction(&$event)
{
$id = $event->getEventParam('id');
$object =& $this->Application->recallObject($event->Prefix.'.-item', $event->Prefix, Array ('skip_autoload' => true));
if (in_array($event->Name, Array('OnBeforeDeleteFromLive','OnAfterClone')) ) {
$object->SwitchToLive();
}
elseif ($event->Name == 'OnBeforeItemDelete') {
// keep current table
}
else {
$object->SwitchToTemp();
}
$object->Load($id);
$fields = Array('LocalPath' => 'LocalImage', 'ThumbPath' => 'LocalThumb');
foreach ($fields as $a_field => $mode_field) {
$file = $object->GetField($a_field);
if (!$file) continue;
$source_file = FULL_PATH.$file;
switch ($event->Name) {
// Copy image files to pending dir and update corresponding fields in temp record
// Checking for existing files and renaming if nessessary - two users may upload same pending files at the same time!
case 'OnAfterCopyToTemp':
$new_file = IMAGES_PENDING_PATH . $this->ValidateFileName(FULL_PATH.IMAGES_PENDING_PATH, basename($file));
$dest_file = FULL_PATH.$new_file;
copy($source_file, $dest_file);
$object->Fields[$a_field]['skip_empty'] = false;
$object->SetDBField($a_field, $new_file);
break;
// Copy image files to live dir (checking if fileexists and renameing if nessessary)
// and update corresponding fields in temp record (which gets copied to live automatically)
case 'OnBeforeCopyToLive':
if ( $object->GetDBField($mode_field) ) { // if image is local
// rename file if it exists in live folder
$new_file = IMAGES_PATH . $this->ValidateFileName(FULL_PATH.IMAGES_PATH, basename($file));
$dest_file = FULL_PATH.$new_file;
rename($source_file, $dest_file);
}
else { // if image is remote url - remove local file (if any), update local file field with empty value
if (file_exists($source_file)) @unlink($source_file);
$new_file = '';
}
$object->Fields[$a_field]['skip_empty'] = false;
$object->SetDBField($a_field, $new_file);
break;
case 'OnBeforeDeleteFromLive': // Delete image files from live folder before copying over from temp
case 'OnBeforeItemDelete': // Delete image files when deleteing Image object
@unlink(FULL_PATH.$file);
break;
case 'OnAfterClone': // Copy files when cloning objects, renaming it on the fly
$path_info = pathinfo($file);
$new_file = $path_info['dirname'].'/'.$this->ValidateFileName(FULL_PATH.$path_info['dirname'], $path_info['basename']);
$dest_file = FULL_PATH . $new_file;
copy($source_file, $dest_file);
$object->Fields[$a_field]['skip_empty'] = false;
$object->SetDBField($a_field, $new_file);
break;
}
}
if ( in_array($event->Name, Array('OnAfterClone', 'OnBeforeCopyToLive', 'OnAfterCopyToTemp')) ) {
$object->Update(null, true);
}
}
function ValidateFileName($path, $name)
{
$parts = pathinfo($name);
$ext = '.'.$parts['extension'];
$filename = mb_substr($parts['basename'], 0, -mb_strlen($ext));
$new_name = $filename.$ext;
while ( file_exists($path.'/'.$new_name) )
{
if ( preg_match('/('.preg_quote($filename, '/').'_)([0-9]*)('.preg_quote($ext, '/').')/', $new_name, $regs) ) {
$new_name = $regs[1].($regs[2]+1).$regs[3];
}
else {
$new_name = $filename.'_1'.$ext;
}
}
return $new_name;
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnSetPrimary(&$event)
{
$object =& $event->getObject();
$object->SetDBField('DefaultImg', 1);
$object->Update();
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnBeforeItemUpdate(&$event)
{
$object =& $event->getObject();
// $parent_info = $object->getLinkedInfo();
$id = $object->GetDBField('ResourceId');
// $id = $parent_info['ParentId'] ? $parent_info['ParentId'] : $this->Application->GetVar('p_id');
$sql = 'SELECT ImageId FROM '.$object->TableName.' WHERE ResourceId='.$id.' AND DefaultImg=1';
if(!$this->Conn->GetOne($sql))
{
$object->SetDBField('DefaultImg', 1);
}
if($object->GetDBField('DefaultImg') && $object->Validate())
{
$sql = 'UPDATE '.$object->TableName.'
SET DefaultImg = 0
WHERE ResourceId = '.$id.' AND ImageId <> '.$object->GetDBField('ImageId');
$this->Conn->Query($sql);
$object->SetDBField('Enabled', 1);
}
}
function OnAfterItemCreate(&$event)
{
$event->CallSubEvent('OnBeforeItemUpdate');
$object =& $event->getObject();
$object->Update();
}
/**
* Deletes all selected items.
* Automatically recurse into sub-items using temp handler, and deletes sub-items
* by calling its Delete method if sub-item has AutoDelete set to true in its config file
*
* @param kEvent $event
*/
function OnMassDelete(&$event)
{
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
$event->status = erFAIL;
return;
}
$event->status=erSUCCESS;
$temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
$event->setEventParam('ids', $this->StoreSelectedIDs($event) );
$this->customProcessing($event, 'before');
$ids = $event->getEventParam('ids');
$object =& $event->getObject();
$sql = 'SELECT ImageId FROM '.$object->TableName.' WHERE DefaultImg=1';
$primary = $this->Conn->GetOne($sql);
if( $primary && ($key = array_search($primary, $ids)) )
{
$sql = 'SELECT ImageId FROM '.$object->TableName.' WHERE DefaultImg=0';
$res = $this->Conn->Query($sql);
if($res)
{
unset($ids[$key]);
}
}
if($ids)
{
$temp->DeleteItems($event->Prefix, $event->Special, $ids);
}
$this->clearSelectedIDs($event);
}
/*function OnAfterItemLoad(&$event)
{
$object =& $event->getObject();
if ( $object->GetDBField('ThumbPath') || $object->GetDBField('SameImages') )
{
// return local image or url
$path = $object->GetDBField('LocalThumb') ? PROTOCOL.SERVER_NAME.BASE_PATH.$object->GetDBField('ThumbPath') : $object->GetDBField('ThumbUrl');
if ( $object->GetDBField('LocalThumb') && !file_exists(FULL_PATH.$object->GetDBField('ThumbPath')) ) $path = '';
}
else { // if we need full which is not the same as thumb
$path = $object->GetDBField('LocalImage') ? PROTOCOL.SERVER_NAME.BASE_PATH.$object->GetDBField('LocalPath') : $object->GetDBField('Url');
if ( $object->GetDBField('LocalImage') && !file_exists(FULL_PATH.$object->GetDBField('LocalPath')) ) $path = '';
}
$object->SetDBField('ImageUrl', $path);
}*/
function SetCustomQuery(&$event)
{
parent::SetCustomQuery($event);
$types=$event->getEventParam('types');
$except_types=$event->getEventParam('except');
$object =& $event->getObject();
$type_clauses = Array();
if (!$this->Application->isAdminUser) {
$object->addFilter('active', '%1$s.Enabled = 1');
}
if($product_id = $event->getEventParam('product_id'))
{
$object->removeFilter('parent_filter');
$sql = 'SELECT ResourceId FROM '.$this->Application->getUnitOption('p', 'TableName').'
WHERE ProductId = '.$product_id;
$resource_id = (int) $this->Conn->GetOne($sql);
$object->addFilter('product_images', '%1$s.ResourceId = '.$resource_id);
}
$type_clauses['additional']['include'] = '%1$s.DefaultImg != 1';
$type_clauses['additional']['except'] = '%1$s.DefaultImg = 1';
$type_clauses['additional']['having_filter'] = false;
/********************************************/
$includes_or_filter =& $this->Application->makeClass('kMultipleFilter');
$includes_or_filter->setType(FLT_TYPE_OR);
$excepts_and_filter =& $this->Application->makeClass('kMultipleFilter');
$excepts_and_filter->setType(FLT_TYPE_AND);
$includes_or_filter_h =& $this->Application->makeClass('kMultipleFilter');
$includes_or_filter_h->setType(FLT_TYPE_OR);
$excepts_and_filter_h =& $this->Application->makeClass('kMultipleFilter');
$excepts_and_filter_h->setType(FLT_TYPE_AND);
$except_types_array=explode(',', $types);
if ($types){
$types_array=explode(',', $types);
for ($i=0; $i<sizeof($types_array); $i++){
$type=trim($types_array[$i]);
if (isset($type_clauses[$type])){
if ($type_clauses[$type]['having_filter']){
$includes_or_filter_h->removeFilter('filter_'.$type);
$includes_or_filter_h->addFilter('filter_'.$type, $type_clauses[$type]['include']);
}else{
$includes_or_filter->removeFilter('filter_'.$type);
$includes_or_filter->addFilter('filter_'.$type, $type_clauses[$type]['include']);
}
}
}
}
if ($except_types){
$except_types_array=explode(',', $except_types);
for ($i=0; $i<sizeof($except_types_array); $i++){
$type=trim($except_types_array[$i]);
if (isset($type_clauses[$type])){
if ($type_clauses[$type]['having_filter']){
$excepts_and_filter_h->removeFilter('filter_'.$type);
$excepts_and_filter_h->addFilter('filter_'.$type, $type_clauses[$type]['except']);
}else{
$excepts_and_filter->removeFilter('filter_'.$type);
$excepts_and_filter->addFilter('filter_'.$type, $type_clauses[$type]['except']);
}
}
}
}
$object->addFilter('includes_filter', $includes_or_filter);
$object->addFilter('excepts_filter', $excepts_and_filter);
$object->addFilter('includes_filter_h', $includes_or_filter_h, HAVING_FILTER);
$object->addFilter('excepts_filter_h', $excepts_and_filter_h, HAVING_FILTER);
}
/**
* [AGENT] Remove unused images from "/system/images" and "/system/images/pending" folders
*
* @param kEvent $event
*/
function OnCleanImages(&$event)
{
// 1. get images, that are currently in use
$active_images = $this->_getActiveImages( $this->Application->getUnitOption('img', 'TableName') );
$active_images[] = 'noimage.gif';
// 2. get images on disk
$this->_deleteUnusedImages(FULL_PATH . IMAGES_PATH, $active_images);
// 3. get images in use from "images/pending" folder
$active_images = $this->_getPendingImages();
// 4. get image on disk
$this->_deleteUnusedImages(FULL_PATH . IMAGES_PENDING_PATH, $active_images);
}
/**
* Gets image filenames (no path) from given table
*
* @param string $image_table
* @return Array
*/
function _getActiveImages($image_table)
{
$sql = 'SELECT LocalPath, ThumbPath
FROM ' . $image_table . '
WHERE COALESCE(LocalPath, "") <> "" OR COALESCE(ThumbPath) <> ""';
$images = $this->Conn->Query($sql);
$active_images = Array ();
foreach ($images as $image) {
if ($image['LocalPath']) {
$active_images[] = basename($image['LocalPath']);
}
if ($image['ThumbPath']) {
$active_images[] = basename($image['ThumbPath']);
}
}
return $active_images;
}
/**
* Gets active images, that are currently beeing edited inside temporary tables
*
* @return Array
*/
function _getPendingImages()
{
$tables = $this->Conn->GetCol('SHOW TABLES');
$mask_edit_table = '/'.TABLE_PREFIX.'ses_(.*)_edit_' . TABLE_PREFIX . 'Images/';
$active_images = Array ();
foreach ($tables as $table) {
if (!preg_match($mask_edit_table, $table)) {
continue;
}
$active_images = array_unique( array_merge($active_images, $this->_getActiveImages($table)) );
}
return $active_images;
}
/**
* Deletes all files in given path, except of given $active_images
*
* @param string $path
* @param Array $active_images
*/
function _deleteUnusedImages($path, &$active_images)
{
$images = glob($path . '*.*');
if ($images) {
$images = array_map('basename', $images);
// delete images, that are on disk, but are not mentioned in Images table
$delete_images = array_diff($images, $active_images);
foreach ($delete_images as $delete_image) {
unlink($path . $delete_image);
}
}
}
/**
* [AGENT] Remove all images from "/system/images/resized" and "/system/images/pending/resized" folders
*
* @param kEvent $event
*/
function OnCleanResizedImages(&$event)
{
$images = glob(FULL_PATH . IMAGES_PATH . 'resized/*.*');
if ($images) {
foreach ($images as $image) {
unlink($image);
}
}
$images = glob(FULL_PATH . IMAGES_PENDING_PATH . 'resized/*.*');
if ($images) {
foreach ($images as $image) {
unlink($image);
}
}
}
}

Event Timeline