eZ Publish  [4.0]
ezimagealiashandler.php
Go to the documentation of this file.
00001 <?php
00002 //
00003 // Definition of eZImageAliasHandler class
00004 //
00005 // Created on: <16-Oct-2003 09:34:25 bf>
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 /*!
00032   \class eZImageAliasHandler ezimagealiashandler.php
00033   \ingroup eZDatatype
00034   \brief Internal manager for the eZImage datatype
00035 
00036   Takes care of image conversion and serialization from and to
00037   the internal XML format.
00038 
00039   \note This handler was introduced in eZ Publish 3.3 and will detect older
00040         eZImage structures and convert them on the fly.
00041 
00042   \note The XML storage was improved in 3.8, from then it always stores the
00043         attribute ID, version and language in the <original> tag.
00044         This was required to get the new multi-language features to work.
00045 */
00046 
00047 //include_once( 'lib/ezdb/classes/ezdb.php' );
00048 //include_once( 'lib/ezfile/classes/ezfilehandler.php' );
00049 //include_once( "kernel/classes/datatypes/ezimage/ezimagefile.php" );
00050 
00051 class eZImageAliasHandler
00052 {
00053     /*!
00054      Creates the handler and creates a reference to the contentobject attribute that created it.
00055     */
00056     function eZImageAliasHandler( $contentObjectAttribute )
00057     {
00058         $this->ContentObjectAttributeData = array();
00059         if ( is_object( $contentObjectAttribute ) )
00060         {
00061             $this->ContentObjectAttributeData['id'] = $contentObjectAttribute->attribute( 'id' );
00062             $this->ContentObjectAttributeData['contentobject_id'] = $contentObjectAttribute->attribute( 'contentobject_id' );
00063             $this->ContentObjectAttributeData['version'] = $contentObjectAttribute->attribute( 'version' );
00064             $this->ContentObjectAttributeData['language_code'] = $contentObjectAttribute->attribute( 'language_code' );
00065             $this->ContentObjectAttributeData['can_translate'] = $contentObjectAttribute->attribute( 'can_translate' );
00066             $this->ContentObjectAttributeData['data_text'] = $contentObjectAttribute->attribute( 'data_text' );
00067             $this->ContentObjectAttributeData['DataTypeCustom'] = $contentObjectAttribute->DataTypeCustom;
00068             if ( !is_array( $this->ContentObjectAttributeData['DataTypeCustom'] ) )
00069             {
00070                 $this->ContentObjectAttributeData['DataTypeCustom'] = array();
00071             }
00072         }
00073         else
00074         {
00075             eZDebug::writeWarning( 'Invalid eZContentObjectAttribute', 'eZImageAliasHandler::eZImageAliasHandler' );
00076         }
00077     }
00078 
00079     /*!
00080      Lists all available image aliases as attributes as well as:
00081      - alternative_text - The alternative text input by the user, can be empty
00082      - original_filename - The name of image which it had on the users disk before it was uploaded
00083      - is_valid - A boolean which says if there is an image here or not.
00084     */
00085     function attributes()
00086     {
00087         require_once( 'kernel/common/image.php' );
00088         $imageManager = imageInit();
00089         $aliasList = $imageManager->aliasList();
00090         return array_merge( array( 'alternative_text',
00091                                    'original_filename',
00092                                    'is_valid' ),
00093                             array_keys( $aliasList ) );
00094     }
00095 
00096     /*!
00097      \return true if the attribute named \a $attributeName exists.
00098      See eZImageAliasHandler::attributes() for which attributes are available.
00099     */
00100     function hasAttribute( $attributeName )
00101     {
00102         if ( in_array( $attributeName,
00103                        array( 'alternative_text',
00104                               'original_filename',
00105                               'is_valid' ) ) )
00106             return true;
00107         require_once( 'kernel/common/image.php' );
00108         $imageManager = imageInit();
00109         if ( $imageManager->hasAlias( $attributeName ) )
00110             return true;
00111         return false;
00112     }
00113 
00114     /*!
00115      \return the value of the attribute named \a $attributeName.
00116      See eZImageAliasHandler::attributes() for which attributes are available.
00117     */
00118     function attribute( $attributeName )
00119     {
00120         if ( in_array( $attributeName,
00121                        array( 'alternative_text',
00122                               'original_filename',
00123                               'is_valid' ) ) )
00124         {
00125             return $this->attributeFromOriginal( $attributeName );
00126         }
00127         $aliasName = $attributeName;
00128         return $this->imageAlias( $aliasName );
00129     }
00130 
00131     /*!
00132      \return The value of the attribute named \a $attributeName from the 'original' image alias.
00133 
00134      This is a quick way for extracting information from the 'original' image alias.
00135     */
00136     function &attributeFromOriginal( $attributeName )
00137     {
00138         $originalAlias = $this->attribute( 'original' );
00139         if ( $originalAlias )
00140             return $originalAlias[$attributeName];
00141         $retValue = null;
00142         return $retValue;
00143     }
00144 
00145     /*!
00146      Sets the attribute named \a $attributeName to have the value \a $attributeValue.
00147 
00148      The following attributes can be set:
00149      - alternative text
00150      - original_filename
00151     */
00152     function setAttribute( $attributeName, $attributeValue )
00153     {
00154         if ( in_array( $attributeName,
00155                        array( 'alternative_text',
00156                               'original_filename' ) ) )
00157         {
00158             $aliasList = $this->aliasList();
00159             foreach ( array_keys( $aliasList ) as $aliasName )
00160             {
00161                 $this->setAliasAttribute( $aliasName, $attributeName, $attributeValue );
00162             }
00163             if ( $attributeName == 'alternative_text' )
00164             {
00165                 $text = $this->displayText( $attributeValue );
00166                 foreach ( array_keys( $aliasList ) as $aliasName )
00167                 {
00168                     $this->setAliasAttribute( $aliasName, 'text', $text );
00169                 }
00170             }
00171             $this->recreateDOMTree();
00172             $this->setStorageRequired();
00173             return true;
00174         }
00175         return false;
00176     }
00177 
00178     /*!
00179      \return \c true if this is considered to be owner of the image.
00180 
00181      It will be considered an owner if attribute data is not a copy
00182      of another attribute. For instance each time a new image is uploaded
00183      this will return \c true.
00184     */
00185     function isImageOwner()
00186     {
00187         $originalData = $this->originalAttributeData();
00188         return ( $originalData['attribute_id'] == false ||
00189                  ( $originalData['attribute_id'] == $this->ContentObjectAttributeData['id'] &&
00190                    $originalData['attribute_version'] == $this->ContentObjectAttributeData['version'] &&
00191                    $originalData['attribute_language'] == $this->ContentObjectAttributeData['language_code'] ) );
00192     }
00193 
00194     /*!
00195      \return The current serial number, the value will be 1 or higher.
00196 
00197      The serial number is used to create unique filenames for uploaded images,
00198      it will be increased each time an image is uploaded.
00199 
00200 
00201      \note This was required to get around the problem where browsers
00202            caches image information, if two images were uploaded in one version (e.g. a draft)
00203            the browser would not load the new image since it thought it had not changed.
00204     */
00205     function imageSerialNumber()
00206     {
00207         $serialNumber = $this->imageSerialNumberRaw();
00208         if ( $serialNumber < 1 )
00209         {
00210             $serialNumber = 1;
00211         }
00212         return $serialNumber;
00213     }
00214 
00215     /*!
00216      Increases the serial by one.
00217     */
00218     function increaseImageSerialNumber()
00219     {
00220         $this->setImageSerialNumber( $this->imageSerialNumberRaw() + 1 );
00221     }
00222 
00223     /*!
00224      Resets the serial number to zero.
00225     */
00226     function resetImageSerialNumber()
00227     {
00228         $this->setImageSerialNumber( 0 );
00229     }
00230 
00231     /*!
00232      \return A text string which can be used as display for the image.
00233 
00234      The text string will either contain the alternative text from the attribute
00235      or the parameter \a $alternativeText if it is set.
00236     */
00237     function displayText( $alternativeText = null )
00238     {
00239         if ( $alternativeText === null )
00240             $text = $this->attribute( 'alternative_text' );
00241         else
00242             $text = $alternativeText;
00243 
00244         return $text;
00245     }
00246 
00247     /*!
00248      \return The full directory path to the image, this includes the var and storage directory.
00249     */
00250     function directoryPath()
00251     {
00252         $aliasList = $this->aliasList();
00253         if ( isset( $aliasList['original'] ) )
00254         {
00255             return $aliasList['original']['dirpath'];
00256         }
00257         return false;
00258     }
00259 
00260     /*!
00261      \return A normalized name for the image.
00262 
00263      The image name will generated from the name of the current version.
00264      If this is empty it will use the object name or the alternative text.
00265 
00266      This ensures that the image has a name which corresponds to the object it belongs to.
00267 
00268      The normalization ensures that the name only contains filename and URL friendly characters.
00269     */
00270     function imageName( $contentObjectAttribute, $contentVersion, $language = false )
00271     {
00272         if ( $language === false )
00273         {
00274             if ( is_object( $contentObjectAttribute ) ) // for backward compatibility when eZImageAliasHandler used $this->contentObjectAttribute
00275             {
00276                 $language = $contentObjectAttribute->attribute( 'language_code' );
00277             }
00278             else
00279             {
00280                 $language = $contentObjectAttribute['language_code'];
00281             }
00282         }
00283         $objectName = $contentVersion->versionName( $language );
00284         if ( !$objectName )
00285         {
00286             $objectName = $contentVersion->name( $language );
00287             if ( !$objectName )
00288             {
00289                 $objectName = $this->attribute( 'alternative_text' );
00290                 if ( !$objectName )
00291                 {
00292                     $objectName = ezi18n( 'kernel/classes/datatypes', 'image', 'Default image name' );
00293                 }
00294             }
00295         }
00296         $objectName = eZImageAliasHandler::normalizeImageName( $objectName );
00297         $objectName .= $this->imageSerialNumber();
00298 
00299         return $objectName;
00300     }
00301 
00302     /*!
00303      \return A normalized name for the image based on a node.
00304 
00305      Similar to \a imageName() but fetches name information from the node \a $mainNode.
00306 
00307      The normalization ensures that the name only contains filename and URL friendly characters.
00308     */
00309     function imageNameByNode( $contentObjectAttribute, $mainNode, $language = false )
00310     {
00311         if ( $language === false )
00312         {
00313             if ( is_object( $contentObjectAttribute ) ) // for backward compatibility when eZImageAliasHandler used $this->contentObjectAttribute
00314             {
00315                 $language = $contentObjectAttribute->attribute( 'language_code' );
00316             }
00317             else
00318             {
00319                 $language = $contentObjectAttribute['language_code'];
00320             }
00321         }
00322         $objectName = $mainNode->getName( $language );
00323         if ( !$objectName )
00324         {
00325             $objectName = $this->attribute( 'alternative_text' );
00326             if ( !$objectName )
00327             {
00328                 $objectName = ezi18n( 'kernel/classes/datatypes', 'image', 'Default image name' );
00329             }
00330         }
00331         $objectName = eZImageAliasHandler::normalizeImageName( $objectName );
00332         return $objectName;
00333     }
00334 
00335     /*!
00336      \return The storage path for the image.
00337 
00338      The path is calculated by using information from the current object and version.
00339      If the object is in the node tree it will contain a path that matches the node path,
00340      if not it will be placed in the versioned storage repository.
00341     */
00342     function imagePath( $contentObjectAttribute, $contentVersion, $isImageOwner = null )
00343     {
00344         $useVersion = false;
00345         if ( $isImageOwner === null )
00346             $isImageOwner = $this->isImageOwner();
00347         if ( $contentVersion->attribute( 'status' ) == eZContentObjectVersion::STATUS_PUBLISHED or
00348              !$isImageOwner )
00349         {
00350             $contentObject = $contentVersion->attribute( 'contentobject' );
00351             $mainNode = $contentObject->attribute( 'main_node' );
00352             if ( !$mainNode )
00353             {
00354                 $ini = eZINI::instance( 'image.ini' );
00355                 $contentImageSubtree = $ini->variable( 'FileSettings', 'VersionedImages' );
00356                 $pathString = $contentImageSubtree;
00357                 $useVersion = true;
00358             }
00359             else
00360             {
00361                 $ini = eZINI::instance( 'image.ini' );
00362                 $contentImageSubtree = $ini->variable( 'FileSettings', 'PublishedImages' );
00363                 $pathString = $mainNode->pathWithNames();
00364                 $pathString = function_exists( 'mb_strtolower' ) ? mb_strtolower( $pathString ) : strtolower( $pathString );
00365                 $pathString = $contentImageSubtree . '/' . $pathString;
00366             }
00367         }
00368         else
00369         {
00370             $ini = eZINI::instance( 'image.ini' );
00371             $contentImageSubtree = $ini->variable( 'FileSettings', 'VersionedImages' );
00372             $pathString = $contentImageSubtree;
00373             $useVersion = true;
00374         }
00375         $attributeData = $this->originalAttributeData();
00376         $attributeID = $attributeData['attribute_id'];
00377         $attributeVersion = $attributeData['attribute_version'];
00378         $attributeLanguage = $attributeData['attribute_language'];
00379         if ( $useVersion )
00380             $identifierString = $attributeID . '/' . $attributeVersion . '-' . $attributeLanguage;
00381         else
00382             $identifierString = $attributeID . '-' . $attributeVersion . '-' . $attributeLanguage;
00383         $imagePath = eZSys::storageDirectory() . '/' . $pathString . '/' . $identifierString;
00384         return $imagePath;
00385     }
00386 
00387     /*!
00388      \return The storage path for the image based on a node.
00389 
00390      Similar to \a imagePath() but fetches name information from the node \a $mainNode.
00391     */
00392     function imagePathByNode( $contentObjectAttribute, $mainNode )
00393     {
00394         $pathString = $mainNode->pathWithNames();
00395         $pathString = function_exists( 'mb_strtolower' ) ? mb_strtolower( $pathString ) : strtolower( $pathString );
00396 
00397         $ini = eZINI::instance( 'image.ini' );
00398         $contentImageSubtree = $ini->variable( 'FileSettings', 'PublishedImages' );
00399         $attributeData = $this->originalAttributeData();
00400         $attributeID = $attributeData['attribute_id'];
00401         $attributeVersion = $attributeData['attribute_version'];
00402         $attributeLanguage = $attributeData['attribute_language'];
00403         $pathParts = array( eZSys::storageDirectory(), $contentImageSubtree );
00404         if ( $pathString != '' )
00405         {
00406             $pathParts[] = $pathString;
00407         }
00408         $pathParts[] = $attributeID . '-' . $attributeVersion . '-' . $attributeLanguage;
00409         $imagePath = implode( '/', $pathParts );
00410         return $imagePath;
00411     }
00412 
00413     /*!
00414      \return The image alias structure for the alias named \a $aliasName.
00415 
00416      This will create the image alias if it does not exist yet, this can involve
00417      running image operations to for instance scale the image.
00418     */
00419     function imageAlias( $aliasName )
00420     {
00421         require_once( 'kernel/common/image.php' );
00422         $imageManager = imageInit();
00423         if ( !$imageManager->hasAlias( $aliasName ) )
00424         {
00425             return null;
00426         }
00427 
00428         $aliasList = $this->aliasList();
00429         if ( array_key_exists( $aliasName, $aliasList ) )
00430         {
00431             return $aliasList[$aliasName];
00432         }
00433         else
00434         {
00435             $imageManager = imageInit();
00436             if ( $imageManager->hasAlias( $aliasName ) )
00437             {
00438                 $original = $aliasList['original'];
00439                 $basename = $original['basename'];
00440                 if ( $imageManager->createImageAlias( $aliasName, $aliasList,
00441                                                       array( 'basename' => $basename ) ) )
00442                 {
00443                     $text = $this->displayText( $original['alternative_text'] );
00444                     $originalFilename = $original['original_filename'];
00445                     foreach ( $aliasList as $aliasKey => $alias )
00446                     {
00447                         $alias['original_filename'] = $originalFilename;
00448                         $alias['text'] = $text;
00449                         if ( $alias['url'] )
00450                         {
00451                             require_once( 'kernel/classes/ezclusterfilehandler.php' );
00452                             $aliasFile = eZClusterFileHandler::instance( $alias['url'] );
00453                             if( $aliasFile->exists() )
00454                                 $alias['filesize'] = $aliasFile->size();
00455                         }
00456                         if ( $alias['is_new'] )
00457                         {
00458                             eZImageFile::appendFilepath( $this->ContentObjectAttributeData['id'], $alias['url'] );
00459                         }
00460                         $aliasList[$aliasKey] = $alias;
00461                     }
00462                     $this->setAliasList( $aliasList );
00463                     $this->addImageAliases( $aliasList );
00464                     $aliasList = $this->aliasList();
00465                     return $aliasList[$aliasName];
00466                 }
00467             }
00468         }
00469 
00470         return null;
00471     }
00472 
00473     /*!
00474      Set alias list. Set alias list to current object
00475 
00476      \param alias list
00477     */
00478     protected function setAliasList( $aliasList )
00479     {
00480         $this->ContentObjectAttributeData['DataTypeCustom']['alias_list'] = $aliasList;
00481     }
00482 
00483     /*
00484      Set alias variation
00485 
00486      \param alias name
00487      \param variation array
00488     */
00489     protected function setAliasVariation( $aliasName, $variation )
00490     {
00491         $this->ContentObjectAttributeData['DataTypeCustom']['alias_list'][$aliasName] = $variation;
00492     }
00493 
00494     /*!
00495      Set alias value.
00496 
00497      \param alias name
00498      \param attribute name
00499      \param attribute value
00500     */
00501     protected function setAliasAttribute( $aliasName, $attributeName, $value )
00502     {
00503         $this->ContentObjectAttributeData['DataTypeCustom']['alias_list'][$aliasName][$attributeName] = $value;
00504     }
00505 
00506     /*!
00507      \private
00508      \return A list of aliases structures for the current attribute.ezxml
00509 
00510      The first this is called the XML data will be parsed into the internal
00511      structures. Subsequent calls will simply return the internal structure.
00512     */
00513     function aliasList()
00514     {
00515         if ( isset( $this->ContentObjectAttributeData['DataTypeCustom']['alias_list'] ) )
00516         {
00517             return $this->ContentObjectAttributeData['DataTypeCustom']['alias_list'];
00518         }
00519 
00520         eZDebug::accumulatorStart('imageparse', 'XML', 'Image XML parsing' );
00521 
00522         $domTree = new DOMDocument( '1.0', 'utf-8' );
00523 
00524         $xmlString = $this->ContentObjectAttributeData['data_text'];
00525 
00526         $success = false;
00527         if ( $xmlString != '' )
00528         {
00529             $success = $domTree->loadXML( $xmlString );
00530         }
00531 
00532         if ( !$success )
00533         {
00534             $this->generateXMLData();
00535             $xmlString = $this->ContentObjectAttributeData['data_text'];
00536             $success = $domTree->loadXML( $xmlString );
00537         }
00538 
00539         $this->ContentObjectAttributeData['DataTypeCustom']['dom_tree'] = $domTree;
00540         $imageNodeArray = $domTree->getElementsByTagName( "ezimage" );
00541 
00542         $aliasList = array();
00543 
00544         // I think this is a bug in the plain package or related to the bug I filed
00545         // about the image datatype serialization
00546         // http://ez.no/bugs/view/8821 ezpm Error: (eZFileHandler::copy) Unable to open source file in read mode
00547         if ( $imageNodeArray->length == 0 )
00548         {
00549             return $aliasList;
00550         }
00551 
00552         $imageNode = $imageNodeArray->item( 0 );
00553 
00554         $imageInfoNodeArray = $imageNode->getElementsByTagName( "information" );
00555         $imageVariationNodeArray = $imageNode->getElementsByTagName( "alias" );
00556         $imageOriginalArray = $imageNode->getElementsByTagName( "original" );
00557 
00558         $aliasEntry = array();
00559 
00560         $alternativeText = $imageNode->getAttribute( 'alternative_text' );
00561         $originalFilename = $imageNode->getAttribute( 'original_filename' );
00562         $basename = $imageNode->getAttribute( 'basename' );
00563         $displayText = $this->displayText( $alternativeText );
00564 
00565         $originalData = array( 'attribute_id' => '',
00566                                'attribute_version' => '',
00567                                'attribute_language' => '' );
00568         if ( $imageOriginalArray->length > 0 )
00569         {
00570             $imageOriginalNode = $imageOriginalArray->item( 0 );
00571             $originalData = array( 'attribute_id' => $imageOriginalNode->getAttribute( 'attribute_id' ),
00572                                    'attribute_version' => $imageOriginalNode->getAttribute( 'attribute_version' ),
00573                                    'attribute_language' => $imageOriginalNode->getAttribute( 'attribute_language' ) );
00574         }
00575         if ( strlen( $originalData['attribute_id'] ) == 0 ||
00576              strlen( $originalData['attribute_version'] ) == 0 ||
00577              strlen( $originalData['attribute_language'] ) == 0 )
00578         {
00579             $originalData = array( 'attribute_id' => $this->ContentObjectAttributeData['id'],
00580                                    'attribute_version' => $this->ContentObjectAttributeData['version'],
00581                                    'attribute_language' => $this->ContentObjectAttributeData['language_code'] );
00582         }
00583         $this->setOriginalAttributeData( $originalData );
00584 
00585         $aliasEntry['name'] = 'original';
00586         $aliasEntry['width'] = $imageNode->getAttribute( 'width' );
00587         $aliasEntry['height'] = $imageNode->getAttribute( 'height' );
00588         $aliasEntry['mime_type'] = $imageNode->getAttribute( 'mime_type' );
00589         $aliasEntry['filename'] = $imageNode->getAttribute( 'filename' );
00590         $aliasEntry['suffix'] = $imageNode->getAttribute( 'suffix' );
00591         $aliasEntry['dirpath'] = $imageNode->getAttribute( 'dirpath' );
00592         $aliasEntry['basename'] = $basename;
00593         $aliasEntry['alternative_text'] = $alternativeText;
00594         $aliasEntry['text'] = $displayText;
00595         $aliasEntry['original_filename'] = $originalFilename;
00596         $aliasEntry['url'] = $imageNode->getAttribute( 'url' );
00597         $aliasEntry['alias_key'] = $imageNode->getAttribute( 'alias_key' );
00598         $aliasEntry['timestamp'] = $imageNode->getAttribute( 'timestamp' );
00599         $aliasEntry['full_path'] = $aliasEntry['url'];
00600         $aliasEntry['is_valid'] = $imageNode->getAttribute( 'is_valid' );
00601         $aliasEntry['is_new'] = false;
00602         $aliasEntry['filesize'] = false;
00603 
00604         if ( $aliasEntry['url'] )
00605         {
00606             require_once( 'kernel/classes/ezclusterfilehandler.php' );
00607             $aliasFile = eZClusterFileHandler::instance( $aliasEntry['url'] );
00608 
00609             if ( $aliasFile->exists() )
00610                 $aliasEntry['filesize'] = $aliasFile->size();
00611         }
00612 
00613         $imageInformation = false;
00614         if ( $imageInfoNodeArray->length > 0 )
00615         {
00616             $imageInfoNode = $imageInfoNodeArray->item( 0 );
00617             $imageInformation = $this->parseInformationNode( $imageInfoNode );
00618         }
00619         $aliasEntry['info'] = $imageInformation;
00620 
00621         $serialNumber = $imageNode->getAttribute( 'serial_number' );
00622         if ( $serialNumber )
00623         {
00624             $this->setImageSerialNumber( $serialNumber );
00625         }
00626 
00627         $aliasList['original'] = $aliasEntry;
00628 
00629         if ( $imageVariationNodeArray->length > 0 )
00630         {
00631             foreach ( $imageVariationNodeArray as $imageVariation )
00632             {
00633                 $aliasEntry = array();
00634                 $aliasEntry['name'] = $imageVariation->getAttribute( 'name' );
00635                 $aliasEntry['width'] = $imageVariation->getAttribute( 'width' );
00636                 $aliasEntry['height'] = $imageVariation->getAttribute( 'height' );
00637                 $aliasEntry['mime_type'] = $imageVariation->getAttribute( 'mime_type' );
00638                 $aliasEntry['filename'] = $imageVariation->getAttribute( 'filename' );
00639                 $aliasEntry['suffix'] = $imageVariation->getAttribute( 'suffix' );
00640                 $aliasEntry['dirpath'] = $imageVariation->getAttribute( 'dirpath' );
00641                 $aliasEntry['alias_key'] = $imageVariation->getAttribute( 'alias_key' );
00642                 $aliasEntry['timestamp'] = $imageVariation->getAttribute( 'timestamp' );
00643                 $aliasEntry['is_valid'] = $imageVariation->getAttribute( 'is_valid' );
00644                 $aliasEntry['url'] = $imageVariation->getAttribute( 'url' );
00645                 $aliasEntry['basename'] = $basename;
00646                 $aliasEntry['alternative_text'] = $alternativeText;
00647                 $aliasEntry['text'] = $displayText;
00648                 $aliasEntry['original_filename'] = $originalFilename;
00649                 $aliasEntry['full_path'] = $aliasEntry['url'];
00650                 $aliasEntry['is_new'] = false;
00651                 $aliasEntry['info'] = $imageInformation;
00652 
00653                 if ( $aliasEntry['url'] )
00654                 {
00655                     require_once( 'kernel/classes/ezclusterfilehandler.php' );
00656                     $aliasFile = eZClusterFileHandler::instance( $aliasEntry['url'] );
00657 
00658                     if ( $aliasFile->exists() )
00659                         $aliasEntry['filesize'] = $aliasFile->size();
00660                 }
00661 
00662                 require_once( 'kernel/common/image.php' );
00663                 $imageManager = imageInit();
00664                 if ( $imageManager->isImageAliasValid( $aliasEntry ) )
00665                 {
00666                     $aliasList[$aliasEntry['name']] = $aliasEntry;
00667                 }
00668             }
00669         }
00670         $this->setAliasList( $aliasList );
00671         eZDebug::accumulatorStop( 'imageparse' );
00672         return $aliasList;
00673     }
00674 
00675    /**
00676     * Removes all image alias files which the attribute refers to.
00677     *
00678     * @param eZContentObjectAttribute
00679     * @note If you want to remove the alias information use removeAliases().
00680     **/
00681     static function removeAllAliases( $contentObjectAttribute )
00682     {
00683         $handler = $contentObjectAttribute->attribute( 'content' );
00684         if ( !$handler->isImageOwner() )
00685         {
00686             return;
00687         }
00688         $attributeData = $handler->originalAttributeData();
00689         $files = eZImageFile::fetchForContentObjectAttribute( $attributeData['attribute_id'], false );
00690         $dirs = array();
00691 
00692         require_once( 'kernel/classes/ezclusterfilehandler.php' );
00693         foreach ( $files as $filepath )
00694         {
00695             $file = eZClusterFileHandler::instance( $filepath );
00696             if ( $file->exists() )
00697             {
00698                 // FIXME: optimize not to use recursive delete
00699                 $file->delete();
00700                 $dirs[] = eZDir::dirpath( $filepath );
00701             }
00702         }
00703         $dirs = array_unique( $dirs );
00704         foreach ( $dirs as $dirpath )
00705         {
00706             eZDir::cleanupEmptyDirectories( $dirpath );
00707         }
00708         eZImageFile::removeForContentObjectAttribute( $attributeData['attribute_id'] );
00709     }
00710 
00711     /**
00712      * Removes all the image aliases and their information.
00713      * The stored images will also be removed if the attribute is the owner
00714      * of the images.
00715      *
00716      * After the images are removed the attribute will containe an internal
00717      * structure with empty data
00718      *
00719      * @param eZContentObjectAttribute $contentObjectAttribute
00720      *        Content object attribute to remove aliases for
00721      *
00722      * @return void
00723      **/
00724     function removeAliases( $contentObjectAttribute )
00725     {
00726         $aliasList = $this->aliasList();
00727         $alternativeText = false;
00728 
00729         $contentObjectAttributeVersion = $this->ContentObjectAttributeData['version'];
00730         $contentObjectAttributeID = $this->ContentObjectAttributeData['id'];
00731 
00732         $isImageOwner = $this->isImageOwner();
00733 
00734         // We loop over each image alias, and look up the file in ezcontentobject_attribute
00735         // Only images referenced by one version will be removed
00736         foreach ( $aliasList as $aliasName => $alias )
00737         {
00738             $dirpath = $alias['dirpath'];
00739             $doNotDelete = false; // Do not delete files from storage
00740 
00741             if ( $aliasName == 'original' )
00742                 $alternativeText = $alias['alternative_text'];
00743             if ( $alias['is_valid'] )
00744             {
00745                 $filepath = $alias['url'];
00746 
00747                 // Fetch ezimage attributes that use $filepath
00748                 // Always returns current attribute (array of $contentObjectAttributeID and $contentObjectAttributeVersion)
00749                 $dbResult = eZImageFile::fetchImageAttributesByFilepath( $filepath, $contentObjectAttributeID );
00750                 $dbResultCount = count( $dbResult );
00751                 // Check if there are the attributes.
00752                 if ( $dbResultCount > 0 )
00753                 {
00754                     $doNotDelete = true;
00755                     foreach ( $dbResult as $res )
00756                     {
00757                         // We only look results where the version matches
00758                         if ( $res['version'] == $contentObjectAttributeVersion )
00759                         {
00760                             // If more than one result has been returned, it means
00761                             // that another version is using the same image,
00762                             // and we should not delete this file
00763                             if ( $dbResultCount > 1 )
00764                             {
00765                                 continue;
00766                             }
00767                             // Only one result means that the current attribute
00768                             // & version are the only ones using this image,
00769                             // and it can be removed
00770                             else
00771                             {
00772                                 $doNotDelete = false;
00773                             }
00774                         }
00775 
00776                         eZImageFile::appendFilepath( $res['id'], $filepath, true );
00777                     }
00778                 }
00779 
00780                 if ( !$doNotDelete )
00781                 {
00782                     require_once( 'kernel/classes/ezclusterfilehandler.php' );
00783                     $file = eZClusterFileHandler::instance( $filepath );
00784                     if ( $file->exists() )
00785                     {
00786                         $file->delete();
00787                         eZImageFile::removeFilepath( $contentObjectAttributeID, $filepath );
00788                         eZDir::cleanupEmptyDirectories( $dirpath );
00789                     }
00790                     else
00791                     {
00792                         eZDebug::writeError( "Image file $filepath for alias $aliasName does not exist, could not remove from disk",
00793                                              'eZImageAliasHandler::removeAliases' );
00794                     }
00795                 }
00796             }
00797         }
00798 
00799         $doc = new DOMDocument( '1.0', 'utf-8' );
00800         $imageNode = $doc->createElement( "ezimage" );
00801         $doc->appendChild( $imageNode );
00802 
00803         $imageNode->setAttribute( 'serial_number', false );
00804         $imageNode->setAttribute( 'is_valid', false );
00805         $imageNode->setAttribute( 'filename', false );
00806         $imageNode->setAttribute( 'suffix', false );
00807         $imageNode->setAttribute( 'basename', false );
00808         $imageNode->setAttribute( 'dirpath', false );
00809         $imageNode->setAttribute( 'url', false );
00810         $imageNode->setAttribute( 'original_filename', false );
00811         $imageNode->setAttribute( 'mime_type', false );
00812         $imageNode->setAttribute( 'width', false );
00813         $imageNode->setAttribute( 'height', false );
00814         $imageNode->setAttribute( 'alternative_text', $alternativeText );
00815         $imageNode->setAttribute( 'alias_key', false );
00816         $imageNode->setAttribute( 'timestamp', false );
00817 
00818         $this->ContentObjectAttributeData['DataTypeCustom']['dom_tree'] = $doc;
00819         unset( $this->ContentObjectAttributeData['DataTypeCustom']['alias_list'] );
00820 
00821         $this->storeDOMTree( $doc, true, $contentObjectAttribute );
00822     }
00823 
00824     /*!
00825      Will update the path for images to point to the new path \a $dirpath and filename \a $name.
00826 
00827      This is usually called when the object contain the image attribute is moved in the tree.
00828     */
00829     function updateAliasPath( $dirpath, $name )
00830     {
00831         if ( !file_exists( $dirpath ) )
00832         {
00833             eZDir::mkdir( $dirpath, false, true );
00834         }
00835         //include_once( 'lib/ezutils/classes/ezmimetype.php' );
00836         $aliasList = $this->aliasList();
00837         $this->resetImageSerialNumber();
00838 
00839         foreach ( $aliasList as $aliasName => $alias )
00840         {
00841             if ( $alias['dirpath'] != $dirpath )
00842             {
00843                 $oldDirpath = $alias['url'];
00844                 $oldURL = $alias['url'];
00845                 $basename = $name;
00846                 if ( $aliasName != 'original' )
00847                     $basename .= '_' . $aliasName;
00848                 eZMimeType::changeFileData( $alias, $dirpath, $basename );
00849                 $alias['full_path'] = $alias['url'];
00850                 if ( $this->isImageOwner() )
00851                 {
00852                     if ( $oldURL == '' )
00853                     {
00854                         continue;
00855                     }
00856 
00857                     require_once( 'kernel/classes/ezclusterfilehandler.php' );
00858                     $fileHandler = eZClusterFileHandler::instance();
00859                     $fileHandler->fileMove( $oldURL, $alias['url'] );
00860 
00861                     eZDir::cleanupEmptyDirectories( $oldDirpath );
00862                     eZImageFile::moveFilepath( $this->ContentObjectAttributeData['id'], $oldURL, $alias['url'] );
00863                 }
00864                 else
00865                 {
00866                     require_once( 'kernel/classes/ezclusterfilehandler.php' );
00867                     $fileHandler = eZClusterFileHandler::instance();
00868                     $fileHandler->fileLinkCopy( $oldURL, $alias['url'], false );
00869                     eZImageFile::appendFilepath( $this->ContentObjectAttributeData['id'], $alias['url'] );
00870                 }
00871                 $this->setAliasVariation( $aliasName, $alias );
00872             }
00873         }
00874 
00875         $this->recreateDOMTree();
00876         $this->setStorageRequired();
00877     }
00878 
00879     /*!
00880      \private
00881      Creates XML attributes containing information on the original image attribute.
00882 
00883      The new attributes will be appended to \a $originalNode.
00884     */
00885     function createOriginalAttributeXMLData( $originalNode, $originalData )
00886     {
00887         $originalNode->setAttribute( 'attribute_id', $originalData['attribute_id'] );
00888         $originalNode->setAttribute( 'attribute_version', $originalData['attribute_version'] );
00889         $originalNode->setAttribute( 'attribute_language', $originalData['attribute_language'] );
00890     }
00891 
00892     /*!
00893      \private
00894      Recreates the DOM tree from the internal array structures and stores the DOM tree
00895      in the 'data_text' field of the attribute.
00896     */
00897     function recreateDOMTree()
00898     {
00899         $aliasList = $this->aliasList();
00900         $doc = new DOMDocument( '1.0', 'utf-8' );
00901         $imageNode = $doc->createElement( "ezimage" );
00902         $doc->appendChild( $imageNode );
00903 
00904         $originalNode = $doc->createElement( "original" );
00905         $imageNode->appendChild( $originalNode );
00906 
00907         require_once( 'kernel/common/image.php' );
00908         $imageManager = imageInit();
00909 
00910         $aliasName = 'original';
00911 
00912         $originalData = $this->originalAttributeData();
00913         $this->createOriginalAttributeXMLData( $originalNode, $originalData );
00914 
00915         $imageNode->setAttribute( 'serial_number', $this->imageSerialNumber() );
00916         $imageNode->setAttribute( 'is_valid', $aliasList[$aliasName]['is_valid'] );
00917         $imageNode->setAttribute( 'filename', $aliasList[$aliasName]['filename'] );
00918         $imageNode->setAttribute( 'suffix', $aliasList[$aliasName]['suffix'] );
00919         $imageNode->setAttribute( 'basename', $aliasList[$aliasName]['basename'] );
00920         $imageNode->setAttribute( 'dirpath', $aliasList[$aliasName]['dirpath'] );
00921         $imageNode->setAttribute( 'url', $aliasList[$aliasName]['url'] );
00922         $imageNode->setAttribute( 'original_filename', $aliasList[$aliasName]['original_filename'] );
00923         $imageNode->setAttribute( 'mime_type', $aliasList[$aliasName]['mime_type'] );
00924         $imageNode->setAttribute( 'width', $aliasList[$aliasName]['width'] );
00925         $imageNode->setAttribute( 'height', $aliasList[$aliasName]['height'] );
00926         $imageNode->setAttribute( 'alternative_text', $aliasList[$aliasName]['alternative_text'] );
00927         $imageNode->setAttribute( 'alias_key', $imageManager->createImageAliasKey( $imageManager->alias( $aliasName ) ) );
00928         $imageNode->setAttribute( 'timestamp', $aliasList[$aliasName]['timestamp'] );
00929 
00930         $filename = $aliasList[$aliasName]['url'];
00931         if ( $filename )
00932         {
00933             require_once( 'kernel/classes/ezclusterfilehandler.php' );
00934             $imageFile = eZClusterFileHandler::instance( $filename );
00935 
00936             $fetchedFilePath = $imageFile->fetchUnique();
00937 
00938             //(Cluster) Get mime data of real file, and fetch info by image analizer.
00939             //include_once( 'lib/ezutils/classes/ezmimetype.php' );
00940             $mimeDataTemp = eZMimeType::findByFileContents( $fetchedFilePath );
00941             $imageManager->analyzeImage( $mimeDataTemp );
00942 
00943             //(Cluster) Get mime data of a file which does not really exist on file system. We need this to build correct imageInformationNode.
00944             $mimeData = eZMimeType::findByURL( $filename );
00945             if ( isset( $mimeDataTemp['info'] ) )
00946                 $mimeData['info'] = $mimeDataTemp['info'];
00947 
00948             $this->createImageInformationNode( $imageNode, $mimeData );
00949             $imageFile->fileDeleteLocal( $fetchedFilePath );
00950         }
00951 
00952         foreach ( $aliasList as $aliasName => $alias )
00953         {
00954             if ( $aliasName == 'original' )
00955                 continue;
00956             $this->addImageAliasToXML( $doc, $alias );
00957         }
00958 
00959         $this->setDOMTree( $doc );
00960     }
00961 
00962     /*!
00963      \return the DOM tree for the current content object attribute.
00964      \note It will cache the result in the DataTypeCustom member variable of the
00965            content object attribute in the 'dom_tree' key.
00966     */
00967     function domTree()
00968     {
00969         $contentObjectAttributeData = $this->ContentObjectAttributeData;
00970         if ( isset( $contentObjectAttributeData['DataTypeCustom']['dom_tree'] ) )
00971         {
00972             return $contentObjectAttributeData['DataTypeCustom']['dom_tree'];
00973         }
00974 
00975         $dom = new DOMDocument( '1.0', 'utf-8' );
00976         $xmlString = $contentObjectAttributeData['data_text'];
00977         $success = $xmlString == '' ? false : $dom->loadXML( $xmlString );
00978         if ( !$success )
00979         {
00980             $this->generateXMLData();
00981             $xmlString = $this->ContentObjectAttributeData['data_text'];
00982             $success = $dom->loadXML( $xmlString );
00983         }
00984 
00985         $contentObjectAttributeData['DataTypeCustom']['dom_tree'] = $dom;
00986 
00987         return $dom;
00988     }
00989 
00990     /*!
00991      \private
00992      Parses the information node and generates the internal information structures.
00993 
00994      The information node contains information from the image itself, for instance
00995      EXIF data from a JPEG or TIFF image.
00996 
00997      \param $imageInfoNode
00998 
00999      \return $imageInformation array
01000     */
01001     function parseInformationNode( $imageInfoNode )
01002     {
01003         $imageInformation = array();
01004 
01005         $attributes = $imageInfoNode->attributes;
01006         foreach ( $attributes as $attribute )
01007         {
01008             $imageInformation[$attribute->name] = $attribute->value;
01009         }
01010 
01011         $children = $imageInfoNode->childNodes;
01012         foreach ( $children as $child )
01013         {
01014             if ( $child->nodeType != XML_ELEMENT_NODE )
01015             {
01016                 continue;
01017             }
01018 
01019             $childName = false;
01020             if ( isset ( $child->localName ) )
01021             {
01022                 $childName = $child->localName;
01023             }
01024 
01025             if ( $childName == 'array' )
01026             {
01027                 $name = $child->getAttribute( 'name' );
01028                 $items = $child->getElementsByTagName( 'item' );
01029                 $array = array();
01030                 foreach ( $items as $item )
01031                 {
01032                     $itemValue = $item->textContent;
01033                     if (  $item->getAttribute( 'base64' ) == '1' )
01034                     {
01035                         $array[$item->getAttribute( 'key' )] = base64_decode( $itemValue );
01036                     }
01037                     else
01038                     {
01039                         $array[$item->getAttribute( 'key' )] = $itemValue;
01040                     }
01041                 }
01042                 ksort( $array );
01043                 $imageInformation[$name] = $array;
01044             }
01045             else if ( $childName == 'serialized' )
01046             {
01047                 $name = $child->getAttribute( 'name' );
01048                 $data = $child->getAttribute( 'data' );
01049                 $imageInformation[$name] = unserialize( $data );
01050             }
01051         }
01052 
01053         return $imageInformation;
01054     }
01055 
01056     /*!
01057      \static
01058      Normalized the image name \a $imageName by removing all characters that are not considered
01059      filename or URL friendly.
01060      The filename will also be in non-capital letters.
01061     */
01062     function normalizeImageName( $imageName )
01063     {
01064         // Initialize transformation system
01065         //include_once( 'lib/ezi18n/classes/ezchartransform.php' );
01066         $trans = eZCharTransform::instance();
01067 
01068         $imageName = eZURLAliasML::convertToAlias( $imageName );
01069         return $imageName;
01070     }
01071 
01072     /*!
01073      Sets the uploaded HTTP file object to \a $httpFile.
01074      This object is used to store information about the image file until the content object attribute is to be stored.
01075      \sa httpFile
01076     */
01077     function setHTTPFile( $httpFile )
01078     {
01079         $this->ContentObjectAttributeData['DataTypeCustom']['http_file'] = $httpFile;
01080     }
01081 
01082     /*!
01083      \return the stored HTTP file object or \c false if no object is previously stored.
01084      \sa setHTTPFile
01085     */
01086     function httpFile( $release = false )
01087     {
01088         if ( isset( $this->ContentObjectAttributeData['DataTypeCustom']['http_file'] ) )
01089         {
01090             $httpFile = $this->ContentObjectAttributeData['DataTypeCustom']['http_file'];
01091             if ( $release )
01092             {
01093                 unset( $this->ContentObjectAttributeData['DataTypeCustom']['http_file'] );
01094             }
01095             return $httpFile;
01096         }
01097 
01098         return false;
01099     }
01100 
01101     /*!
01102      Initializes the content object attribute \a $contentObjectAttribute with the uploaded HTTP file \a $httpFile.
01103      Optionally you may also specify the alternative text in the parameter \a $imageAltText.
01104     */
01105     function initializeFromHTTPFile( $httpFile, $imageAltText = false )
01106     {
01107         $this->increaseImageSerialNumber();
01108 
01109         //include_once( 'lib/ezutils/classes/ezmimetype.php' );
01110         $mimeData = eZMimeType::findByFileContents( $httpFile->attribute( 'filename' ) );
01111         if ( !$mimeData['is_valid'] )
01112         {
01113             $mimeData = eZMimeType::findByName( $httpFile->attribute( 'mime_type' ) );
01114             if ( !$mimeData['is_valid'] )
01115             {
01116                 $mimeData = eZMimeType::findByURL( $httpFile->attribute( 'original_filename' ) );
01117             }
01118         }
01119         $attr = false;
01120         $this->removeAliases( $attr );
01121         $this->setOriginalAttributeDataValues( $this->ContentObjectAttributeData['id'],
01122                                                $this->ContentObjectAttributeData['version'],
01123                                                $this->ContentObjectAttributeData['language_code'] );
01124         $contentVersion = eZContentObjectVersion::fetchVersion( $this->ContentObjectAttributeData['version'],
01125                                                                 $this->ContentObjectAttributeData['contentobject_id'] );
01126         $objectName = $this->imageName( $this->ContentObjectAttributeData, $contentVersion );
01127         $objectPathString = $this->imagePath( $this->ContentObjectAttributeData, $contentVersion, true );
01128 
01129         eZMimeType::changeBaseName( $mimeData, $objectName );
01130         eZMimeType::changeDirectoryPath( $mimeData, $objectPathString );
01131 
01132         $httpFile->store( false, false, $mimeData );
01133 
01134         $originalFilename = $httpFile->attribute( 'original_filename' );
01135         return $this->initialize( $mimeData, $originalFilename, $imageAltText );
01136     }
01137 
01138     /*!
01139      Initializes the content object attribute \a $contentObjectAttribute with the filename \a $filename.
01140      Optionally you may also specify the alternative text in the parameter \a $imageAltText.
01141      \sa initialize
01142     */
01143     function initializeFromFile( $filename, $imageAltText = false, $originalFilename = false )
01144     {
01145         if ( !file_exists( $filename ) )
01146         {
01147             eZDebug::writeError( "The image '$filename' does not exist, cannot initialize image attribute with it",
01148                                  'eZImageAliasHandler::initializeFromFile' );
01149             return false;
01150         }
01151 
01152         $this->increaseImageSerialNumber();
01153 
01154         if ( !$originalFilename )
01155             $originalFilename = basename( $filename );
01156         //include_once( 'lib/ezutils/classes/ezmimetype.php' );
01157         $mimeData = eZMimeType::findByFileContents( $filename );
01158         if ( !$mimeData['is_valid'] and
01159              $originalFilename != $filename )
01160         {
01161             $mimeData = eZMimeType::findByFileContents( $originalFilename );
01162         }
01163 
01164         $attr = false;
01165         $this->removeAliases( $attr );
01166         $this->setOriginalAttributeDataValues( $this->ContentObjectAttributeData['id'],
01167                                                $this->ContentObjectAttributeData['version'],
01168                                                $this->ContentObjectAttributeData['language_code'] );
01169         $contentVersion = eZContentObjectVersion::fetchVersion( $this->ContentObjectAttributeData['version'],
01170                                                                 $this->ContentObjectAttributeData['contentobject_id'] );
01171         $objectName = $this->imageName( $this->ContentObjectAttributeData, $contentVersion );
01172         $objectPathString = $this->imagePath( $this->ContentObjectAttributeData, $contentVersion, true );
01173 
01174         eZMimeType::changeBaseName( $mimeData, $objectName );
01175         eZMimeType::changeDirectoryPath( $mimeData, $objectPathString );
01176         if ( !file_exists( $mimeData['dirpath'] ) )
01177         {
01178             eZDir::mkdir( $mimeData['dirpath'], false, true );
01179         }
01180 
01181         eZFileHandler::copy( $filename, $mimeData['url'] );
01182 
01183         return $this->initialize( $mimeData, $originalFilename, $imageAltText );
01184     }
01185 
01186     /*!
01187      Makes sure the attribute contains the image file mentioned in \a $mimeData.
01188      This involves removing any previous image (and image aliases), increasing
01189      the image name counter, figuring out the image size and creating
01190      the internal XML structure.
01191      \return \c true on success.
01192     */
01193     function initialize( $mimeData, $originalFilename, $imageAltText = false )
01194     {
01195         require_once( 'kernel/common/image.php' );
01196         $imageManager = imageInit();
01197 
01198         $this->setOriginalAttributeDataValues( $this->ContentObjectAttributeData['id'],
01199                                                $this->ContentObjectAttributeData['version'],
01200                                                $this->ContentObjectAttributeData['language_code'] );
01201 
01202         $aliasList = array( 'original' => $mimeData );
01203         $aliasList['original']['alternative_text'] = $imageAltText;
01204         $aliasList['original']['original_filename'] = $originalFilename;
01205 
01206         require_once( 'kernel/classes/ezclusterfilehandler.php' );
01207         $fileHandler = eZClusterFileHandler::instance();
01208         $filePath = $mimeData['url'];
01209         $fileHandler->fileStore( $filePath, 'image', false, $mimeData['name'] );
01210 
01211         if ( $imageManager->createImageAlias( 'original', $aliasList, array( 'basename' => $mimeData['basename'] ) ) )
01212         {
01213             $mimeData = $aliasList['original'];
01214             $mimeData['name'] = $mimeData['mime_type'];
01215             $aliasList['original']['original_filename'] = $originalFilename;
01216         }
01217 
01218         if ( $aliasList['original']['url'] )
01219         {
01220             require_once( 'kernel/classes/ezclusterfilehandler.php' );
01221             $aliasFile = eZClusterFileHandler::instance( $aliasList['original']['url'] );
01222             if( $aliasFile->exists() )
01223                 $aliasList['original']['filesize'] = $aliasFile->size();
01224         }
01225 
01226         // refetch the original image
01227         $fileHandler->fileFetch( $filePath );
01228 
01229         $imageManager->analyzeImage( $mimeData );
01230 
01231         $doc = new DOMDocument( '1.0', 'utf-8' );
01232         $imageNode = $doc->createElement( "ezimage" );
01233         $doc->appendChild( $imageNode );
01234 
01235         $width = false;
01236         $height = false;
01237         $info = getimagesize( $mimeData['url'] );
01238         if ( $info )
01239         {
01240             $width = $info[0];
01241             $height = $info[1];
01242         }
01243 
01244         $originalNode = $doc->createElement( "original" );
01245         $imageNode->appendChild( $originalNode );
01246         $attributeData = $this->originalAttributeData();
01247         $this->createOriginalAttributeXMLData( $originalNode, $attributeData );
01248 
01249         $imageNode->setAttribute( 'serial_number', $this->imageSerialNumber() );
01250         $imageNode->setAttribute( 'is_valid', true );
01251         $imageNode->setAttribute( 'filename', $mimeData['filename'] );
01252         $imageNode->setAttribute( 'suffix', $mimeData['suffix'] );
01253         $imageNode->setAttribute( 'basename', $mimeData['basename'] );
01254         $imageNode->setAttribute( 'dirpath', $mimeData['dirpath'] );
01255         $imageNode->setAttribute( 'url', $mimeData['url'] );
01256         $imageNode->setAttribute( 'original_filename', $originalFilename );
01257         $imageNode->setAttribute( 'mime_type', $mimeData['name'] );
01258         $imageNode->setAttribute( 'width', $width );
01259         $imageNode->setAttribute( 'height', $height );
01260         $imageNode->setAttribute( 'alternative_text', $imageAltText );
01261         $imageNode->setAttribute( 'alias_key', $imageManager->createImageAliasKey( $imageManager->alias( 'original' ) ) );
01262         $imageNode->setAttribute( 'timestamp', time() );
01263 
01264         $this->createImageInformationNode( $imageNode, $mimeData );
01265 
01266         $this->setDOMTree( $doc );
01267 
01268         $this->setAliasList( $aliasList );
01269 
01270         eZImageFile::appendFilepath( $this->ContentObjectAttributeData['id'], $mimeData['url'] );
01271 
01272         $fileHandler->fileDeleteLocal( $filePath );
01273 
01274         return true;
01275     }
01276 
01277     function createImageInformationNode( $imageNode, $mimeData )
01278     {
01279         $dom = $imageNode->ownerDocument;
01280         if ( isset( $mimeData['info'] ) and
01281              $mimeData['info'] )
01282         {
01283             $imageInfoNode = $dom->createElement( 'information' );
01284             $info = $mimeData['info'];
01285             foreach ( $info as $infoItemName => $infoItem )
01286             {
01287                 if ( is_array( $infoItem ) )
01288                 {
01289                     $hasScalarValues = true;
01290                     foreach ( $infoItem as $infoArrayItem )
01291                     {
01292                         if ( is_array( $infoArrayItem ) )
01293                         {
01294                             $hasScalarValues = false;
01295                             break;
01296                         }
01297                     }
01298                     if ( !$hasScalarValues )
01299                     {
01300                         $toRemove = array();
01301                         foreach ( $infoItem as $key => $value )
01302                         {
01303                             if ( is_string( $value ) && !ctype_print( $value ) )
01304                             {
01305                                 $toRemove[] = $key;
01306                             }
01307                         }
01308 
01309                         if ( count( $toRemove ) > 0 )
01310                         {
01311                             eZDebug::writeDebug( 'removing image information items containing non-printable characters: ' . implode( ', ', $toRemove ) );
01312 
01313                             foreach ( $toRemove as $remove )
01314                             {
01315                                 unset( $infoItem[$remove] );
01316                             }
01317                         }
01318 
01319                         unset( $serializedNode );
01320                         $serializedNode = $dom->createElement( 'serialized' );
01321                         $serializedNode->setAttribute( 'name', $infoItemName );
01322                         $serializedNode->setAttribute( 'data', serialize( $infoItem ) );
01323 
01324                         $imageInfoNode->appendChild( $serializedNode );
01325                     }
01326                     else
01327                     {
01328                         unset( $arrayNode );
01329                         $arrayNode = $dom->createElement( 'array' );
01330                         $arrayNode->setAttribute( 'name', $infoItemName );
01331 
01332                         $imageInfoNode->appendChild( $arrayNode );
01333                         foreach ( $infoItem as $infoArrayKey => $infoArrayItem )
01334                         {
01335                             unset( $arrayItemNode );
01336                             $arrayItemNode = $dom->createElement( 'item' );
01337                             $arrayItemNode->appendChild( $dom->createTextNode( base64_encode( $infoArrayItem ) ) );
01338                             $arrayItemNode->setAttribute( 'key', $infoArrayKey );
01339                             $arrayItemNode->setAttribute( 'base64', 1 );
01340 
01341                             $arrayNode->appendChild( $arrayItemNode );
01342                         }
01343                     }
01344                 }
01345                 else
01346                 {
01347                     $infoItem = iconv( mb_detect_encoding( $infoItem ), 'UTF-8//IGNORE', $infoItem );
01348                     $imageInfoNode->setAttribute( $infoItemName, $infoItem );
01349                 }
01350             }
01351             $imageNode->appendChild( $imageInfoNode );
01352         }
01353     }
01354 
01355     /*!
01356      Adds all the new image alias structures in \a $imageAliasList to the content object attribute.
01357     */
01358     function addImageAliases( $imageAliasList )
01359     {
01360         $domTree = $this->domTree();
01361         foreach ( $imageAliasList as $imageAliasName => $imageAlias )
01362         {
01363             if ( $imageAlias['is_new'] )
01364             {
01365                 $this->addImageAliasToXML( $domTree, $imageAlias );
01366                 $this->setAliasAttribute( $imageAliasName, 'is_new', false );
01367             }
01368         }
01369         $attr = false;
01370         $this->storeDOMTree( $domTree, true, $attr );
01371     }
01372 
01373     /*!
01374      Adds the image alias structure \a $imageAlias to the content object attribute.
01375     */
01376     function addImageAlias( $imageAlias )
01377     {
01378         $domTree = $this->domTree();
01379         $this->addImageAliasToXML( $domTree, $imageAlias );
01380         $attr = false;
01381         $this->storeDOMTree( $domTree, true, $attr );
01382 
01383     }
01384 
01385     /*!
01386      Adds the image alias structure \a $imageAlias to the XML DOM document \a $domTree.
01387     */
01388     function addImageAliasToXML( $domTree, $imageAlias )
01389     {
01390         $imageVariationNodeArray = $domTree->getElementsByTagName( 'alias' );
01391         $imageNode = false;
01392         foreach ( $imageVariationNodeArray as $imageVariation )
01393         {
01394             $aliasEntryName = $imageVariation->getAttribute( 'name' );
01395             if ( $aliasEntryName == $imageAlias['name'] )
01396             {
01397                 $imageNode = $imageVariation;
01398                 break;
01399             }
01400         }
01401         if ( !$imageNode )
01402         {
01403             $rootNode = $domTree->documentElement;
01404 
01405             $imageNode = $domTree->createElement( "alias" );
01406             $rootNode->appendChild( $imageNode );
01407         }
01408         else
01409         {
01410             $imageNode->removeAttribute( 'name' );
01411             $imageNode->removeAttribute( 'filename' );
01412             $imageNode->removeAttribute( 'suffix' );
01413             $imageNode->removeAttribute( 'dirpath' );
01414             $imageNode->removeAttribute( 'url' );
01415             $imageNode->removeAttribute( 'mime_type' );
01416             $imageNode->removeAttribute( 'width' );
01417             $imageNode->removeAttribute( 'height' );
01418             $imageNode->removeAttribute( 'alias_key' );
01419             $imageNode->removeAttribute( 'timestamp' );
01420             $imageNode->removeAttribute( 'is_valid' );
01421         }
01422         $imageNode->setAttribute( 'name', $imageAlias['name'] );
01423         $imageNode->setAttribute( 'filename', $imageAlias['filename'] );
01424         $imageNode->setAttribute( 'suffix', $imageAlias['suffix'] );
01425         $imageNode->setAttribute( 'dirpath', $imageAlias['dirpath'] );
01426         $imageNode->setAttribute( 'url', $imageAlias['url'] );
01427         $imageNode->setAttribute( 'mime_type', $imageAlias['mime_type'] );
01428         $imageNode->setAttribute( 'width', $imageAlias['width'] );
01429         $imageNode->setAttribute( 'height', $imageAlias['height'] );
01430         $imageNode->setAttribute( 'alias_key', $imageAlias['alias_key'] );
01431         $imageNode->setAttribute( 'timestamp', $imageAlias['timestamp'] );
01432         $imageNode->setAttribute( 'is_valid', $imageAlias['is_valid'] );
01433     }
01434 
01435     /*!
01436      Sets the XML DOM document \a $domTree as the current DOM document.
01437     */
01438     function setDOMTree( $domTree )
01439     {
01440         $this->ContentObjectAttributeData['DataTypeCustom']['dom_tree'] = $domTree;
01441         $this->ContentObjectAttributeData['DataTypeCustom']['is_storage_required'] = true;
01442     }
01443 
01444     /*!
01445      Stores the XML DOM document \a $domTree to the content object attribute.
01446     */
01447     function storeDOMTree( $domTree, $storeAttribute, $contentObjectAttributeRef )
01448     {
01449         if ( !$domTree )
01450             return false;
01451         $this->ContentObjectAttributeData['DataTypeCustom']['dom_tree'] = $domTree;
01452         $this->ContentObjectAttributeData['DataTypeCustom']['is_storage_required'] = false;
01453         $xmlString = $domTree->saveXML();
01454         $this->ContentObjectAttributeData['data_text'] = $xmlString;
01455 
01456         if ( $storeAttribute )
01457         {
01458             if ( is_object( $contentObjectAttributeRef )  )
01459             {
01460                 $contentObjectAttribute = $contentObjectAttributeRef;
01461             }
01462             else
01463             {
01464                 $contentObjectAttribute = eZContentObjectAttribute::fetch( $this->ContentObjectAttributeData['id'],
01465                                                                            $this->ContentObjectAttributeData['version'] );
01466             }
01467 
01468             if ( is_object( $contentObjectAttribute )  )
01469             {
01470                 $contentObjectAttribute->setAttribute( 'data_text', $xmlString );
01471                 $contentObjectAttribute->storeData();
01472             }
01473             else
01474             {
01475                 eZDebug::writeError( "Invalid objectAttribute: id = " . $this->ContentObjectAttributeData['id'] .
01476                                     " version = " . $this->ContentObjectAttributeData['version'] ,
01477                                     "eZImageAliasHandler::storeDOMTree" );
01478             }
01479         }
01480 
01481         return true;
01482     }
01483 
01484     /*!
01485      Stores the data in the image alias handler to the content object attribute.
01486      \sa isStorageRequired, setStorageRequired
01487     */
01488     function store( $contentObjectAttribute )
01489     {
01490         $domTree = $this->domTree();
01491         if ( $domTree )
01492         {
01493             if ( is_object( $contentObjectAttribute ) )
01494             {
01495                 $this->storeDOMTree( $domTree, false, $contentObjectAttribute );
01496 
01497                 $contentObjectAttribute->setAttribute( 'data_text', $this->ContentObjectAttributeData['data_text'] );
01498                 $contentObjectAttribute->storeData();
01499             }
01500             else
01501             {
01502                 $this->storeDOMTree( $domTree, true, $contentObjectAttribute );
01503 
01504             }
01505         }
01506 
01507         $this->setStorageRequired( false );
01508     }
01509 
01510     /*!
01511      \return \c true if the image alias handler is required to store it's contents.
01512      \sa setStorageRequired, store
01513     */
01514     function isStorageRequired()
01515     {
01516         return isset( $this->ContentObjectAttributeData['DataTypeCustom']['is_storage_required'] ) ?
01517             $this->ContentObjectAttributeData['DataTypeCustom']['is_storage_required'] :
01518             false;
01519     }
01520 
01521     /*!
01522      Sets whether storage of the image alias data is required or not.
01523      \sa isStorageRequired, store
01524     */
01525     function setStorageRequired( $require = true )
01526     {
01527         $this->ContentObjectAttributeData['DataTypeCustom']['is_storage_required'] = $require;
01528     }
01529 
01530     /*!
01531      \return An array structure with information on which attribute
01532              originally created the current data.
01533 
01534      This will only contain data if the attribute is a copy of
01535      another attribute, e.g in the case of a new version without an new image upload.
01536     */
01537     function originalAttributeData()
01538     {
01539         $contentObjectAttributeData = $this->ContentObjectAttributeData;
01540         if ( isset( $contentObjectAttributeData['DataTypeCustom']['original_data'] ) )
01541             return $contentObjectAttributeData['DataTypeCustom']['original_data'];
01542 
01543         $originalData = array( 'attribute_id' => $contentObjectAttributeData['id'],
01544                                'attribute_version' => $contentObjectAttributeData['version'],
01545                                'attribute_language' => $contentObjectAttributeData['language_code'] );
01546         $this->setOriginalAttributeData( $originalData );
01547         return $originalData;
01548     }
01549 
01550     /*!
01551      Sets the information on which attribute the data was fetched from.
01552      See eZImageAliasHandler::originalAttributeData() for more information.
01553     */
01554     function setOriginalAttributeData( $originalData )
01555     {
01556         $this->ContentObjectAttributeData['DataTypeCustom']['original_data'] = $originalData;
01557 
01558         $domTree = $this->domTree();
01559         $imageOriginalArray = $domTree->getElementsByTagName( "original" );
01560         if ( $imageOriginalArray->length > 0 )
01561         {
01562             $imageOriginalNode = $imageOriginalArray->item( 0 );
01563             $this->createOriginalAttributeXMLData( $imageOriginalNode, $originalData );
01564         }
01565     }
01566 
01567     /*!
01568      Sets the information on which attribute the data was fetched from.
01569 
01570      Fetches data from the contentobject attribute \a $contentObjectAttribute and
01571      sets it using setOriginalAttributeData().
01572     */
01573     function setOriginalAttributeDataFromAttribute( $contentObjectAttribute )
01574     {
01575         $originalImageHandler = $contentObjectAttribute->attribute( 'content' );
01576         $originalAttributeData = $originalImageHandler->originalAttributeData();
01577         $domTree = $originalImageHandler->domTree();
01578         $this->setDOMTree( $domTree );
01579         if ( $originalAttributeData['attribute_id'] )
01580         {
01581             $this->setOriginalAttributeData( $originalAttributeData );
01582         }
01583         else
01584         {
01585             $this->setOriginalAttributeDataValues( $contentObjectAttribute->attribute( 'id' ),
01586                                                    $contentObjectAttribute->attribute( 'version' ),
01587                                                    $contentObjectAttribute->attribute( 'language_code' ),
01588                                                    false );
01589         }
01590     }
01591 
01592     /*!
01593      Sets the information on which attribute the data was fetched from.
01594 
01595      Fetches data from the parameters and sets it using setOriginalAttributeData().
01596     */
01597     function setOriginalAttributeDataValues( $attributeID, $attributeVersion, $attributeLanguage )
01598     {
01599         $this->setOriginalAttributeData( array( 'attribute_id' => $attributeID,
01600                                                 'attribute_version' => $attributeVersion,
01601                                                 'attribute_language' => $attributeLanguage ) );
01602     }
01603 
01604     /*!
01605      Set internal serial number
01606 
01607      \param value
01608     */
01609     function setImageSerialNumber( $val )
01610     {
01611         $this->ContentObjectAttributeData['DataTypeCustom']['serial_number'] = $val;
01612     }
01613 
01614     /*!
01615      \private
01616      \return The internal serial number.
01617 
01618      It will check if a serial number exists and return that, if not a new one will be created and returned.
01619     */
01620     private function imageSerialNumberRaw()
01621     {
01622         return isset( $this->ContentObjectAttributeData['DataTypeCustom']['serial_number'] ) ?
01623             $this->ContentObjectAttributeData['DataTypeCustom']['serial_number'] :
01624             0;
01625     }
01626 
01627     /*!
01628      Fetches image information from the old 3.2 image system and creates new information.
01629     */
01630     function generateXMLData()
01631     {
01632         // VS-DBFILE
01633         // VS: I feel we don't need clustering support for the old image system.
01634 
01635         //include_once( "lib/ezdb/classes/ezdb.php" );
01636 
01637         $db = eZDB::instance();
01638 
01639         $contentObjectAttributeData = $this->ContentObjectAttributeData;
01640         $attributeID = $contentObjectAttributeData['id'];
01641         $attributeVersion = $contentObjectAttributeData['version'];
01642 
01643         if ( is_numeric( $attributeID ) )
01644         {
01645             $imageRow = $db->arrayQuery( "SELECT * FROM ezimage
01646                                            WHERE contentobject_attribute_id=$attributeID AND
01647                                                  version=$attributeVersion" );
01648         }
01649 
01650         $doc = new DOMDocument( '1.0', 'utf-8' );
01651         $imageNode = $doc->createElement( "ezimage" );
01652         $doc->appendChild( $imageNode );
01653 
01654         $isValid = false;
01655         $fileName = false;
01656         $suffix = false;
01657         $baseName = false;
01658         $dirPath = false;
01659         $filePath = false;
01660         $originalFileName = false;
01661         $mimeType = false;
01662         $width = false;
01663         $height = false;
01664         $altText = false;
01665 
01666         //include_once( 'lib/ezutils/classes/ezmimetype.php' );
01667         if ( count( $imageRow ) == 1 )
01668         {
01669             require_once( 'kernel/classes/ezclusterfilehandler.php' );
01670             $fileHandler = eZClusterFileHandler::instance();
01671 
01672             $fileName = $imageRow[0]['filename'];
01673             $originalFileName = $imageRow[0]['original_filename'];
01674             $mimeType = $imageRow[0]['mime_type'];
01675             $altText = $imageRow[0]['alternative_text'];
01676 
01677             $dirPath = eZSys::storageDirectory() . '/original/image';
01678             $filePath = $dirPath . '/' . $fileName;
01679 
01680             // VS-DBFILE : TODO checked
01681 
01682             $baseName = $fileName;
01683             $dotPosition = strrpos( $fileName, '.' );
01684             if ( $dotPosition !== false )
01685             {
01686                 $baseName = substr( $fileName, 0, $dotPosition );
01687                 $suffix = substr( $fileName, $dotPosition + 1 );
01688             }
01689 
01690             $width = false;
01691             $height = false;
01692             if ( !file_exists( $filePath ) )
01693             {
01694                 $referenceDirPath = eZSys::storageDirectory() . '/reference/image';
01695                 $suffixList = array( 'jpg', 'png', 'gif' );
01696                 foreach ( $suffixList as $suffix )
01697                 {
01698                     // VS-DBFILE : TODO checked
01699 
01700                     $referenceFilePath = $referenceDirPath . '/' . $baseName . '.' . $suffix;
01701                     if ( file_exists( $referenceFilePath ) )
01702                     {
01703                         $filePath = $referenceFilePath;
01704                         $dirPath = $referenceDirPath;
01705                         break;
01706                     }
01707                 }
01708             }
01709 
01710             // VS-DBFILE : TODO checked
01711 
01712             if ( file_exists( $filePath ) )
01713             {
01714                 $isValid = true;
01715                 $info = getimagesize( $filePath );
01716                 if ( $info )
01717                 {
01718                     $width = $info[0];
01719                     $height = $info[1];
01720                 }
01721                 $mimeInfo = eZMimeType::findByFileContents( $filePath );
01722                 $mimeType = $mimeInfo['name'];
01723 
01724                 $newFilePath = $filePath;
01725                 $newSuffix = $suffix;
01726                 $contentVersion = eZContentObjectVersion::fetchVersion( $contentObjectAttributeData['version'],
01727                                                                         $contentObjectAttributeData['contentobject_id'] );
01728                 if ( $contentVersion )
01729                 {
01730                     $objectName = $this->imageName( $contentObjectAttributeData, $contentVersion );
01731                     $objectPathString = $this->imagePath( $contentObjectAttributeData, $contentVersion );
01732 
01733                     $newDirPath =  $objectPathString;
01734                     $newFileName = $objectName . '.' . $mimeInfo['suffix'];
01735                     $newSuffix = $mimeInfo['suffix'];
01736                     $newFilePath = $newDirPath . '/' . $newFileName;
01737                     $newBaseName = $objectName;
01738                 }
01739 
01740                 // VS-DBFILE : TODO checked
01741 
01742                 if ( $newFilePath != $filePath )
01743                 {
01744                     if ( !file_exists( $newDirPath ) )
01745                     {
01746                         //include_once( 'lib/ezfile/classes/ezdir.php' );
01747                         eZDir::mkdir( $newDirPath, eZDir::directoryPermission(), true );
01748                     }
01749                     eZFileHandler::copy( $filePath, $newFilePath );
01750 
01751                     // VS-DBFILE : TODO checked
01752 
01753                     //require_once( 'kernel/classes/ezclusterfilehandler.php' );
01754                     //$fileHandler = eZClusterFileHandler::instance();
01755                     //$fileHandler->fileCopy( $filePath, $newFilePath );
01756 
01757                     $filePath = $newFilePath;
01758                     $fileName = $newFileName;
01759                     $suffix = $newSuffix;
01760                     $dirPath = $newDirPath;
01761                     $baseName = $newBaseName;
01762                 }
01763             }
01764         }
01765         require_once( 'kernel/common/image.php' );
01766         $imageManager = imageInit();
01767 
01768         $mimeData = eZMimeType::findByFileContents( $fileName );
01769 
01770         $imageManager->analyzeImage( $mimeData );
01771 
01772         $imageNode->setAttribute( 'serial_number', false );
01773         $imageNode->setAttribute( 'is_valid', $isValid );
01774         $imageNode->setAttribute( 'filename', $fileName );
01775         $imageNode->setAttribute( 'suffix', $suffix );
01776         $imageNode->setAttribute( 'basename', $baseName );
01777         $imageNode->setAttribute( 'dirpath', $dirPath );
01778         $imageNode->setAttribute( 'url', $filePath );
01779         $imageNode->setAttribute( 'original_filename', $originalFileName );
01780         $imageNode->setAttribute( 'mime_type', $mimeType );
01781         $imageNode->setAttribute( 'width', $width );
01782         $imageNode->setAttribute( 'height', $height );
01783         $imageNode->setAttribute( 'alternative_text', $altText );
01784         $imageNode->setAttribute( 'alias_key', $imageManager->createImageAliasKey( $imageManager->alias( 'original' ) ) );
01785         $imageNode->setAttribute( 'timestamp', time() );
01786 
01787         $this->createImageInformationNode( $imageNode, $mimeData );
01788 
01789         $attr = false;
01790         $this->storeDOMTree( $doc, true, $attr );
01791 
01792 
01793         eZImageFile::appendFilepath( $contentObjectAttributeData['id'], $filePath );
01794     }
01795 
01796     /// \privatesection
01797     /// Contains a some eZContentObjectAttribute's attributes.
01798     public $ContentObjectAttributeData;
01799     /// Deprecated. Contains a reference to the object attribute
01800     public $ContentObjectAttribute;
01801 
01802 }
01803 ?>