eZ Publish  [4.0]
ezimagemanager.php
Go to the documentation of this file.
00001 <?php
00002 //
00003 // Definition of eZImageManager class
00004 //
00005 // Created on: <01-Mar-2002 14:23:49 amos>
00006 //
00007 // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00008 // SOFTWARE NAME: eZ Publish
00009 // SOFTWARE RELEASE: 4.0.x
00010 // COPYRIGHT NOTICE: Copyright (C) 1999-2008 eZ Systems AS
00011 // SOFTWARE LICENSE: GNU General Public License v2.0
00012 // NOTICE: >
00013 //   This program is free software; you can redistribute it and/or
00014 //   modify it under the terms of version 2.0  of the GNU General
00015 //   Public License as published by the Free Software Foundation.
00016 //
00017 //   This program is distributed in the hope that it will be useful,
00018 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 //   GNU General Public License for more details.
00021 //
00022 //   You should have received a copy of version 2.0 of the GNU General
00023 //   Public License along with this program; if not, write to the Free
00024 //   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00025 //   MA 02110-1301, USA.
00026 //
00027 //
00028 // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00029 //
00030 
00031 /*! \defgroup eZImage Image conversion and scaling */
00032 
00033 /*!
00034   \class eZImageManager ezimagemanager.php
00035   \ingroup eZImage
00036   \brief Manages image operations using delegates to do the work
00037 
00038   The manager allows for transparent conversion of one image format
00039   to another. The conversion may be done in one step if the required
00040   conversion type is available or it may build a tree of conversion
00041   rules which is needed to reach the desired end format.
00042 
00043   It's also possible to run operations on images. It's up to each conversion
00044   rule to report whether or not the operation is supported, the manager will
00045   then distribute the operations on the available rules which can handle them.
00046   Examples of operations are scaling and grayscale.
00047 
00048   The scale operation is special and is known to the manager directly while
00049   the other operations must be recognized by the converter.
00050 
00051   In determing what image rules to be used the manager must first know
00052   which output types are allowed, this is set with setOutputTypes().
00053   It takes an array of mimetypes which are allowed.
00054 
00055   The manager must then be fed conversion rules, these tell which conversion
00056   type is used for converting from the source mimetype to the destination
00057   mimetype. The rules are set with setRules() which accepts an array of
00058   rules and a default rule as paremeter. The default rule is used when no
00059   other mimetype match is found.
00060   To create a rule you should use the createRule() function, it takes the source
00061   and destination mimetype as well as the conversion type name. Optionally
00062   it can specified whether the rule can scale or run operations.
00063 
00064   The last thing that needs to be done is to specify the mimetypes. The manager
00065   uses mimetypes internally to know what type of image it's working on.
00066   To go from a filename to a mimetype a set of matches must be setup. The matches
00067   are created with createMIMEType() which takes the mimetype, regex filename match
00068   and suffix as parameter. The mimetypes are then registered with setMIMETypes().
00069 
00070   See <a href="http://www.iana.org/">www.iana.org</a> for information on MIME types.
00071 
00072   Now the manager is ready and you can convert images with convert().
00073 
00074   Example:
00075 \code
00076 $img = eZImageManager::instance();
00077 $img->registerType( "convert", new eZImageShell( '', "convert", array(), array(),
00078                                                  array( eZImageShell::createRule( "-geometry %wx%h>", // Scale rule
00079                                                                                   "modify/scale" ),
00080                                                         eZImageShell::createRule( "-colorspace GRAY", // Grayscale rule
00081                                                                                   "colorspace/gray" ) ) ) ); // Register shell program convert
00082 $img->registerType( "gd", new eZImageGD() ); // Register PHP converter GD
00083 
00084 $img->setOutputTypes( array( "image/jpeg",
00085                              "image/png" ) ); // We only want jpeg and png, gif is not recommended due to licencing issues.
00086 $rules = array( $img->createRule( "image/jpeg", "image/jpeg", "GD", true, false ), // Required for scaling jpeg images
00087                 $img->createRule( "image/gif", "image/png", "convert", true, false ) ); // Convert GIF to png
00088 $img->setRules( $rules, $img->createRule( "*", "image/png", "convert", true, false ) ); // Convert all other images to PNG with convert
00089 
00090 $mime_rules = array( $img->createMIMEType( "image/jpeg", "\.jpe?g$", "jpg" ),
00091                      $img->createMIMEType( "image/png", "\.png$", "png" ),
00092                      $img->createMIMEType( "image/gif", "\.gif$", "gif" ) );
00093 $img->setMIMETypes( $mime_rules ); // Register mimetypes
00094 
00095 $img1 = $img->convert( "image1.gif", "cache/" ); // Convert GIF and places it in cache dir
00096 $img1 = $img->convert( "image1.png", "cache/", // Scale PNG image and place in cache dir
00097                        array( "width" => 200, "height" => 200 ), // Scale parameter
00098                        array( array( "rule-type" => "colorspace/gray" ) ) ); // Gray scale conversion
00099  \endcode
00100 
00101 
00102 */
00103 
00104 //include_once( 'lib/ezutils/classes/ezini.php' );
00105 
00106 class eZImageManager
00107 {
00108     /*!
00109      Initializes the manager by registering a application/octet-stream mimetype
00110      which is applied for all unknown files.
00111     */
00112     function eZImageManager()
00113     {
00114         $this->SupportedFormats = array();
00115         $this->SupportedMIMEMap = array();
00116         $this->ImageHandlers = array();
00117         $this->AliasList = array();
00118         $this->Factories = array();
00119         $this->ImageFilters = array();
00120         $this->MIMETypeSettings = array();
00121         $this->MIMETypeSettingsMap = array();
00122         $this->QualityValues = array();
00123         $this->QualityValueMap = array();
00124 
00125         $ini = eZINI::instance( 'image.ini' );
00126         $this->TemporaryImageDirPath = eZSys::cacheDirectory() . '/' . $ini->variable( 'FileSettings', 'TemporaryDir' );
00127         $this->lockTimeout = $ini->hasVariable( 'ImageConverterSettings', 'LockTimeout' ) ? $ini->variable( 'ImageConverterSettings', 'LockTimeout' ) : 60;
00128     }
00129 
00130     /*!
00131      Sets which MIME-Types are allowed to use for destination format, this is an array of MIME-Type names.
00132      e.g.
00133      \code
00134      $manager->setOutputTypes( array( 'image/jpeg', 'image/gif' ) );
00135      \endcode
00136     */
00137     function setSupportedFormats( $mimeList )
00138     {
00139         $this->SupportedFormats = $mimeList;
00140         $this->SupportedMIMEMap = array();
00141         foreach ( $mimeList as $mimeName )
00142         {
00143             $this->SupportedMIMEMap[$mimeName] = true;
00144         }
00145     }
00146 
00147     /*!
00148      Sets which MIME-Types are allowed to use for destination format, this is an array of MIME-Type names.
00149      e.g.
00150      \code
00151      $manager->setOutputTypes( array( 'image/jpeg', 'image/gif' ) );
00152      \endcode
00153     */
00154     function appendSupportedFormat( $mimeName )
00155     {
00156         $this->SupportedFormats[] = $mimeName;
00157         $this->SupportedMIMEMap[$mimeName] = true;
00158     }
00159 
00160     /*!
00161      Appends the image handler \a $handler to the list of known handlers in the image system.
00162      Onces it is added the supported image filters for that handler is extracted.
00163 
00164      \note If the handler is not available (isAvailable()) it will not be added.
00165     */
00166     function appendImageHandler( $handler )
00167     {
00168         if ( !$handler )
00169             return false;
00170         if ( !$handler->isAvailable() )
00171             return false;
00172         $this->ImageHandlers[] = $handler;
00173         $this->ImageFilters = array_merge( $this->ImageFilters, $handler->supportedImageFilters() );
00174         $this->ImageFilters = array_unique( $this->ImageFilters );
00175         return true;
00176     }
00177 
00178     /*!
00179      \return \c true if the filtername \a $filtername is supported by any of the image handlers.
00180     */
00181     function isFilterSupported( $filterName )
00182     {
00183         return in_array( $filterName, $this->ImageFilters );
00184     }
00185 
00186     /*!
00187      Returns a list of defined image aliases in the image system.
00188      Each entry in the list is an associative array with the following keys:
00189      - name - The name of the alias
00190      - reference - The name of the alias it refers to or \c false if no reference
00191      - mime_type - Controls which MIME-Type the alias will be in, or \c false if not defined.
00192      - filters - An array with filters which applies to this alias
00193      - alias_key - The CRC key for this alias, it is created from the current values of the alias
00194                    and will change each time the alias values changes
00195     */
00196     function aliasList()
00197     {
00198         $aliasList = $this->AliasList;
00199         if ( !isset( $aliasList['original'] ) )
00200         {
00201             $alias = array( 'name' => 'original',
00202                             'reference' => false,
00203                             'mime_type' => false,
00204                             'filters' => array() );
00205             $alias['alias_key'] = $this->createImageAliasKey( $alias );
00206             $aliasList['original'] = $alias;
00207         }
00208         return $aliasList;
00209     }
00210 
00211     /*!
00212      \return \c true if the image alias \a $aliasName exists.
00213     */
00214     function hasAlias( $aliasName )
00215     {
00216         $aliasList = $this->aliasList();
00217         return array_key_exists( $aliasName, $aliasList );
00218     }
00219 
00220     /*!
00221      \return the definition for the Image Alias named \a $aliasName.
00222     */
00223     function alias( $aliasName )
00224     {
00225         $aliasList = $this->aliasList();
00226         if ( !array_key_exists( $aliasName, $aliasList ) )
00227             return false;
00228         return $aliasList[$aliasName];
00229     }
00230 
00231     /*!
00232      Appends the image alias \a $alias to the list of defined aliases.
00233     */
00234     function appendImageAlias( $alias )
00235     {
00236         $key = $this->createImageAliasKey( $alias );
00237         $alias['alias_key'] = $key;
00238         $this->AliasList[$alias['name']] = $alias;
00239         return $key;
00240     }
00241 
00242     /*!
00243      Creates a unique key for the image alias and returns it.
00244      \note The key is an MD5 of the alias settings and is used to determine if alias settings has changed.
00245     */
00246     function createImageAliasKey( $alias )
00247     {
00248         $keyData = array( $alias['name'],
00249                           $alias['reference'],
00250                           $alias['mime_type'] );
00251         if ( $alias['reference'] )
00252         {
00253             $referenceAlias = $this->alias( $alias['reference'] );
00254             if ( $referenceAlias )
00255                 $keyData[] = $referenceAlias['alias_key'];
00256         }
00257         foreach ( $alias['filters'] as $filter )
00258         {
00259             $filterData = $filter['name'];
00260             if ( is_array( $filter['data'] ) )
00261                 $filterData .= '=' . implode( ',', $filter['data'] );
00262             $keyData[] = $filterData;
00263         }
00264 
00265         //include_once( 'lib/ezutils/classes/ezsys.php' );
00266         $key = eZSys::ezcrc32( implode( "\n", $keyData ) );
00267 
00268         return $key;
00269     }
00270 
00271     /*!
00272      \return \c true if the Image Alias \a $alias is valid for use.
00273              This is tested by checking the key against the key for current Image Alias settings.
00274     */
00275     function isImageAliasValid( $alias )
00276     {
00277         $aliasName = $alias['name'];
00278         if ( isset( $this->AliasList[$aliasName] ) )
00279         {
00280             $aliasKey = $alias['alias_key'];
00281             $aliasInfo = $this->AliasList[$aliasName];
00282             $checkKey = $aliasInfo['alias_key'];
00283             $isValid = ( $aliasKey == $checkKey );
00284             if ( $isValid )
00285             {
00286                 $aliasTimestamp = $alias['timestamp'];
00287                 $isValid = $this->isImageTimestampValid( $aliasTimestamp );
00288             }
00289             return $isValid;
00290         }
00291         return false;
00292     }
00293 
00294     /*!
00295      \return \c true if the timestamp \a $timestamp is newer than the image alias expiry timestamp.
00296      The image alias expiry timestamp will be set whenever the image aliases must be recreated.
00297 
00298      \note Normally the expiry timestamp is not set.
00299     */
00300     function isImageTimestampValid( $timestamp )
00301     {
00302         eZExpiryHandler::registerShutdownFunction();
00303         $expiryHandler = eZExpiryHandler::instance();
00304         if ( $expiryHandler->hasTimestamp( 'image-manager-alias' ) )
00305         {
00306             $aliasTimestamp = $expiryHandler->timestamp( 'image-manager-alias' );
00307             return ( $timestamp > $aliasTimestamp );
00308         }
00309         return true;
00310     }
00311 
00312     /*!
00313      Reads all image aliases from the INI file 'image.ini'
00314      and appends them to the image system.
00315      \param $iniFile The INI file to read from or if \c false use 'image.ini'
00316     */
00317     function readImageAliasesFromINI( $iniFile = false )
00318     {
00319         if ( !$iniFile )
00320             $iniFile = 'image.ini';
00321         $ini = eZINI::instance( $iniFile );
00322         if ( !$ini )
00323             return false;
00324         $aliasNames = $ini->variable( 'AliasSettings', 'AliasList' );
00325         foreach ( $aliasNames as $aliasName )
00326         {
00327             $alias = $this->createAliasFromINI( $aliasName );
00328             if ( $alias )
00329             {
00330                 $this->appendImageAlias( $alias );
00331             }
00332             else
00333                 eZDebug::writeWarning( "Failed reading Image Alias $aliasName from $iniFile",
00334                                        'eZImageManager::readImageAliasFromINI' );
00335         }
00336         $aliasName = 'original';
00337         if ( !in_array( $aliasName, $aliasNames ) )
00338         {
00339             //include_once( 'lib/ezutils/classes/ezini.php' );
00340             $ini = eZINI::instance( 'image.ini' );
00341             if ( $ini->hasGroup( $aliasName ) )
00342             {
00343                 $alias = $this->createAliasFromINI( $aliasName );
00344                 if ( $alias )
00345                 {
00346                     $alias['reference'] = false;
00347                     $this->appendImageAlias( $alias );
00348                 }
00349                 else
00350                 {
00351                     eZDebug::writeWarning( "Failed reading Image Alias $aliasName from $iniFile",
00352                                            'eZImageManager::readImageAliasFromINI' );
00353                 }
00354             }
00355         }
00356     }
00357 
00358     /*!
00359      Reads all supported image formats from the INI file 'image.ini'
00360      and appends them to the image system.
00361      \param $iniFile The INI file to read from or if \c false use 'image.ini'
00362     */
00363     function readSupportedFormatsFromINI( $iniFile = false )
00364     {
00365         if ( !$iniFile )
00366             $iniFile = 'image.ini';
00367         $ini = eZINI::instance( $iniFile );
00368         if ( !$ini )
00369             return false;
00370         $allowedOutputFormats = $ini->variable( 'OutputSettings', 'AllowedOutputFormat' );
00371         foreach ( $allowedOutputFormats as $allowedOutputFormat )
00372         {
00373             $this->appendSupportedFormat( $allowedOutputFormat );
00374         }
00375     }
00376 
00377     /*!
00378      \return \c true if the MIME-Type defined in \a $mimeData exists in the image system.
00379     */
00380     function hasMIMETypeSetting( $mimeData )
00381     {
00382         return isset( $this->MIMETypeSettingsMap[$mimeData['name']] );
00383     }
00384 
00385     /*!
00386      \return The setting for the MIME-Type defined in \a $mimeData.
00387     */
00388     function mimeTypeSetting( $mimeData )
00389     {
00390         if ( !isset( $this->MIMETypeSettingsMap[$mimeData['name']] ) )
00391             return false;
00392         $list = $this->MIMETypeSettingsMap[$mimeData['name']];
00393         foreach ( $list as $item )
00394         {
00395             if ( is_array( $item['match'] ) )
00396             {
00397                 if ( array_key_exists( 'info', $mimeData ) && is_array( $mimeData['info'] ) )
00398                 {
00399                     $isMatch = true;
00400                     $info = $mimeData['info'];
00401                     foreach ( $item['match'] as $matchKey => $matchValue )
00402                     {
00403                         if ( !isset( $info[$matchKey] ) or
00404                              $info[$matchKey] != $matchValue )
00405                         {
00406                             $isMatch = false;
00407                             break;
00408                         }
00409                     }
00410                     if ( $isMatch )
00411                         return $item;
00412                 }
00413             }
00414             else
00415                 return $item;
00416         }
00417         return false;
00418     }
00419 
00420     /*!
00421      Calls eZImageHandler::wildcardToRegexp() to generate
00422      a regular expression out of the wilcard and return it.
00423     */
00424     static function wildcardToRegexp( $wildcard, $separatorCharacter = false )
00425     {
00426         return eZImageHandler::wildcardToRegexp( $wildcard, $separatorCharacter );
00427     }
00428 
00429     /*!
00430      \return The override MIME-Type for the MIME structure \a $mimeData or \c false if no override.
00431     */
00432     function mimeTypeOverride( $mimeData )
00433     {
00434         if ( $this->hasMIMETypeSetting( $mimeData ) )
00435         {
00436             $settings = $this->mimeTypeSetting( $mimeData );
00437             if ( $settings )
00438             {
00439                 return $settings['override_mime_type'];
00440             }
00441         }
00442         return false;
00443     }
00444 
00445     /*!
00446      \return An array with extra filters for the MIME-Type defined in \a $mimeData
00447              or \c false if no filters.
00448     */
00449     function mimeTypeFilters( $mimeData )
00450     {
00451         if ( $this->hasMIMETypeSetting( $mimeData ) )
00452         {
00453             $settings = $this->mimeTypeSetting( $mimeData );
00454             if ( $settings )
00455             {
00456                 return $settings['extra_filters'];
00457             }
00458         }
00459         return false;
00460     }
00461 
00462     /*!
00463      \return \c true if the filtername \a $filtername is allowed to be used on the type defined in \a $mimeData.
00464     */
00465     function isFilterAllowed( $filterName, $mimeData )
00466     {
00467         if ( $this->hasMIMETypeSetting( $mimeData ) )
00468         {
00469             $settings = $this->mimeTypeSetting( $mimeData );
00470             if ( $settings )
00471             {
00472                 if ( is_array( $settings['disallowed_filters'] ) )
00473                 {
00474                     foreach ( $settings['disallowed_filters'] as $filter )
00475                     {
00476                         $regexp = eZImageManager::wildcardToRegexp( $filter );
00477                         if ( preg_match( '#' . $regexp . '#', $filterName ) )
00478                         {
00479                             return false;
00480                         }
00481                     }
00482                 }
00483                 if ( is_array( $settings['allowed_filters'] ) )
00484                 {
00485                     foreach ( $settings['allowed_filters'] as $filter )
00486                     {
00487                         $regexp = eZImageManager::wildcardToRegexp( $filter );
00488                         if ( preg_match( '#' . $regexp . '#', $filterName ) )
00489                         {
00490                             return true;
00491                         }
00492                     }
00493                     return false;
00494                 }
00495                 return true;
00496             }
00497         }
00498         return true;
00499     }
00500 
00501     /*!
00502      Binds the quality value \a $qualityValue to the MIME-Type \a $mimeType.
00503     */
00504     function appendQualityValue( $mimeType, $qualityValue )
00505     {
00506         $element = array( 'name' => $mimeType,
00507                           'value' => $qualityValue );
00508         $this->QualityValues[] = $element;
00509         $this->QualityValueMap[$mimeType] = $element;
00510     }
00511 
00512     /*!
00513      \return the quality value for MIME-Type \a $mimeType or \c false if none exists.
00514     */
00515     function qualityValue( $mimeType )
00516     {
00517         if ( isset( $this->QualityValueMap[$mimeType] ) )
00518             return $this->QualityValueMap[$mimeType]['value'];
00519         return false;
00520     }
00521 
00522     /*!
00523      Appends the MIME-Type setting \a $settings to the image system.
00524     */
00525     function appendMIMETypeSetting( $settings )
00526     {
00527         $this->MIMETypeSettings[] = $settings;
00528         if ( !isset( $this->MIMETypeSettingsMap[$settings['mime_type']] ) )
00529             $this->MIMETypeSettingsMap[$settings['mime_type']] = array();
00530         $this->MIMETypeSettingsMap[$settings['mime_type']][] = $settings;
00531     }
00532 
00533     /*!
00534      Reads all MIME-Type settings from the INI file 'image.ini'
00535      and appends them to the image system.
00536      \param $iniFile The INI file to read from or if \c false use 'image.ini'
00537     */
00538     function readMIMETypeSettingsFromINI( $iniFile = false )
00539     {
00540         if ( !$iniFile )
00541             $iniFile = 'image.ini';
00542         $ini = eZINI::instance( $iniFile );
00543         if ( !$ini )
00544             return false;
00545         $overrideList = $ini->variable( 'MIMETypeSettings', 'OverrideList' );
00546         foreach ( $overrideList as $mimeType )
00547         {
00548             $settings = eZImageManager::readMIMETypeSettingFromINI( $mimeType );
00549             if ( $settings )
00550                 $this->appendMIMETypeSetting( $settings );
00551         }
00552     }
00553 
00554     /*!
00555      Reads MIME-Type quality settings and appends them.
00556     */
00557     function readMIMETypeQualitySettingFromINI( $iniFile = false )
00558     {
00559         if ( !$iniFile )
00560             $iniFile = 'image.ini';
00561         $ini = eZINI::instance( $iniFile );
00562         if ( !$ini )
00563             return false;
00564         if ( !$ini->hasVariable( 'MIMETypeSettings', 'Quality' ) )
00565             return false;
00566         $values = $ini->variable( 'MIMETypeSettings', 'Quality' );
00567         foreach ( $values as $value )
00568         {
00569             $elements = explode( ';', $value );
00570             $mimeType = $elements[0];
00571             $qualityValue = $elements[1];
00572             $this->appendQualityValue( $mimeType, $qualityValue );
00573         }
00574     }
00575 
00576     /*!
00577      Reads in global conversion rules from INI file.
00578     */
00579     function readConversionRuleSettingsFromINI( $iniFile = false )
00580     {
00581         if ( !$iniFile )
00582             $iniFile = 'image.ini';
00583         $ini = eZINI::instance( $iniFile );
00584         if ( !$ini )
00585             return false;
00586         if ( $ini->hasVariable( 'MIMETypeSettings', 'ConversionRules' ) )
00587         {
00588             $conversionRules = array();
00589             $rules = $ini->variable( 'MIMETypeSettings', 'ConversionRules' );
00590             foreach ( $rules as $ruleString )
00591             {
00592                 $ruleItems = explode( ';', $ruleString );
00593                 if ( count( $ruleItems ) >= 2 )
00594                 {
00595                     $conversionRule = array( 'from' => $ruleItems[0],
00596                                              'to' => $ruleItems[1] );
00597                     $this->appendConversionRule( $conversionRule );
00598                 }
00599             }
00600         }
00601     }
00602 
00603     /*!
00604      Will read in all required INI settings.
00605     */
00606     function readINISettings()
00607     {
00608         $this->readImageHandlersFromINI();
00609         $this->readSupportedFormatsFromINI();
00610         $this->readImageAliasesFromINI();
00611         $this->readMIMETypeSettingsFromINI();
00612         $this->readMIMETypeQualitySettingFromINI();
00613         $this->readConversionRuleSettingsFromINI();
00614     }
00615 
00616     /*!
00617      Appends a new global conversion rule.
00618     */
00619     function appendConversionRule( $conversionRule )
00620     {
00621         $this->ConversionRules[] = $conversionRule;
00622     }
00623 
00624     /*!
00625      \return The global conversion rules.
00626     */
00627     function conversionRules()
00628     {
00629         return $this->ConversionRules;
00630     }
00631 
00632     /*!
00633      Reads a single MIME-Type setting from the INI file 'image.ini'
00634      and appends them to the image system.
00635      \param $mimeGroup Which INI group to read settings from.
00636      \param $iniFile The INI file to read from or if \c false use 'image.ini'
00637      \return The settings that were read.
00638     */
00639     function readMIMETypeSettingFromINI( $mimeGroup, $iniFile = false )
00640     {
00641         if ( !$iniFile )
00642             $iniFile = 'image.ini';
00643         $ini = eZINI::instance( $iniFile );
00644         if ( !$ini )
00645             return false;
00646         if ( !$ini->hasGroup( $mimeGroup ) )
00647             return false;
00648         if ( !$ini->hasVariable( $mimeGroup, 'MIMEType' ) )
00649             return false;
00650         $settings = array( 'name' => $mimeGroup,
00651                            'match' => false,
00652                            'mime_type' => false,
00653                            'override_mime_type' => false,
00654                            'allowed_filters' => false,
00655                            'disallowed_filters' => false,
00656                            'extra_filters' => false );
00657         $settings['mime_type'] = $ini->variable( $mimeGroup, 'MIMEType' );
00658         $ini->assign( $mimeGroup, 'Match', $settings['match'] );
00659         $ini->assign( $mimeGroup, 'OverrideMIMEType', $settings['override_mime_type'] );
00660         $ini->assign( $mimeGroup, 'AllowedFilters', $settings['allowed_filters'] );
00661         $ini->assign( $mimeGroup, 'DisallowedFilters', $settings['disallowed_filters'] );
00662         if ( $ini->hasVariable( $mimeGroup, 'ExtraFilters' ) )
00663         {
00664             $filters = array();
00665             $filterRawList = $ini->variable( $mimeGroup, 'ExtraFilters' );
00666             foreach ( $filterRawList as $filterRawItem )
00667             {
00668                 $filters[] = $this->createFilterDataFromINI( $filterRawItem );
00669             }
00670             if ( count( $filters ) > 0 )
00671                 $settings['extra_filters'] = $filters;
00672         }
00673         return $settings;
00674     }
00675 
00676     /*!
00677      Reads all settings for image handlers from the INI file 'image.ini'
00678      and appends them to the image system.
00679      \param $iniFile The INI file to read from or if \c false use 'image.ini'
00680     */
00681     function readImageHandlersFromINI( $iniFile = false )
00682     {
00683         if ( !$iniFile )
00684             $iniFile = 'image.ini';
00685         $ini = eZINI::instance( $iniFile );
00686         if ( !$ini )
00687             return false;
00688         $handlerList = $ini->variable( 'ImageConverterSettings', 'ImageConverters' );
00689         foreach ( $handlerList as $handlerName )
00690         {
00691             if ( $ini->hasGroup( $handlerName ) )
00692             {
00693                 if ( $ini->hasVariable( $handlerName, 'Handler' ) )
00694                 {
00695                     $factoryName = $ini->variable( $handlerName, 'Handler' );
00696                     $factory = $this->factoryFor( $factoryName, $iniFile );
00697                     if ( $factory )
00698                     {
00699                         $convertHandler = $factory->produceFromINI( $handlerName, $iniFile );
00700                         $this->appendImageHandler( $convertHandler );
00701                     }
00702                 }
00703                 else
00704                 {
00705                     eZDebug::writeWarning( "INI group $handlerName does not have a Handler setting, cannot instantiate handler without it",
00706                                            'eZImageManager::readImageHandlersFromINI' );
00707                 }
00708             }
00709             else
00710             {
00711                 eZDebug::writeWarning( "No INI group $handlerName for Image Handler $handlerName, cannot instantiate",
00712                                        'eZImageManager::readImageHandlersFromINI' );
00713             }
00714         }
00715     }
00716 
00717     /*!
00718      Finds the image handler factory with the name \a $factoryName and returns it.
00719      \param $iniFile The INI file to read from or if \c false use 'image.ini'
00720     */
00721     function factoryFor( $factoryName, $iniFile = false )
00722     {
00723         if ( !$iniFile )
00724             $iniFile = 'image.ini';
00725         if ( isset( $this->Factories[$factoryName] ) )
00726         {
00727             return $this->Factories[$factoryName];
00728         }
00729         else
00730         {
00731             //include_once( 'lib/ezutils/classes/ezextension.php' );
00732             if ( eZExtension::findExtensionType( array( 'ini-name' => $iniFile,
00733                                                         'repository-group' => 'ImageConverterSettings',
00734                                                         'repository-variable' => 'RepositoryList',
00735                                                         'extension-group' => 'ImageConverterSettings',
00736                                                         'extension-variable' => 'ExtensionList',
00737                                                         'extension-subdir' => 'imagehandler',
00738                                                         'alias-group' => 'ImageConverterSettings',
00739                                                         'alias-variable' => 'ImageHandlerAlias',
00740                                                         'suffix-name' => 'handler.php',
00741                                                         'type-directory' => false,
00742                                                         'type' => $factoryName ),
00743                                                  $result ) )
00744             {
00745                 $filepath = $result['found-file-path'];
00746                 include_once( $filepath );
00747                 $className = $result['type'] . 'factory';
00748                 include_once( $result['found-file-dir'] . '/' . $className . '.php' );
00749                 if ( class_exists( $className ) )
00750                 {
00751                     return $this->Factories[$factoryName] = new $className();
00752                 }
00753                 else
00754                 {
00755                     eZDebug::writeWarning( "The Image Factory class $className was not found, cannot create factory",
00756                                            'eZImageManager::factoryFor' );
00757                 }
00758             }
00759             else
00760             {
00761                 eZDebug::writeWarning( "Could not locate Image Factory for $factoryName",
00762                                        'eZImageManager::factoryFor' );
00763             }
00764         }
00765         return false;
00766     }
00767 
00768     /*!
00769      Parses the filter text \a $filterText which is taken from an INI file
00770      and returns a filter data structure for it.
00771     */
00772     function createFilterDataFromINI( $filterText )
00773     {
00774         $equalPosition = strpos( $filterText, '=' );
00775         $filterData = false;
00776         if ( $equalPosition !== false )
00777         {
00778             $filterName = substr( $filterText, 0, $equalPosition );
00779             $filterDataText = substr( $filterText, $equalPosition + 1 );
00780             $filterData = explode( ';', $filterDataText );
00781         }
00782         else
00783             $filterName = $filterText;
00784         return array( 'name' => $filterName,
00785                       'data' => $filterData );
00786     }
00787 
00788     /*!
00789      Parses the INI group \a $iniGroup and creates an Image Alias from it.
00790      \return the Image Alias structure.
00791     */
00792     function createAliasFromINI( $iniGroup )
00793     {
00794         //include_once( 'lib/ezutils/classes/ezini.php' );
00795         $ini = eZINI::instance( 'image.ini' );
00796         if ( !$ini->hasGroup( $iniGroup ) )
00797         {
00798             eZDebug::writeError( "No such group $iniGroup in ini file image.ini",
00799                                  'eZImageManager::createAliasFromINI' );
00800             return false;
00801         }
00802         $alias = array( 'name' => $iniGroup,
00803                         'reference' => false,
00804                         'mime_type' => false,
00805                         'filters' => array() );
00806         if ( $ini->hasVariable( $iniGroup, 'Name' ) )
00807             $alias['name'] = $ini->variable( $iniGroup, 'Name' );
00808         if ( $ini->hasVariable( $iniGroup, 'MIMEType' ) )
00809             $alias['mime_type'] = $ini->variable( $iniGroup, 'MIMEType' );
00810         if ( $ini->hasVariable( $iniGroup, 'Filters' ) )
00811         {
00812             $filters = array();
00813             $filterRawList = $ini->variable( $iniGroup, 'Filters' );
00814             foreach ( $filterRawList as $filterRawItem )
00815             {
00816                 $filters[] = $this->createFilterDataFromINI( $filterRawItem );
00817             }
00818             $alias['filters'] = $filters;
00819         }
00820         if ( $ini->hasVariable( $iniGroup, 'Reference' ) )
00821             $alias['reference'] = $ini->variable( $iniGroup, 'Reference' );
00822         return $alias;
00823     }
00824 
00825     /*!
00826      Makes sure the Image Alias \a $aliasName is created. It will check if referenced
00827      image aliases exists and if not create those also.
00828      \return \c true if successful
00829     */
00830     function createImageAlias( $aliasName, &$existingAliasList, $parameters = array() )
00831     {
00832         //eZDebug::writeDebug( $existingAliasList, 'eZImageManager::createImageAlias existing alias list' );
00833         $aliasList = $this->aliasList();
00834         if ( !isset( $aliasList[$aliasName] ) )
00835         {
00836             eZDebug::writeWarning( "Alias name $aliasName does not exist, cannot create it" );
00837             return false;
00838         }
00839         $currentAliasInfo = $aliasList[$aliasName];
00840         $referenceAlias = $currentAliasInfo['reference'];
00841         if ( $referenceAlias and !$this->hasAlias( $referenceAlias ) )
00842         {
00843             eZDebug::writeError( "The referenced alias '$referenceAlias' for image alias '$aliasName' does not exist, cannot use it for reference.\n" .
00844                                  "Will use 'original' alias instead.",
00845                                  'eZImageManager::createImageAlias' );
00846             $referenceAlias = false;
00847         }
00848         if ( !$referenceAlias )
00849             $referenceAlias = 'original';
00850         $hasReference = false;
00851         if ( array_key_exists( $referenceAlias, $existingAliasList ) )
00852         {
00853             require_once( 'kernel/classes/ezclusterfilehandler.php' );
00854             $fileHandler = eZClusterFileHandler::instance();
00855             if ( $fileHandler->fileExists( $existingAliasList[$referenceAlias]['url'] ) )
00856             {
00857                 $hasReference = true;
00858             }
00859             else
00860             {
00861                 eZDebug::writeDebug( 'cluster file handler could not find ' . $existingAliasList[$referenceAlias]['url'], 'eZImageManager::createImageAlias' );
00862                 eZDebug::writeError( "The reference alias $referenceAlias file " . $existingAliasList[$referenceAlias]['url'] . " does not exist",
00863                                      'eZImageManager::createImageAlias' );
00864             }
00865         }
00866         if ( !$hasReference )
00867         {
00868             if ( $referenceAlias == 'original' )
00869             {
00870                 eZDebug::writeError( "Original alias does not exists, cannot create other aliases without it" );
00871                 return false;
00872             }
00873             if ( !$this->createImageAlias( $referenceAlias, $existingAliasList, $parameters ) )
00874             {
00875                 eZDebug::writeError( "Failed creating the referenced alias $referenceAlias, cannot create alias $aliasName",
00876                                      'eZImageManager::createImageAlias' );
00877                 return false;
00878             }
00879         }
00880         if ( array_key_exists( $referenceAlias, $existingAliasList ) )
00881         {
00882             $aliasInfo = $existingAliasList[$referenceAlias];
00883             $aliasFilePath = $aliasInfo['url'];
00884             $aliasKey = $currentAliasInfo['alias_key'];
00885 
00886             $aliasFile = eZClusterFileHandler::instance( $aliasFilePath );
00887 
00888             if ( $aliasFile->exists() )
00889             {
00890                 $aliasFile->fetch();
00891                 //include_once( 'lib/ezutils/classes/ezmimetype.php' );
00892                 $sourceMimeData = eZMimeType::findByFileContents( $aliasFilePath );
00893                 $destinationMimeData = $sourceMimeData;
00894                 if ( isset( $parameters['basename'] ) )
00895                 {
00896                     $sourceMimeData['basename'] = $parameters['basename'];
00897                     eZMimeType::changeBasename( $destinationMimeData, $parameters['basename'] );
00898                 }
00899 
00900                 if ( !$this->_exclusiveLock( $aliasFilePath, $aliasName ) )
00901                 {
00902                     return false;
00903                 }
00904 
00905                 $wantImage = $this->imageAliasInfo( $sourceMimeData, $aliasName );
00906                 $wantImagePath = $wantImage['url'];
00907 
00908                 $fileHandler = eZClusterFileHandler::instance( $wantImagePath );
00909                 $fileHandler->loadMetaData( true );
00910 
00911                 if ( $fileHandler->exists() and $this->isImageTimestampValid( $fileHandler->mtime() ) )
00912                 {
00913                     $destinationMimeData = $wantImage;
00914                     $wasLocked = true;
00915                 }
00916                 else
00917                 {
00918                     $destinationMimeData['is_valid'] = false;
00919                     if ( !$this->convert( $sourceMimeData, $destinationMimeData, $aliasName, $parameters ) )
00920                     {
00921                         $sourceFile = $sourceMimeData['url'];
00922                         $destinationDir = $destinationMimeData['dirpath'];
00923                         eZDebug::writeError( "Failed converting $sourceFile to alias '$aliasName' in directory '$destinationDir'",
00924                                              'eZImageManager::createImageAlias' );
00925                         $aliasFile->deleteLocal();
00926                         return false;
00927                     }
00928                 }
00929 
00930                 $currentAliasData = array( 'url' => $destinationMimeData['url'],
00931                                            'dirpath' => $destinationMimeData['dirpath'],
00932                                            'filename' => $destinationMimeData['filename'],
00933                                            'suffix' => $destinationMimeData['suffix'],
00934                                            'basename' => $destinationMimeData['basename'],
00935                                            'alternative_text' => $aliasInfo['alternative_text'],
00936                                            'name' => $aliasName,
00937                                            'sub_type' => false,
00938                                            'timestamp' => time(),
00939                                            'alias_key' => $aliasKey,
00940                                            'mime_type' => $destinationMimeData['name'],
00941                                            'override_mime_type' => false,
00942                                            'info' => false,
00943                                            'width' => false,
00944                                            'height' => false,
00945                                            'is_valid' => true,
00946                                            'is_new' => true );
00947                 if ( isset( $destinationMimeData['override_mime_type'] ) )
00948                     $currentAliasData['override_mime_type'] = $destinationMimeData['override_mime_type'];
00949                 if ( isset( $destinationMimeData['info'] ) )
00950                     $currentAliasData['info'] = $destinationMimeData['info'];
00951                 $currentAliasData['full_path'] =& $currentAliasData['url'];
00952                 if ( function_exists( 'getimagesize' ) )
00953                 {
00954                     $fileHandler = eZClusterFileHandler::instance();
00955                     $fileHandler->fileFetch( $destinationMimeData['url'] );
00956 
00957                     if ( file_exists( $destinationMimeData['url'] ) )
00958                     {
00959                         $info = getimagesize( $destinationMimeData['url'] );
00960                         if ( $info )
00961                         {
00962                             $width = $info[0];
00963                             $height = $info[1];
00964                             $currentAliasData['width'] = $width;
00965                             $currentAliasData['height'] = $height;
00966                         }
00967                         else
00968                         {
00969                             eZDebug::writeError("The size of the generated image " . $destinationMimeData['url'] . " could not be read by getimagesize()", 'eZImageManager::createImageAlias' );
00970                         }
00971 
00972                         // The file is not written to the database if it was already written due to a lock situation
00973                         if ( !isset( $wasLocked ) )
00974                         {
00975                             $fileHandler = eZClusterFileHandler::instance( $aliasFilePath );
00976                             $fileHandler->fileStore( $destinationMimeData['url'], 'image', true, $destinationMimeData['name'] );
00977                         }
00978                     }
00979                     else
00980                     {
00981                         eZDebug::writeError( "The destination image " . $destinationMimeData['url'] . " does not exist, cannot figure out image size", 'eZImageManager::createImageAlias' );
00982                     }
00983                 }
00984                 else
00985                     eZDebug::writeError( "Unknown function 'getimagesize' cannot get image size", 'eZImageManager::createImageAlias' );
00986                 $existingAliasList[$aliasName] = $currentAliasData;
00987                 $aliasFile->deleteLocal();
00988 
00989                 $this->_freeExclusiveLock( $aliasFilePath, $aliasName );
00990 
00991                 return true;
00992             }
00993         }
00994         return false;
00995     }
00996 
00997     /*!
00998      \static
00999      Analyzes the image in the MIME structure \a $mimeData and fills in extra information if found.
01000      \return \c true if the image was succesfully analyzed, \c false otherwise.
01001      \note It will return \c true if there is no analyzer for the image type.
01002     */
01003     static function analyzeImage( &$mimeData, $parameters = array() )
01004     {
01005         $file = $mimeData['url'];
01006 
01007         if ( !file_exists( $file ) )
01008             return false;
01009         $analyzer = eZImageAnalyzer::createForMIME( $mimeData );
01010         $status = true;
01011         if ( is_object( $analyzer ) )
01012         {
01013             $imageInformation = $analyzer->process( $mimeData, $parameters );
01014             if ( $imageInformation )
01015             {
01016                 $mimeData['info'] = $imageInformation;
01017             }
01018             else
01019                 $status = false;
01020         }
01021         return $status;
01022     }
01023 
01024     /*!
01025      Converts the source image \a $sourceMimeData into the destination image \a $destinationMimeData.
01026      The source image can be supplied with the full path to the image instead of the MIME structure.
01027      The destination image can be supplied with full path or dirpath to the destination image instead of the MIME structure.
01028      \param $aliasName determines the Image Alias to use for conversion, this usually adds some filters to the conversion.
01029     */
01030     function convert( $sourceMimeData, &$destinationMimeData, $aliasName = false, $parameters = array() )
01031     {
01032         require_once( 'kernel/classes/ezclusterfilehandler.php' );
01033         $sourceFile = eZClusterFileHandler::instance( $sourceMimeData['url'] );
01034         $sourceFile->fetch();
01035 
01036         //include_once( 'lib/ezutils/classes/ezmimetype.php' );
01037         if ( is_string( $sourceMimeData ) )
01038             $sourceMimeData = eZMimeType::findByFileContents( $sourceMimeData );
01039 
01040         $this->analyzeImage( $sourceMimeData );
01041         $currentMimeData = $sourceMimeData;
01042         $handlers = $this->ImageHandlers;
01043         $supportedMIMEMap = $this->SupportedMIMEMap;
01044         if ( is_string( $destinationMimeData ) )
01045         {
01046             $destinationPath = $destinationMimeData;
01047             $destinationMimeData = eZMimeType::findByFileContents( $destinationPath );
01048         }
01049 
01050         $filters = array();
01051         $alias = false;
01052         if ( $aliasName )
01053         {
01054             $aliasList = $this->aliasList();
01055             if ( isset( $aliasList[$aliasName] ) )
01056             {
01057                 $alias = $aliasList[$aliasName];
01058                 $filters = $alias['filters'];
01059                 if ( $alias['mime_type'] )
01060                 {
01061                     eZMimeType::changeMIMEType( $destinationMimeData, $alias['mime_type'] );
01062                 }
01063             }
01064         }
01065         $mimeTypeOverride = $this->mimeTypeOverride( $sourceMimeData );
01066         if ( $mimeTypeOverride )
01067             $alias['override_mime_type'] = $mimeTypeOverride;
01068 
01069         if ( isset( $parameters['filters'] ) )
01070         {
01071             $filters = array_merge( $filters, $parameters['filters'] );
01072         }
01073 
01074         $wantedFilters = $filters;
01075         $mimeTypeFilters = $this->mimeTypeFilters( $sourceMimeData );
01076         if ( is_array( $mimeTypeFilters ) )
01077             $wantedFilters = array_merge( $wantedFilters, $mimeTypeFilters );
01078         $filters = array();
01079         foreach ( array_keys( $wantedFilters ) as $wantedFilterKey )
01080         {
01081             $wantedFilter = $wantedFilters[$wantedFilterKey];
01082             if ( !$this->isFilterSupported( $wantedFilter['name'] ) )
01083             {
01084                 eZDebug::writeWarning( "The filter '" . $wantedFilter['name'] . "' is not supported by any of the image handlers, will ignore this filter",
01085                                        'eZImageManager::convert' );
01086                 continue;
01087             }
01088             $filters[] = $wantedFilter;
01089         }
01090         if ( !$destinationMimeData['is_valid'] )
01091         {
01092             $destinationDirPath = $destinationMimeData['dirpath'];
01093             $destinationBasename = $destinationMimeData['basename'];
01094             if ( isset( $supportedMIMEMap[$sourceMimeData['name']] ) )
01095             {
01096                 $destinationMimeData = $sourceMimeData;
01097                 if ( $alias['mime_type'] )
01098                 {
01099                     eZMimeType::changeMIMEType( $destinationMimeData, $alias['mime_type'] );
01100                 }
01101                 eZMimeType::changeFileData( $destinationMimeData, $destinationDirPath, $destinationBasename );
01102             }
01103             else
01104             {
01105                 $hasDestination = false;
01106                 foreach ( $handlers as $handler )
01107                 {
01108                     $gotMimeData = true;
01109                     while( $gotMimeData )
01110                     {
01111                         $gotMimeData = false;
01112                         $outputMimeData = $handler->outputMIMEType( $this, $sourceMimeData, false, $this->SupportedFormats, $aliasName );
01113                         if ( $outputMimeData and
01114                              isset( $supportedMIMEMap[$outputMimeData['name']] ) )
01115                         {
01116                             $destinationMimeData = $outputMimeData;
01117                             eZMimeType::changeFileData( $destinationMimeData, $destinationDirPath, $destinationBasename );
01118                             $hasDestination = true;
01119                             $gotMimeData = true;
01120                             break;
01121                         }
01122                     }
01123                 }
01124                 if ( !$hasDestination )
01125                 {
01126                     $sourceFile->deleteLocal();
01127                     return false;
01128                 }
01129             }
01130         }
01131 
01132         $wantedFilters = $filters;
01133         $filters = array();
01134         foreach ( array_keys( $wantedFilters ) as $wantedFilterKey )
01135         {
01136             $wantedFilter = $wantedFilters[$wantedFilterKey];
01137             if ( !$this->isFilterAllowed( $wantedFilter['name'], $destinationMimeData ) )
01138             {
01139                 continue;
01140             }
01141             $filters[] = $wantedFilter;
01142         }
01143         $result = true;
01144         $tempFiles = array();
01145         if ( $currentMimeData['name'] != $destinationMimeData['name'] or
01146              count( $filters ) > 0 )
01147         {
01148             while ( $currentMimeData['name'] != $destinationMimeData['name'] or
01149                     count( $filters ) > 0 )
01150             {
01151                 $nextMimeData = false;
01152                 $nextHandler = false;
01153                 foreach ( $handlers as $handler )
01154                 {
01155                     if ( !$handler )
01156                         continue;
01157                     $outputMimeData = $handler->outputMIMEType( $this, $currentMimeData, $destinationMimeData, $this->SupportedFormats, $aliasName );
01158                     if ( $outputMimeData['name'] == $destinationMimeData['name'] )
01159                     {
01160                         $nextMimeData = $outputMimeData;
01161                         $nextHandler = $handler;
01162                         break;
01163                     }
01164                     if ( $outputMimeData and
01165                          !$nextMimeData )
01166                     {
01167                         $nextMimeData = $outputMimeData;
01168                         $nextHandler = $handler;
01169                     }
01170                 }
01171                 if ( !$nextMimeData )
01172                 {
01173                     eZDebug::writeError( "None of the handlers can convert MIME-Type " . $currentMimeData['name'],
01174                                          'eZImageManager::convert' );
01175                     $sourceFile->deleteLocal();
01176                     return false;
01177                 }
01178                 $handlerFilters = array();
01179                 $leftoverFilters = array();
01180                 foreach ( $filters as $filter )
01181                 {
01182                     if ( $nextHandler->isFilterSupported( $filter ) )
01183                         $handlerFilters[] = $filter;
01184                     else
01185                         $leftoverFilters[] = $filter;
01186                 }
01187                 $useTempImage = false;
01188                 if ( $nextMimeData['name'] == $destinationMimeData['name'] and
01189                      count( $leftoverFilters ) == 0 )
01190                 {
01191                     $nextMimeData['dirpath'] = $destinationMimeData['dirpath'];
01192                 }
01193                 else
01194                 {
01195                     $useTempImage = true;
01196                     $nextMimeData['dirpath'] = $this->temporaryImageDirPath();
01197                 }
01198                 eZMimeType::changeDirectoryPath( $nextMimeData, $nextMimeData['dirpath'] );
01199 
01200                 if ( $nextMimeData['dirpath'] and
01201                      !file_exists( $nextMimeData['dirpath'] ) )
01202                     eZDir::mkdir( $nextMimeData['dirpath'], false, true );
01203                 if ( $currentMimeData['name'] == $nextMimeData['name'] and
01204                      count( $handlerFilters ) == 0 )
01205                 {
01206                     if ( $currentMimeData['url'] != $nextMimeData['url'] )
01207                     {
01208                         //include_once( 'lib/ezfile/classes/ezfilehandler.php' );
01209                         if ( eZFileHandler::copy( $currentMimeData['url'], $nextMimeData['url'] ) )
01210                         {
01211                             if ( $useTempImage )
01212                                 $tempFiles[] = $nextMimeData['url'];
01213                         }
01214                         else
01215                         {
01216                             $result = false;
01217                             break;
01218                         }
01219                     }
01220                     $currentMimeData = $nextMimeData;
01221                 }
01222                 else
01223                 {
01224                     if ( $nextHandler->convert( $this, $currentMimeData, $nextMimeData, $handlerFilters ) )
01225                     {
01226                         if ( $useTempImage )
01227                             $tempFiles[] = $nextMimeData['url'];
01228                     }
01229                     else
01230                     {
01231                         $result = false;
01232                         break;
01233                     }
01234                     $currentMimeData = $nextMimeData;
01235                 }
01236                 $filters = $leftoverFilters;
01237             }
01238         }
01239         else
01240         {
01241             $useCopy = false;
01242             if ( $aliasName and
01243                  $aliasName != 'original' )
01244             {
01245                 $destinationMimeData['filename'] = $destinationMimeData['basename'] . '_' . $aliasName . '.' . $destinationMimeData['suffix'];
01246                 if ( $destinationMimeData['dirpath'] )
01247                     $destinationMimeData['url'] = $destinationMimeData['dirpath'] . '/' . $destinationMimeData['filename'];
01248                 else
01249                     $destinationMimeData['url'] = $destinationMimeData['filename'];
01250             }
01251             if ( $sourceMimeData['url'] != $destinationMimeData['url'] )
01252             {
01253                 //include_once( 'lib/ezfile/classes/ezfilehandler.php' );
01254                 if ( $useCopy )
01255                 {
01256                     eZFileHandler::copy( $sourceMimeData['url'], $destinationMimeData['url'] );
01257                 }
01258                 else
01259                 {
01260                     eZFileHandler::linkCopy( $sourceMimeData['url'], $destinationMimeData['url'], false );
01261                 }
01262                 $currentMimeData = $destinationMimeData;
01263             }
01264         }
01265         foreach ( $tempFiles as $tempFile )
01266         {
01267             if ( !@unlink( $tempFile ) )
01268             {
01269                 eZDebug::writeError( "Failed to unlink temporary image file $tempFile",
01270                                      'eZImageManager::convert' );
01271             }
01272         }
01273         $destinationMimeData = $currentMimeData;
01274 
01275         if ( $aliasName && $aliasName != 'original' )
01276         {
01277             if ( $result )
01278             {
01279                 $destinationFilePath = $destinationMimeData['url'];
01280                 require_once( 'kernel/classes/ezclusterfilehandler.php' );
01281                 $fileHandler = eZClusterFileHandler::instance();
01282                 $fileHandler->fileStore( $destinationFilePath, 'image', true, $destinationMimeData['name'] );
01283             }
01284 
01285             $sourceFile->deleteLocal();
01286         }
01287 
01288         return $result;
01289     }
01290 
01291     /**
01292      * Image information for $aliasName. This is the information which normally
01293      * would be provided during generation of aliasName. This so that requests
01294      * not holding the lock will provide meaningful information.
01295      *
01296      * @param mixed $mimeData
01297      * @param string $aliasName
01298      * @return mixed
01299      */
01300     function imageAliasInfo( $mimeData, $aliasName )
01301     {
01302         if ( is_string( $mimeData ) )
01303             $mimeData = eZMimeType::findByFileContents( $mimeData );
01304 
01305         $this->analyzeImage( $mimeData );
01306         if ( $aliasName )
01307         {
01308             $aliasList = $this->aliasList();
01309             if ( isset( $aliasList[$aliasName] ) )
01310             {
01311                 $alias = $aliasList[$aliasName];
01312                 if ( $alias['mime_type'] )
01313                 {
01314                     eZMimeType::changeMIMEType( $mimeData, $alias['mime_type'] );
01315                 }
01316             }
01317         }
01318         if ( $aliasName != 'original' )
01319         {
01320             $mimeData['filename'] = $mimeData['basename'] . '_' . $aliasName . '.' . $mimeData['suffix'];
01321             $mimeData['url'] = $mimeData['dirpath'] . '/' . $mimeData['filename'];
01322         }
01323         // eZDebug::writeDebug( $mimeData, 'return from eZImageManager::imageAliasInfo' );
01324         return $mimeData;
01325     }
01326 
01327     /*!
01328      \return the path for temporary images.
01329      \note The default value uses the temporary directory setting from site.ini.
01330     */
01331     function temporaryImageDirPath()
01332     {
01333         return $this->TemporaryImageDirPath;
01334     }
01335 
01336     /*!
01337      Returns the only instance of the image manager.
01338     */
01339     static function instance()
01340     {
01341         if ( !isset( $GLOBALS["eZImageManager"] ) )
01342         {
01343             $GLOBALS["eZImageManager"] = new eZImageManager();
01344         }
01345         return $GLOBALS["eZImageManager"];
01346     }
01347 
01348     /*!
01349      Acquires an exclusive lock for the currently generated alias
01350     */
01351     private function _exclusiveLock( $fileName, $aliasName )
01352     {
01353         // mutex w/ exclusive lock: convert(targetFileName)
01354         $mutex = $this->_mutex( "{$fileName}-{$aliasName}" );
01355         while( true )
01356         {
01357             $timestamp  = $mutex->lockTS(); // Note: This does not lock, only checks what the timestamp is.
01358             if ( $timestamp === false )
01359             {
01360                 if ( !$mutex->lock() )
01361                 {
01362                     eZDebug::writeWarning( "Failed to acquire lock for file $fileName/$aliasName" );
01363                     return false;
01364                 }
01365                 $mutex->setMeta( 'pid', getmypid() );
01366                 return true;
01367             }
01368             if ( $timestamp >= time() - $this->lockTimeout )
01369             {
01370                 sleep( 1 ); // Sleep 1 second
01371                 continue;
01372             }
01373 
01374             $oldPid = $mutex->meta( 'pid' );
01375             if ( is_numeric( $oldPid ) &&
01376                  $oldPid != 0 &&
01377                  function_exists( 'posix_kill' ) )
01378             {
01379                 posix_kill( $oldPid, 9 );
01380             }
01381             if ( !$mutex->steal() )
01382             {
01383                 eZDebug::writeWarning( "Failed to steal lock for file $fileName/$aliasName from PID $oldPid" );
01384                 return false;
01385             }
01386             $mutex->setMeta( 'pid', getmypid() );
01387             return true;
01388         } // while
01389     }
01390 
01391     /*!
01392      Frees the current exclusive lock in use.
01393 
01394      \param $fname Name of the calling code (usually function name).
01395      */
01396     private function _freeExclusiveLock( $fileName, $aliasName )
01397     {
01398         $this->_mutex( "{$fileName}-{$aliasName}" )->unlock();
01399     }
01400 
01401     /*!
01402      Returns the mutex object for the current file.
01403      */
01404     private function _mutex( $fname = false )
01405     {
01406         if ( $this->Mutex !== null )
01407         {
01408             return $this->Mutex;
01409         }
01410         $this->Mutex = new eZMutex( $fname );
01411         return $this->Mutex;
01412     }
01413 
01414     /// \privatesection
01415     public $ImageHandlers;
01416     public $OutputMIME;
01417     public $OutputMIMEMap;
01418     public $Rules;
01419     public $DefaultRule;
01420     public $RuleMap;
01421     public $MIMETypes;
01422     public $Types = array();
01423 
01424     /**
01425      * Holds the mutex for image alias file.
01426      *
01427      * @var eZMutex
01428      */
01429     private $Mutex;
01430 
01431     /**
01432      * The time spent waiting before an existing eZMutex lock is cancelled and reused.
01433      * Default value is 60 seconds, which is set in constructor.
01434      *
01435      * @var int
01436      */
01437     private $lockTimeout;
01438 
01439 }
01440 
01441 ?>