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