Overview

Packages

  • admin
  • classes
    • media
  • CodeIgniter
    • Libraries
  • core
  • functions
  • JSMin
  • None
  • OpenID
  • PHP
  • PHPMailer
  • plugins
    • admin
    • development
    • feed
    • mail
    • media
    • misc
    • seo
    • spam
    • uploader
    • users
    • zenpage
    • zenphoto
      • news
  • Services
    • JSON

Classes

  • _zp_captcha
  • _zp_HTML_cache
  • admin_approval
  • Album
  • AlbumBase
  • AlbumZip
  • AMFReader
  • AMFStream
  • AnyFile
  • AnyFile_Options
  • Auth_OpenID
  • Auth_OpenID_AlreadySigned
  • Auth_OpenID_AssociateRequest
  • Auth_OpenID_Association
  • Auth_OpenID_AuthRequest
  • Auth_OpenID_AX
  • Auth_OpenID_AX_AttrInfo
  • Auth_OpenID_AX_Error
  • Auth_OpenID_AX_FetchRequest
  • Auth_OpenID_AX_FetchResponse
  • Auth_OpenID_AX_KeyValueMessage
  • Auth_OpenID_AX_Message
  • Auth_OpenID_AX_StoreRequest
  • Auth_OpenID_AX_StoreResponse
  • Auth_OpenID_BcMathWrapper
  • Auth_OpenID_CancelResponse
  • Auth_OpenID_CheckAuthRequest
  • Auth_OpenID_CheckIDRequest
  • Auth_OpenID_Consumer
  • Auth_OpenID_ConsumerResponse
  • Auth_OpenID_CryptUtil
  • Auth_OpenID_DatabaseConnection
  • Auth_OpenID_Decoder
  • Auth_OpenID_DiffieHellman
  • Auth_OpenID_DiffieHellmanSHA1ConsumerSession
  • Auth_OpenID_DiffieHellmanSHA1ServerSession
  • Auth_OpenID_DiffieHellmanSHA256ConsumerSession
  • Auth_OpenID_DiffieHellmanSHA256ServerSession
  • Auth_OpenID_DumbStore
  • Auth_OpenID_Encoder
  • Auth_OpenID_EncodingError
  • Auth_OpenID_Extension
  • Auth_OpenID_FailureResponse
  • Auth_OpenID_FileStore
  • Auth_OpenID_GenericConsumer
  • Auth_OpenID_GmpMathWrapper
  • Auth_OpenID_KVForm
  • Auth_OpenID_MalformedReturnURL
  • Auth_OpenID_MalformedTrustRoot
  • Auth_OpenID_Mapping
  • Auth_OpenID_MathLibrary
  • Auth_OpenID_MDB2Store
  • Auth_OpenID_MemcachedStore
  • Auth_OpenID_Message
  • Auth_OpenID_MySQLStore
  • Auth_OpenID_NamespaceMap
  • Auth_OpenID_NoReturnToError
  • Auth_OpenID_OpenIDStore
  • Auth_OpenID_PAPE_Request
  • Auth_OpenID_PAPE_Response
  • Auth_OpenID_Parse
  • Auth_OpenID_PlainTextConsumerSession
  • Auth_OpenID_PlainTextServerSession
  • Auth_OpenID_PostgreSQLStore
  • Auth_OpenID_Request
  • Auth_OpenID_Server
  • Auth_OpenID_ServerError
  • Auth_OpenID_ServerErrorContainer
  • Auth_OpenID_ServerRequest
  • Auth_OpenID_ServerResponse
  • Auth_OpenID_ServiceEndpoint
  • Auth_OpenID_ServiceEndpointLoader
  • Auth_OpenID_SessionNegotiator
  • Auth_OpenID_SetupNeededResponse
  • Auth_OpenID_Signatory
  • Auth_OpenID_SigningEncoder
  • Auth_OpenID_SQLiteStore
  • Auth_OpenID_SQLStore
  • Auth_OpenID_SRegBase
  • Auth_OpenID_SRegRequest
  • Auth_OpenID_SRegResponse
  • Auth_OpenID_SuccessResponse
  • Auth_OpenID_TrustRoot
  • Auth_OpenID_TypeURIMismatch
  • Auth_OpenID_UntrustedReturnURL
  • Auth_OpenID_WebResponse
  • Auth_Yadis_Discovery
  • Auth_Yadis_DiscoveryResult
  • Auth_Yadis_dom
  • Auth_Yadis_domxml
  • Auth_Yadis_HTTPFetcher
  • Auth_Yadis_HTTPResponse
  • Auth_Yadis_Manager
  • Auth_Yadis_ManagerLoader
  • Auth_Yadis_ParanoidHTTPFetcher
  • Auth_Yadis_ParseHTML
  • Auth_Yadis_PHPSession
  • Auth_Yadis_PlainHTTPFetcher
  • Auth_Yadis_ProxyResolver
  • Auth_Yadis_Service
  • Auth_Yadis_SessionLoader
  • Auth_Yadis_XMLParser
  • Auth_Yadis_XRDS
  • Auth_Yadis_Yadis
  • auto_backup
  • AVCSequenceParameterSetReader
  • bxslider
  • cacheManager
  • cacheManagerFeed
  • CI_jsmin
  • CI_load
  • cloneZenphoto
  • codeIgniter_kludge
  • colorbox
  • Comment
  • comment_form
  • contactformOptions
  • crop_image
  • cycle
  • defaultCodeblocks
  • deprecated_functions
  • DownloadList
  • dynamic_locale
  • dynamicAlbum
  • elFinder_options
  • email_new_user
  • exampleMacros
  • external_auth
  • ExternalFeed
  • externalFeed_options
  • favorites
  • favoritesOptions
  • federated_logon
  • feed
  • fieldExtender
  • flag_thumbnail
  • Gallery
  • galleryArticles
  • getID3
  • getid3_aac
  • getid3_apetag
  • getid3_flv
  • getid3_handler
  • getid3_id3v1
  • getid3_id3v2
  • getid3_lib
  • getid3_lyrics3
  • getid3_mp3
  • getid3_mpeg
  • getid3_quicktime
  • getid3_swf
  • GoogleMap
  • Googlemaps
  • googleVerifyOptions
  • hitcounter
  • HTML
  • htmlmetatags
  • http_auth
  • Image
  • image_effects
  • internal_deprecations
  • ipBlocker
  • jcarousel
  • jPlayer
  • jplayer_options
  • jquery_rating
  • JSMin
  • lib_GD_Options
  • lib_Imagick_Options
  • lib_NoGraphics
  • MediaObject
  • menu_manager
  • MergedRSS
  • MergedRSSOptions
  • mobile
  • Mobile_Detect
  • mobileTheme
  • multipleLayoutOptions
  • null_seo
  • OAuthConsumer
  • OAuthDataStore
  • OAuthRequest
  • OAuthServer
  • OAuthSignatureMethod
  • OAuthSignatureMethod_HMAC_SHA1
  • OAuthSignatureMethod_PLAINTEXT
  • OAuthSignatureMethod_RSA_SHA1
  • OAuthToken
  • OAuthUtil
  • pagedThumbsNav
  • pagedthumbsOptions
  • PclZip
  • PersistentObject
  • PHPMailer
  • PlainText
  • POP3
  • print_album_menu
  • pseudoPlayer
  • publishContent
  • quota_manager
  • reCaptcha
  • ReCaptchaResponse
  • register_user
  • rewriteRules
  • rewriteTokens
  • RSS
  • RSS_internal_deprecations
  • rss_options
  • search_statistics
  • SearchEngine
  • security_logger
  • seo_locale
  • Services_JSON
  • Services_JSON_Error
  • setupexternalFeed
  • setupRSS
  • show_not_loggedin
  • sitemap
  • slideshow
  • SMTP
  • static_html_cache
  • tagsuggest
  • TextObject
  • TextObject_internal_deprecations
  • TextObject_Options
  • ThemeObject
  • themeSwitcher
  • tinymce4Options
  • tinyURL
  • Transientimage
  • tweet
  • TwitterOAuth
  • UploadHandler
  • user_expiry
  • user_groups
  • user_logout_options
  • userAddressFields
  • utf8
  • Video
  • Video_internal_deprecations
  • VideoObject_Options
  • viewer_size_image_options
  • WEBdocs
  • WEBdocs_Options
  • xmpMetadata
  • Zenpage
  • Zenpage_internal_deprecations
  • ZenpageCategory
  • zenpagecms
  • ZenpageItems
  • ZenpageNews
  • ZenpagePage
  • ZenpageRoot
  • Zenphoto_Administrator
  • Zenphoto_Authority
  • zenphoto_org_news
  • zenphoto_seo
  • zenphotoDonate
  • ZipStream
  • zp_PHPMailer
  • zpCaptcha
  • zpFunctions
  • zpLegacySpam
  • zpMutex
  • zpSimpleSpam
  • zpTrivialSpam

Exceptions

  • BadFunctionCallException
  • BadMethodCallException
  • Exception
  • getid3_exception
  • JSMin_UnterminatedCommentException
  • JSMin_UnterminatedRegExpException
  • JSMin_UnterminatedStringException
  • LogicException
  • OAuthExcept
  • phpmailerException

Functions

  • __autoload
  • _escape_xref
  • _recaptcha_aes_encrypt
  • _recaptcha_aes_pad
  • _recaptcha_http_post
  • _recaptcha_mailhide_email_parts
  • _recaptcha_mailhide_urlbase64
  • _recaptcha_qsencode
  • accessAllAlbums
  • add_context
  • addalbumsToDatabase
  • addCategoriesToDatabase
  • addGeoCoord
  • addItem
  • addPagesToDatabase
  • addPluginScript
  • addPluginType
  • addSubalbumMenus
  • admin_album_list
  • admin_securityChecks
  • admin_showupdate
  • adminPageNav
  • adminToolbox
  • albumNumber
  • applyMacros
  • Auth_OpenID_arrangeByType
  • Auth_OpenID_AX_checkAlias
  • Auth_OpenID_AX_toTypeURIs
  • Auth_OpenID_bestMatchingService
  • Auth_OpenID_checkFieldName
  • Auth_OpenID_checkSessionType
  • Auth_OpenID_checkTimestamp
  • Auth_OpenID_detectMathLibrary
  • Auth_OpenID_discover
  • Auth_OpenID_discoverURI
  • Auth_OpenID_discoverWithoutYadis
  • Auth_OpenID_discoverWithYadis
  • Auth_OpenID_discoverXRI
  • Auth_OpenID_extractReturnURL
  • Auth_OpenID_findOPLocalIdentifier
  • Auth_OpenID_getAllAssociationTypes
  • Auth_OpenID_getAllowedReturnURLs
  • Auth_OpenID_getAuthorityPattern
  • Auth_OpenID_getAvailableSessionTypes
  • Auth_OpenID_getDefaultAssociationOrder
  • Auth_OpenID_getDefaultGen
  • Auth_OpenID_getDefaultMod
  • Auth_OpenID_getDefaultNegotiator
  • Auth_OpenID_getEncodedPattern
  • Auth_OpenID_getEncryptedNegotiator
  • Auth_OpenID_getEscapeRE
  • Auth_OpenID_getMathLib
  • Auth_OpenID_getOnlyEncryptedOrder
  • Auth_OpenID_getOpenIDConsumerTypeURIs
  • Auth_OpenID_getOpenIDTypeName
  • Auth_OpenID_getOpenIDTypeURIs
  • Auth_OpenID_getOPOrUserServices
  • Auth_OpenID_getSecretSize
  • Auth_OpenID_getSessionTypes
  • Auth_OpenID_getSupportedAssociationTypes
  • Auth_OpenID_getUnreserved
  • Auth_OpenID_getURIPattern
  • Auth_OpenID_getURLIllegalCharRE
  • Auth_OpenID_HMACSHA1
  • Auth_OpenID_HMACSHA256
  • Auth_OpenID_include_init
  • Auth_OpenID_isError
  • Auth_OpenID_isOpenID1
  • Auth_OpenID_legacy_discover
  • Auth_OpenID_makeOpenIDEndpoints
  • Auth_OpenID_math_extensions
  • Auth_OpenID_mkNonce
  • Auth_OpenID_noMathSupport
  • Auth_OpenID_pct_encoded_replace
  • Auth_OpenID_pct_encoded_replace_unreserved
  • Auth_OpenID_registerNamespaceAlias
  • Auth_OpenID_remove_dot_segments
  • Auth_OpenID_removeNamespaceAlias
  • Auth_OpenID_returnToMatches
  • Auth_OpenID_setNoMathSupport
  • Auth_OpenID_SHA1
  • Auth_OpenID_SHA256
  • Auth_OpenID_splitNonce
  • Auth_OpenID_supportsSReg
  • Auth_OpenID_urinorm
  • Auth_OpenID_verifyReturnTo
  • Auth_Yadis_array_scramble
  • Auth_Yadis_escapeForIRI
  • Auth_Yadis_getCanonicalID
  • Auth_Yadis_getDefaultProxy
  • Auth_Yadis_getEscapeRE
  • Auth_Yadis_getIPrivateChars
  • Auth_Yadis_getNSMap
  • Auth_Yadis_getServiceEndpoints
  • Auth_Yadis_getSupportedExtensions
  • Auth_Yadis_getUCSChars
  • Auth_Yadis_getXMLParser
  • Auth_Yadis_getXRDExpiration
  • Auth_Yadis_getXrefRE
  • Auth_Yadis_getXRIAuthorities
  • Auth_Yadis_identifierScheme
  • Auth_Yadis_iriToURI
  • Auth_Yadis_pct_escape_unicode
  • Auth_Yadis_providerIsAuthoritative
  • Auth_Yadis_rootAuthority
  • Auth_Yadis_setDefaultParser
  • Auth_Yadis_startswith
  • Auth_Yadis_toIRINormal
  • Auth_Yadis_toURINormal
  • Auth_Yadis_XRI
  • Auth_Yadis_XRIAppendArgs
  • authorSelector
  • build_query
  • build_url
  • bulkActionRedirect
  • bulkTags
  • byteConvert
  • cacheImage
  • checkAccess
  • checkAlbumimagesort
  • checkAlbumParentid
  • checkAlbumPassword
  • checkChosenItemStatus
  • checkChosenMenuset
  • checked
  • checkFolder
  • checkForEmptyTitle
  • checkForGuest
  • checkForPage
  • checkForPassword
  • checkForUpdate
  • checkHitcounterDisplay
  • checkIfChecked
  • checkIfLockedNews
  • checkIfLockedPage
  • checkIfNew
  • checkInstall
  • checkLayoutUseForImages
  • checkNewsAccess
  • checkNewsCategoryPassword
  • checkObjectsThumb
  • checkPagePassword
  • checkPageValidity
  • checkParentLayouts
  • checkPublishDates
  • checkRequiredField
  • checkSelectedAlbum
  • checkSignature
  • cleanAlbum
  • cleanHTML
  • clearSitemapCache
  • clonedFrom
  • codeblocktabsJS
  • comment_form_addComment
  • comment_form_handle_comment
  • comment_form_PaginationJS
  • comment_form_postcomment
  • comment_form_print10Most
  • comment_form_visualEditor
  • commentFormUseCaptcha
  • commentReply
  • commentsAllowed
  • consolidatedEditMessages
  • copyLayoutSelection
  • copyThemeDirectory
  • countArticles
  • countCombiNews
  • createMenuIfNotExists
  • createRelatedItemsResultArray
  • cron_starter
  • currentRelativeURL
  • customOptions
  • dateDiff
  • datepickerJS
  • dateTimeConvert
  • db_affected_rows
  • db_close
  • db_collation
  • db_connect
  • db_count
  • db_create
  • db_create_table
  • db_error
  • db_fetch_assoc
  • db_fetch_row
  • db_free_result
  • db_getSQLmode
  • db_insert_id
  • db_LIKE_escape
  • db_list_fields
  • db_name
  • db_num_rows
  • db_permissions
  • db_quote
  • db_setSQLmode
  • db_show
  • db_software
  • db_table_update
  • db_truncate_table
  • debug404
  • debugLog
  • debugLogBacktrace
  • debugLogVar
  • defaultCodeblocks_codebox
  • deleteArticle
  • deleteCategory
  • deleteItem
  • deleteLayoutSelection
  • deletePage
  • deleteThemeDirectory
  • detect_fetcher
  • detect_math
  • detect_query_corruption
  • detect_random
  • detect_stores
  • detect_xml
  • dircopy
  • displayError
  • doIncludes
  • elFinder_admin_tabs
  • elFinder_tinymce
  • enableExtension
  • escape
  • executeRSS
  • exitZP
  • exposeZenPhotoInformations
  • extensionEnabled
  • fetchComments
  • filesystemToInternal
  • filter_extractReturnURL
  • filter_MatchesAnyOpenIDConsumerType
  • filter_MatchesAnyOpenIDType
  • filterImageQuery
  • fix_path_redirect
  • formatList
  • fullText
  • galleryAlbumsPerPage
  • genAlbumList
  • generateCaptcha
  • generateLanguageList
  • generateListFromArray
  • generateListFromFiles
  • generateRadiobuttonsFromArray
  • generateSitemapCacheFile
  • generateSitemapIndexCacheFile
  • generateUnorderedListFromArray
  • get_AnyFile_suffixes
  • get_context
  • get_filterScript
  • get_instance
  • get_language_string
  • getAdminThumb
  • getAlbumArray
  • getAlbumBreadcrumb
  • getAlbumBreadcrumbAdmin
  • getAlbumCustomData
  • getAlbumData
  • getAlbumDate
  • getAlbumDesc
  • getAlbumFolder
  • getAlbumGeodata
  • getAlbumId
  • getAlbumInherited
  • getAlbumLinkURL
  • getAlbumLocation
  • getAlbumPage
  • getAlbumPlace
  • getAlbumStatistic
  • getAlbumThumb
  • getAlbumTitle
  • getAlbumURL
  • getAllAccessibleAlbums
  • getAllAlbums
  • getAllArticleDates
  • getAllCategories
  • getAllDates
  • getAllowedTags
  • getAllSubAlbumIDs
  • getAllSubalbums
  • getAllTagsCount
  • getAllTagsFromAlbum
  • getAllTagsFromAlbum_multi_unique
  • getAllTagsFromZenpage
  • getAllTagsUnique
  • getAllTranslations
  • getAnnotatedAlbumTitle
  • getAnnotatedImageTitle
  • getArticles
  • getAuthor
  • getBare
  • getBareAlbumDesc
  • getBareAlbumTitle
  • getBareGalleryDesc
  • getBareGalleryTitle
  • getBareImageDesc
  • getBareImageTitle
  • getBareNewsAlbumTitle
  • getBareNewsTitle
  • getBarePageTitle
  • getCategory
  • getCategoryID
  • getCategoryLink
  • getCategoryParentID
  • getCategorySortOrder
  • getCategoryTitle
  • getCheckboxState
  • getCodeblock
  • getCombiNews
  • getCommentAddress
  • getCommentAuthorEmail
  • getCommentAuthorLink
  • getCommentAuthorName
  • getCommentAuthorSite
  • getCommentBody
  • getCommentCount
  • getCommentDate
  • getCommentDateTime
  • getCommentErrors
  • getCommentsAllowed
  • getCommentStored
  • getCommentTime
  • getConsumer
  • getContentShorten
  • getCurrentMenuItem
  • getCurrentNewsArchive
  • getCurrentNewsCategory
  • getCurrentNewsCategoryID
  • getCurrentNewsCategoryParentID
  • getCurrentNewsPage
  • getCurrentPage
  • getCurrentTheme
  • getCustomAlbumThumb
  • getCustomAlbumThumbMaxSpace
  • getCustomImageURL
  • getCustomPageURL
  • getCustomSizedImageMaxSpace
  • getCustomSizedImageThumbMaxSpace
  • getDefaultHeight
  • getDefaultSizedImage
  • getDefaultWidth
  • getDownloadLink
  • getdownloadList
  • getDownloadURL
  • getE
  • getEnabledPlugins
  • getExpiryDatePost
  • getFavoritesURL
  • getField
  • getFirstImageURL
  • getFullHeight
  • getFullImageURL
  • getFullNewsImage
  • getFullWidth
  • getGalleryDesc
  • getGalleryIndexURL
  • getGalleryTitle
  • getGeoCoord
  • getHeadTitle
  • getHitcounter
  • getImageArgs
  • getImageCacheFilename
  • getImageCachePostfix
  • getImageCity
  • getImageCountry
  • getImageCustomData
  • getImageData
  • getImageDate
  • getImageDesc
  • getImageEXIFData
  • getImageGeodata
  • getImageID
  • getImageLinkURL
  • getImageLocation
  • getImageMetaData
  • getImageParameters
  • getImageProcessorURI
  • getImageProcessorURIFromCacheName
  • getImageRotation
  • getImageSortOrder
  • getImageState
  • getImageStatistic
  • getImageThumb
  • getImageTitle
  • getImageURI
  • getImageURL
  • getItem
  • getItemByID
  • getItemTitleAndURL
  • getjPlayerSkinCSS
  • getjPlayerSkins
  • getLanguageArray
  • getLanguageFlag
  • getLastImageURL
  • getLatestComments
  • getLatestNews
  • getLatestZenpageComments
  • getLayout
  • getLayoutSelector
  • getLink
  • getLinkHTML
  • getLogTabs
  • getMacros
  • getMainSiteName
  • getMainSiteURL
  • getManagedAlbumList
  • getMaxSpaceContainer
  • getMenuFromLink
  • getMenuItemChilds
  • getMenuItems
  • getMenumanagerPredicessor
  • getMenumanagerSuccessor
  • getMenuSetSelector
  • getMenuVisibility
  • getMimeString
  • getNestedAlbumList
  • getNewsAdminOption
  • getNewsAdminOptionPath
  • getNewsAlbumName
  • getNewsAlbumTitle
  • getNewsAlbumURL
  • getNewsArchivePath
  • getNewsArchiveURL
  • getNewsAuthor
  • getNewsCategories
  • getNewsCategoryCustomData
  • getNewsCategoryDesc
  • getNewsCategoryPath
  • getNewsCategoryURL
  • getNewsContent
  • getNewsContentShorten
  • getNewsCustomData
  • getNewsDate
  • getNewsExtraContent
  • getNewsID
  • getNewsImageTags
  • getNewsIndexURL
  • getNewsLink
  • getNewsPagesStatistic
  • getNewsPathNav
  • getNewsReadMore
  • getNewsTitle
  • getNewsTitleLink
  • getNewsTitlePath
  • getNewsType
  • getNewsURL
  • getNewsVideoContent
  • getNextAlbum
  • getNextAlbumURL
  • getNextImageThumb
  • getNextImageURL
  • getNextNewsPageURL
  • getNextNewsURL
  • getNextPageURL
  • getNextPrevNews
  • getNotViewableAlbums
  • getNotViewableImages
  • getNumAlbums
  • getNumAllSubalbums
  • getNumImages
  • getNumNews
  • getNumPages
  • getNumSubalbums
  • getOpenIDURL
  • getOption
  • getOptionFromDB
  • getOptionList
  • getPageAuthor
  • getPageContent
  • getPageCustomData
  • getPageDate
  • getPageExtraContent
  • getPageID
  • getPageLastChangeDate
  • getPageLinkPath
  • getPageLinkURL
  • getPageNavList
  • getPageNumURL
  • getPageParentID
  • getPageRedirect
  • getPages
  • getPageSelector
  • getPageSortorder
  • getPageTitle
  • getPageTitleLink
  • getPageURL
  • getParentAlbums
  • getParentAlbumsAdmin
  • getParentBreadcrumb
  • getParentItems
  • getParentMenuItems
  • getParentNewsCategories
  • getParentPages
  • getPasswordProtectImage
  • getPHPFiles
  • getPlugin
  • getPluginFiles
  • getPluginTabs
  • getPrevAlbum
  • getPrevAlbumURL
  • getPrevImageThumb
  • getPrevImageURL
  • getPrevNewsPageURL
  • getPrevNewsURL
  • getPrevPageURL
  • getProtectedImageURL
  • getRandomImages
  • getRandomImagesAlbum
  • getRating
  • getRelatedItems
  • getRequestURI
  • getReturnTo
  • getRSSHeaderLink
  • getRSSLink
  • getScheme
  • getSearchDate
  • getSearchURL
  • getSearchWords
  • getSelectedLayout
  • getSerializedArray
  • getSetClause
  • getSiteHomeURL
  • getSitemapAlbumList
  • getSitemapAlbums
  • getSitemapGoogleImageVideoExtras
  • getSitemapGoogleLoopIndex
  • getSitemapImages
  • getSitemapIndexLinks
  • getSitemapZenpageNewsArticles
  • getSitemapZenpageNewsCategories
  • getSitemapZenpageNewsIndex
  • getSitemapZenpagePages
  • getSizeCustomImage
  • getSizeDefaultImage
  • getSizeDefaultThumb
  • getSizedImageURL
  • getSizeFullImage
  • getStore
  • getSubCategories
  • getSubtabs
  • getSuffix
  • getTagCountByAccess
  • getTagOrder
  • getTags
  • gettext_pl
  • gettext_th
  • getTheme
  • getThemeFiles
  • getThemeOption
  • getTimezones
  • getTinyMCE4ConfigFiles
  • getTitle
  • getTotalArticles
  • getTotalImagesIn
  • getTotalNewsPages
  • getTotalPages
  • getTrustRoot
  • getUnprotectedImageURL
  • getUrAlbum
  • getURL
  • getUserIP
  • getUserLocale
  • getVersion
  • getViewerImageSize
  • getWatermarkParam
  • getWatermarkPath
  • getWatermarks
  • getWhereClause
  • getXSRFToken
  • getZenpageHitcounter
  • getZenpageRSSHeaderLink
  • getZenpageRSSLink
  • getZenpageStatistic
  • googleVerifyHead
  • handleSearchParms
  • hasDynamicAlbumSuffix
  • hasNextImage
  • hasNextPage
  • hasPrevImage
  • hasPrevPage
  • hitcounter
  • html_decode
  • html_encode
  • html_encodeTagged
  • httpsRedirect
  • httpUploadHandler
  • httpUploadHandler_admin_tabs
  • i18nSetLocale
  • imageBlurGD
  • imageDebug
  • imageError
  • imageNumber
  • imgSrcURI
  • in_context
  • inNewsCategory
  • inProtectedNewsCategory
  • installSignature
  • instrument
  • inSubNewsCategoryOf
  • internalToFilesystem
  • inventMenuItem
  • iptc_make_tag
  • is_AdminEditPage
  • is_connected
  • is_GalleryNewsType
  • is_News
  • is_NewsArchive
  • is_NewsArticle
  • is_NewsCategory
  • is_NewsPage
  • is_NewsType
  • is_Pages
  • is_valid_email_zp
  • is_valid_image
  • is_valid_other_type
  • is_zip
  • isAlbumClass
  • isAlbumPage
  • isArchive
  • isHandledAlbum
  • isImageClass
  • isImagePage
  • isImagePhoto
  • isImageVideo
  • isLandscape
  • isMyAlbum
  • isMyNews
  • isMyPage
  • isolate
  • isProtectedAlbum
  • isProtectedNewsCategory
  • isProtectedPage
  • isSubNewsCategoryOf
  • isValidURL
  • jQueryUpload_head
  • jQueryUpload_headers
  • jQueryUploadHandler
  • jQueryUploadHandler_admin_tabs
  • js_encode
  • json_decode
  • json_encode
  • kses
  • kses_array_lc
  • kses_attr
  • kses_bad_protocol
  • kses_bad_protocol_once
  • kses_bad_protocol_once2
  • kses_check_attr_val
  • kses_decode_entities
  • kses_hair
  • kses_hook
  • kses_html_error
  • kses_js_entities
  • kses_no_null
  • kses_normalize_entities
  • kses_normalize_entities2
  • kses_split
  • kses_split2
  • kses_stripslashes
  • kses_version
  • ksesProcess
  • layoutSelector
  • layoutSelector_album
  • listDBUses
  • listDirectoryFiles
  • listUses
  • load_zenpage_news
  • load_zenpage_pages
  • loadLocalOptions
  • log_message
  • lookupSortKey
  • macro_admin_tabs
  • macroList_show
  • makeAlbumCurrent
  • makeImageCurrent
  • makeSpecialImageName
  • markRelease_button
  • mb_strlen
  • mb_strpos
  • mb_strrpos
  • mb_strtolower
  • mb_strtoupper
  • mb_substr
  • mb_substr_count
  • menu_admin_toolbox_global
  • menu_tabs
  • minDiff
  • mkdir_recursive
  • my_truncate_string
  • myts_date
  • newAlbum
  • newImage
  • next_album
  • next_comment
  • next_image
  • next_news
  • next_page
  • ngettext_pl
  • ngettext_th
  • normalizeColumns
  • omsAdditions
  • openedForComments
  • parse_query
  • parse_size
  • parseAllowedTags
  • parseHttpAcceptLanguage
  • passAlbums
  • passImages
  • pathurlencode
  • PclZipUtilCopyBlock
  • PclZipUtilOptionText
  • PclZipUtilPathInclusion
  • PclZipUtilPathReduction
  • PclZipUtilRename
  • PclZipUtilTranslateWinPath
  • PHPMailerAutoload
  • populateManagedObjectsList
  • postAlbumSort
  • postIndexDecode
  • postIndexEncode
  • prefix
  • prepareAlbumPage
  • prepareCustomPage
  • prepareImagePage
  • prepareIndexPage
  • print404status
  • print_language_string_list
  • printAddToFavorites
  • printAdminFooter
  • printAdminHeader
  • printAdminRightsTable
  • printAdminToolbox
  • printAlbumBreadcrumb
  • printAlbumButtons
  • printAlbumCustomData
  • printAlbumData
  • printAlbumDate
  • printAlbumDesc
  • printAlbumEditForm
  • printAlbumEditRow
  • printAlbumLegend
  • printAlbumLink
  • printAlbumLocation
  • printAlbumMap
  • printAlbumMenu
  • printAlbumMenuJump
  • printAlbumMenuList
  • printAlbumMenuListAlbum
  • printAlbumPlace
  • printAlbumRating
  • printAlbumsSelector
  • printAlbumStatistic
  • printAlbumStatisticItem
  • printAlbumThumbImage
  • printAlbumTitle
  • printAlbumURL
  • printAlbumZip
  • printAllDates
  • printAllNewsCategories
  • printAllTags
  • printAllTagsAs
  • printAllTagsFromAlbum
  • printAllTagsFromZenpage
  • printAnnotatedAlbumTitle
  • printAnnotatedImageTitle
  • printArticleCategories
  • printArticleDatesDropdown
  • printArticlesPerPageDropdown
  • printBareAlbumDesc
  • printBareAlbumTitle
  • printBareGalleryDesc
  • printBareGalleryTitle
  • printBareImageDesc
  • printBareImageTitle
  • printBareNewsTitle
  • printBarePageTitle
  • printBulkActions
  • printCaptcha
  • printCategoriesStatistic
  • printCategoryCheckboxListEntry
  • printCategoryDropdown
  • printCategoryListSortableTable
  • printCategorySelection
  • printCodeblock
  • printCodeblockEdit
  • printCommentAuthorLink
  • printCommentErrors
  • printCommentForm
  • printContactForm
  • printCurrentNewsArchive
  • printCurrentNewsCategory
  • printCustomAlbumThumbImage
  • printCustomAlbumThumbMaxSpace
  • printCustomMenu
  • printCustomPageSelector
  • printCustomPageURL
  • printCustomSizedImage
  • printCustomSizedImageMaxHeight
  • printCustomSizedImageMaxSpace
  • printCustomSizedImageThumbMaxSpace
  • printDefaultSizedImage
  • printDownloadAlbumZipURL
  • printDownloadLink
  • printDownloadLinkAlbumZip
  • printdownloadList
  • printDownloadURL
  • printEditable
  • printEditCommentLink
  • printEditDropdown
  • printExpired
  • printFavoritesLink
  • printFavoritesURL
  • printField
  • printGalleryDesc
  • printGalleryIndexURL
  • printGalleryTitle
  • printGoogleMap
  • printHeadTitle
  • printHomeLink
  • printImageCustomData
  • printImageData
  • printImageDate
  • printImageDesc
  • printImageDiv
  • printImageEXIFData
  • printImageID
  • printImageLink
  • printImageMap
  • printImageMetadata
  • printImageRating
  • printImageSortOrder
  • printImageStatistic
  • printImageThumb
  • printImageTitle
  • printImageURL
  • printItemEditLink
  • printItemsList
  • printItemsListTable
  • printItemStatusDropdown
  • printjCarouselThumbNav
  • printjPlayerPlaylist
  • printLanguageSelector
  • printLatestAlbums
  • printLatestComments
  • printLatestImages
  • printLatestImagesByDate
  • printLatestImagesByMtime
  • printLatestNews
  • printLatestUpdatedAlbums
  • printLatestZenpageComments
  • printLink
  • printLinkHTML
  • printLogoAndLinks
  • printManagedObjects
  • printMenuemanagerPageList
  • printMenuemanagerPageListWithNav
  • printMenumanagerBreadcrumb
  • printMenumanagerNextLink
  • printMenumanagerPrevLink
  • printMostPopularItems
  • printMostRatedAlbums
  • printMostRatedImages
  • printMostRatedItems
  • printNestedAlbumsList
  • printNestedItemsList
  • printNestedMenu
  • printNews
  • printNewsArchive
  • printNewsAuthor
  • printNewsCategories
  • printNewsCategoryCustomData
  • printNewsCategoryDesc
  • printNewsCategoryURL
  • printNewsContent
  • printNewsCustomData
  • printNewsDate
  • printNewsExtraContent
  • printNewsImageTags
  • printNewsIndexURL
  • printNewsLink
  • printNewsPageList
  • printNewsPageListWithNav
  • printNewsReadMoreLink
  • printNewsStatistic
  • printNewsTitle
  • printNewsTitleLink
  • printNewsURL
  • printNextNewsLink
  • printNextNewsPageLink
  • printNextPageLink
  • printNextPageURL
  • printPageArticleTags
  • printPageAuthor
  • printPageContent
  • printPageCustomData
  • printPageDate
  • printPagedThumbsNav
  • printPageExtraContent
  • printPageID
  • printPageLastChangeDate
  • printPageLinkURL
  • printPageList
  • printPageListWithNav
  • printPageMenu
  • printPageNav
  • printPageSelector
  • printPagesListTable
  • printPagesStatistic
  • printPageTitle
  • printPageTitleLink
  • printPageURL
  • printParentBreadcrumb
  • printParentPagesBreadcrumb
  • printPasswordForm
  • printPopularAlbums
  • printPopularImages
  • printPreloadScript
  • printPrevNewsLink
  • printPrevNewsPageLink
  • printPrevPageLink
  • printPrevPageURL
  • printPublished
  • printPublishIconLink
  • printRandomImages
  • printRating
  • printRegisterURL
  • printRegistrationForm
  • printRelatedItems
  • printRSSHeaderLink
  • printRSSLink
  • printSearchBreadcrumb
  • printSearchForm
  • printSiteHomeURL
  • printSizedImageLink
  • printSizedImageURL
  • printSlideShow
  • printSlideShowJS
  • printSlideShowLink
  • printSortableHead
  • printSortOrderDropdown
  • printSubPagesExcerpts
  • printSubtabs
  • printTabs
  • printTags
  • printThumbNav
  • printTopRatedAlbums
  • printTopRatedImages
  • printTopRatedItems
  • printUnpublishedDropdown
  • printUserLogin_out
  • printUserSizeImage
  • printUserSizeSelector
  • printVersion
  • printZenJavascripts
  • printZenpageIconLegend
  • printZenpageItemsBreadcrumb
  • printZenpageNewsCategorySelector
  • printZenpagePagesSelector
  • printZenpageRSSHeaderLink
  • printZenpageRSSLink
  • printZenpageStatistic
  • printZenphotoLink
  • process_language_string_save
  • processAlbumBulkActions
  • processAlbumEdit
  • processCodeblockSave
  • processCommentBulkActions
  • processCredentials
  • processCustomOptionSave
  • processEditSelection
  • processExpired
  • processImageBulkActions
  • processImageEdit
  • processManagedObjects
  • processMenuBulkActions
  • processOrder
  • processRights
  • processTags
  • processZenpageBulkActions
  • propSizes
  • publishItem
  • purgeOption
  • query
  • query_full_array
  • query_single_row
  • rc4
  • read_exif_data_protected
  • readTags
  • recaptcha_check_answer
  • recaptcha_get_html
  • recaptcha_get_signup_url
  • recaptcha_mailhide_html
  • recaptcha_mailhide_url
  • reconfigureAction
  • reconfigureCS
  • reconfigurePage
  • recordMissing
  • rem_context
  • removeParentAlbumNames
  • resetCurrentAlbum
  • restore_context
  • reveal
  • rewrite_get_album_image
  • rewrite_path
  • rewrite_path_zenpage
  • RSS_Channel
  • RSS_Retrieve
  • RSS_Tags
  • rulesList
  • run
  • safe_fnmatch
  • safe_glob
  • sanitize
  • sanitize_numeric
  • sanitize_path
  • sanitize_script
  • sanitize_string
  • sanitizeRedirect
  • save_context
  • saveLayoutSelection
  • saveZenphotoLayoutSelection
  • search_quote
  • secureServer
  • seo_cleanup_button
  • seoFriendly
  • seoFriendlyJS
  • set_context
  • setAlbumCustomData
  • setAlbumSubtabs
  • setImageCustomData
  • setMainDomain
  • setOption
  • setOptionDefault
  • setPluginDomain
  • setThemeColumns
  • setThemeDomain
  • setThemeOption
  • setThemeOptionDefault
  • setupAllowedMaps
  • setupCurrentLocale
  • setupDomain
  • setupTheme
  • shortenContent
  • showOrNotShowField
  • shuffle_assoc
  • signatureChange
  • site_upgrade_button
  • site_upgrade_status
  • sitemap_echonl
  • sitemap_getChangefreq
  • sitemap_getDateformat
  • sitemap_getDBLimit
  • sitemap_getISO8601Date
  • skipScheduledPublishing
  • sortByKey
  • sortByMultilingual
  • sortMultiArray
  • standardScripts
  • standardThemeOptions
  • stickyNews
  • storeConfig
  • storeTags
  • stripSuffix
  • submenuOf
  • switchLog
  • tagSelector
  • tagSuggestJS
  • tagSuggestJS_admin
  • tagSuggestJS_frontend
  • themeIsEditable
  • themeSetup
  • timezoneDiff
  • tinymce4ConfigJS
  • truncate_string
  • unpublishedZenphotoItemCheck
  • unpublishSubalbums
  • unQuote
  • unzip
  • updateArticle
  • updateCacheName
  • updateCategory
  • updateConfigItem
  • updateItemSortorder
  • updateItemsSortorder
  • updateMenuItem
  • updatePage
  • upload_extra
  • upload_form
  • upload_head
  • user_mailing_list_button
  • validateLocale
  • wordpress_import_button
  • wp_prefix
  • wp_query_full_array
  • wpimport_TryAgainError
  • XSRFdefender
  • XSRFToken
  • zenJavascript
  • zenpageAlbumImage
  • zenpageBulkActionMessage
  • zenpageHitcounter
  • zenpageJSCSS
  • zenpageOpenedForComments
  • zenpagePublish
  • zenphoto_PHPMailer
  • zenphoto_sendmail
  • zenPhotoTheme
  • zp_apply_filter
  • zp_clearCookie
  • zp_colorAllocate
  • zp_cookieEncode
  • zp_copyCanvas
  • zp_createImage
  • zp_drawRectangle
  • zp_error
  • zp_filter_slot
  • zp_filter_unique_id
  • zp_getCookie
  • zp_getFonts
  • zp_graphicsLibInfo
  • zp_handle_password
  • zp_handle_password_single
  • zp_has_filter
  • zp_image_types
  • zp_imageCanRotate
  • zp_imageColorTransparent
  • zp_imageDims
  • zp_imageFill
  • zp_imageFontHeight
  • zp_imageFontWidth
  • zp_imageFromString
  • zp_imageGet
  • zp_imageGray
  • zp_imageHeight
  • zp_imageIPTC
  • zp_imageKill
  • zp_imageLoadFont
  • zp_imageMerge
  • zp_imageOutput
  • zp_imageResizeAlpha
  • zp_imageUnsharpMask
  • zp_imageWidth
  • zp_load_album
  • zp_load_gallery
  • zp_load_image
  • zp_load_page
  • zp_load_request
  • zp_load_search
  • zp_loggedin
  • zp_mail
  • zp_register_filter
  • zp_remove_filter
  • zp_resampleImage
  • zp_rotateImage
  • zp_session_start
  • zp_setCookie
  • zp_writeString
  • zpErrorHandler
  • zpFormattedDate
  • zpRewriteURL
  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
   1: <?php
   2: /////////////////////////////////////////////////////////////////
   3: /// getID3() by James Heinrich <info@getid3.org>               //
   4: //  available at http://getid3.sourceforge.net                 //
   5: //            or http://www.getid3.org                         //
   6: //          also https://github.com/JamesHeinrich/getID3       //
   7: /////////////////////////////////////////////////////////////////
   8: //                                                             //
   9: // Please see readme.txt for more information                  //
  10: //                                                            ///
  11: /////////////////////////////////////////////////////////////////
  12: 
  13: // define a constant rather than looking up every time it is needed
  14: if (!defined('GETID3_OS_ISWINDOWS')) {
  15:     define('GETID3_OS_ISWINDOWS', (stripos(PHP_OS, 'WIN') === 0));
  16: }
  17: // Get base path of getID3() - ONCE
  18: if (!defined('GETID3_INCLUDEPATH')) {
  19:     define('GETID3_INCLUDEPATH', dirname(__FILE__).DIRECTORY_SEPARATOR);
  20: }
  21: // Workaround Bug #39923 (https://bugs.php.net/bug.php?id=39923)
  22: if (!defined('IMG_JPG') && defined('IMAGETYPE_JPEG')) {
  23:     define('IMG_JPG', IMAGETYPE_JPEG);
  24: }
  25: 
  26: // attempt to define temp dir as something flexible but reliable
  27: $temp_dir = ini_get('upload_tmp_dir');
  28: if ($temp_dir && (!is_dir($temp_dir) || !is_readable($temp_dir))) {
  29:     $temp_dir = '';
  30: }
  31: if (!$temp_dir && function_exists('sys_get_temp_dir')) { // sys_get_temp_dir added in PHP v5.2.1
  32:     // sys_get_temp_dir() may give inaccessible temp dir, e.g. with open_basedir on virtual hosts
  33:     $temp_dir = sys_get_temp_dir();
  34: }
  35: $temp_dir = @realpath($temp_dir); // see https://github.com/JamesHeinrich/getID3/pull/10
  36: $open_basedir = ini_get('open_basedir');
  37: if ($open_basedir) {
  38:     // e.g. "/var/www/vhosts/getid3.org/httpdocs/:/tmp/"
  39:     $temp_dir     = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $temp_dir);
  40:     $open_basedir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $open_basedir);
  41:     if (substr($temp_dir, -1, 1) != DIRECTORY_SEPARATOR) {
  42:         $temp_dir .= DIRECTORY_SEPARATOR;
  43:     }
  44:     $found_valid_tempdir = false;
  45:     $open_basedirs = explode(PATH_SEPARATOR, $open_basedir);
  46:     foreach ($open_basedirs as $basedir) {
  47:         if (substr($basedir, -1, 1) != DIRECTORY_SEPARATOR) {
  48:             $basedir .= DIRECTORY_SEPARATOR;
  49:         }
  50:         if (preg_match('#^'.preg_quote($basedir).'#', $temp_dir)) {
  51:             $found_valid_tempdir = true;
  52:             break;
  53:         }
  54:     }
  55:     if (!$found_valid_tempdir) {
  56:         $temp_dir = '';
  57:     }
  58:     unset($open_basedirs, $found_valid_tempdir, $basedir);
  59: }
  60: if (!$temp_dir) {
  61:     $temp_dir = '*'; // invalid directory name should force tempnam() to use system default temp dir
  62: }
  63: // $temp_dir = '/something/else/';  // feel free to override temp dir here if it works better for your system
  64: if (!defined('GETID3_TEMP_DIR')) {
  65:     define('GETID3_TEMP_DIR', $temp_dir);
  66: }
  67: unset($open_basedir, $temp_dir);
  68: 
  69: // End: Defines
  70: 
  71: 
  72: class getID3
  73: {
  74:     // public: Settings
  75:     public $encoding        = 'UTF-8';        // CASE SENSITIVE! - i.e. (must be supported by iconv()). Examples:  ISO-8859-1  UTF-8  UTF-16  UTF-16BE
  76:     public $encoding_id3v1  = 'ISO-8859-1';   // Should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'EUC-CN' or 'CP1252'
  77: 
  78:     // public: Optional tag checks - disable for speed.
  79:     public $option_tag_id3v1         = true;  // Read and process ID3v1 tags
  80:     public $option_tag_id3v2         = true;  // Read and process ID3v2 tags
  81:     public $option_tag_lyrics3       = true;  // Read and process Lyrics3 tags
  82:     public $option_tag_apetag        = true;  // Read and process APE tags
  83:     public $option_tags_process      = true;  // Copy tags to root key 'tags' and encode to $this->encoding
  84:     public $option_tags_html         = true;  // Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities
  85: 
  86:     // public: Optional tag/comment calucations
  87:     public $option_extra_info        = true;  // Calculate additional info such as bitrate, channelmode etc
  88: 
  89:     // public: Optional handling of embedded attachments (e.g. images)
  90:     public $option_save_attachments  = true; // defaults to true (ATTACHMENTS_INLINE) for backward compatibility
  91: 
  92:     // public: Optional calculations
  93:     public $option_md5_data          = false; // Get MD5 sum of data part - slow
  94:     public $option_md5_data_source   = false; // Use MD5 of source file if availble - only FLAC and OptimFROG
  95:     public $option_sha1_data         = false; // Get SHA1 sum of data part - slow
  96:     public $option_max_2gb_check     = null;  // Check whether file is larger than 2GB and thus not supported by 32-bit PHP (null: auto-detect based on PHP_INT_MAX)
  97: 
  98:     // public: Read buffer size in bytes
  99:     public $option_fread_buffer_size = 32768;
 100: 
 101:     // Public variables
 102:     public $filename;                         // Filename of file being analysed.
 103:     public $fp;                               // Filepointer to file being analysed.
 104:     public $info;                             // Result array.
 105:     public $tempdir = GETID3_TEMP_DIR;
 106:     public $memory_limit = 0;
 107: 
 108:     // Protected variables
 109:     protected $startup_error   = '';
 110:     protected $startup_warning = '';
 111: 
 112:     const VERSION           = '1.9.10-201511170924';
 113:     const FREAD_BUFFER_SIZE = 32768;
 114: 
 115:     const ATTACHMENTS_NONE   = false;
 116:     const ATTACHMENTS_INLINE = true;
 117: 
 118:     // public: constructor
 119:     public function __construct() {
 120: 
 121:         // Check for PHP version
 122:         $required_php_version = '5.3.0';
 123:         if (version_compare(PHP_VERSION, $required_php_version, '<')) {
 124:             $this->startup_error .= 'getID3() requires PHP v'.$required_php_version.' or higher - you are running v'.PHP_VERSION;
 125:             return false;
 126:         }
 127: 
 128:         // Check memory
 129:         $this->memory_limit = ini_get('memory_limit');
 130:         if (preg_match('#([0-9]+)M#i', $this->memory_limit, $matches)) {
 131:             // could be stored as "16M" rather than 16777216 for example
 132:             $this->memory_limit = $matches[1] * 1048576;
 133:         } elseif (preg_match('#([0-9]+)G#i', $this->memory_limit, $matches)) { // The 'G' modifier is available since PHP 5.1.0
 134:             // could be stored as "2G" rather than 2147483648 for example
 135:             $this->memory_limit = $matches[1] * 1073741824;
 136:         }
 137:         if ($this->memory_limit <= 0) {
 138:             // memory limits probably disabled
 139:         } elseif ($this->memory_limit <= 4194304) {
 140:             $this->startup_error .= 'PHP has less than 4MB available memory and will very likely run out. Increase memory_limit in php.ini';
 141:         } elseif ($this->memory_limit <= 12582912) {
 142:             $this->startup_warning .= 'PHP has less than 12MB available memory and might run out if all modules are loaded. Increase memory_limit in php.ini';
 143:         }
 144: 
 145:         // Check safe_mode off
 146:         if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
 147:             $this->warning('WARNING: Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbos/flac tag writing disabled.');
 148:         }
 149: 
 150:         if (intval(ini_get('mbstring.func_overload')) > 0) {
 151:             $this->warning('WARNING: php.ini contains "mbstring.func_overload = '.ini_get('mbstring.func_overload').'", this may break things.');
 152:         }
 153: 
 154:         // Check for magic_quotes_runtime
 155:         if (function_exists('get_magic_quotes_runtime')) {
 156:             if (get_magic_quotes_runtime()) {
 157:                 return $this->startup_error('magic_quotes_runtime must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_runtime(0) and set_magic_quotes_runtime(1).');
 158:             }
 159:         }
 160: 
 161:         // Check for magic_quotes_gpc
 162:         if (function_exists('magic_quotes_gpc')) {
 163:             if (get_magic_quotes_gpc()) {
 164:                 return $this->startup_error('magic_quotes_gpc must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_gpc(0) and set_magic_quotes_gpc(1).');
 165:             }
 166:         }
 167: 
 168:         // Load support library
 169:         if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) {
 170:             $this->startup_error .= 'getid3.lib.php is missing or corrupt';
 171:         }
 172: 
 173:         if ($this->option_max_2gb_check === null) {
 174:             $this->option_max_2gb_check = (PHP_INT_MAX <= 2147483647);
 175:         }
 176: 
 177: 
 178:         // Needed for Windows only:
 179:         // Define locations of helper applications for Shorten, VorbisComment, MetaFLAC
 180:         //   as well as other helper functions such as head, tail, md5sum, etc
 181:         // This path cannot contain spaces, but the below code will attempt to get the
 182:         //   8.3-equivalent path automatically
 183:         // IMPORTANT: This path must include the trailing slash
 184:         if (GETID3_OS_ISWINDOWS && !defined('GETID3_HELPERAPPSDIR')) {
 185: 
 186:             $helperappsdir = GETID3_INCLUDEPATH.'..'.DIRECTORY_SEPARATOR.'helperapps'; // must not have any space in this path
 187: 
 188:             if (!is_dir($helperappsdir)) {
 189:                 $this->startup_warning .= '"'.$helperappsdir.'" cannot be defined as GETID3_HELPERAPPSDIR because it does not exist';
 190:             } elseif (strpos(realpath($helperappsdir), ' ') !== false) {
 191:                 $DirPieces = explode(DIRECTORY_SEPARATOR, realpath($helperappsdir));
 192:                 $path_so_far = array();
 193:                 foreach ($DirPieces as $key => $value) {
 194:                     if (strpos($value, ' ') !== false) {
 195:                         if (!empty($path_so_far)) {
 196:                             $commandline = 'dir /x '.escapeshellarg(implode(DIRECTORY_SEPARATOR, $path_so_far));
 197:                             $dir_listing = `$commandline`;
 198:                             $lines = explode("\n", $dir_listing);
 199:                             foreach ($lines as $line) {
 200:                                 $line = trim($line);
 201:                                 if (preg_match('#^([0-9/]{10}) +([0-9:]{4,5}( [AP]M)?) +(<DIR>|[0-9,]+) +([^ ]{0,11}) +(.+)$#', $line, $matches)) {
 202:                                     list($dummy, $date, $time, $ampm, $filesize, $shortname, $filename) = $matches;
 203:                                     if ((strtoupper($filesize) == '<DIR>') && (strtolower($filename) == strtolower($value))) {
 204:                                         $value = $shortname;
 205:                                     }
 206:                                 }
 207:                             }
 208:                         } else {
 209:                             $this->startup_warning .= 'GETID3_HELPERAPPSDIR must not have any spaces in it - use 8dot3 naming convention if neccesary. You can run "dir /x" from the commandline to see the correct 8.3-style names.';
 210:                         }
 211:                     }
 212:                     $path_so_far[] = $value;
 213:                 }
 214:                 $helperappsdir = implode(DIRECTORY_SEPARATOR, $path_so_far);
 215:             }
 216:             define('GETID3_HELPERAPPSDIR', $helperappsdir.DIRECTORY_SEPARATOR);
 217:         }
 218: 
 219:         return true;
 220:     }
 221: 
 222:     public function version() {
 223:         return self::VERSION;
 224:     }
 225: 
 226:     public function fread_buffer_size() {
 227:         return $this->option_fread_buffer_size;
 228:     }
 229: 
 230: 
 231:     // public: setOption
 232:     public function setOption($optArray) {
 233:         if (!is_array($optArray) || empty($optArray)) {
 234:             return false;
 235:         }
 236:         foreach ($optArray as $opt => $val) {
 237:             if (isset($this->$opt) === false) {
 238:                 continue;
 239:             }
 240:             $this->$opt = $val;
 241:         }
 242:         return true;
 243:     }
 244: 
 245: 
 246:     public function openfile($filename, $filesize=null) {
 247:         try {
 248:             if (!empty($this->startup_error)) {
 249:                 throw new getid3_exception($this->startup_error);
 250:             }
 251:             if (!empty($this->startup_warning)) {
 252:                 $this->warning($this->startup_warning);
 253:             }
 254: 
 255:             // init result array and set parameters
 256:             $this->filename = $filename;
 257:             $this->info = array();
 258:             $this->info['GETID3_VERSION']   = $this->version();
 259:             $this->info['php_memory_limit'] = (($this->memory_limit > 0) ? $this->memory_limit : false);
 260: 
 261:             // remote files not supported
 262:             if (preg_match('/^(ht|f)tp:\/\//', $filename)) {
 263:                 throw new getid3_exception('Remote files are not supported - please copy the file locally first');
 264:             }
 265: 
 266:             $filename = str_replace('/', DIRECTORY_SEPARATOR, $filename);
 267:             $filename = preg_replace('#(.+)'.preg_quote(DIRECTORY_SEPARATOR).'{2,}#U', '\1'.DIRECTORY_SEPARATOR, $filename);
 268: 
 269:             // open local file
 270:             //if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { // see http://www.getid3.org/phpBB3/viewtopic.php?t=1720
 271:             if ((is_readable($filename) || file_exists($filename)) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) {
 272:                 // great
 273:             } else {
 274:                 $errormessagelist = array();
 275:                 if (!is_readable($filename)) {
 276:                     $errormessagelist[] = '!is_readable';
 277:                 }
 278:                 if (!is_file($filename)) {
 279:                     $errormessagelist[] = '!is_file';
 280:                 }
 281:                 if (!file_exists($filename)) {
 282:                     $errormessagelist[] = '!file_exists';
 283:                 }
 284:                 if (empty($errormessagelist)) {
 285:                     $errormessagelist[] = 'fopen failed';
 286:                 }
 287:                 throw new getid3_exception('Could not open "'.$filename.'" ('.implode('; ', $errormessagelist).')');
 288:             }
 289: 
 290:             $this->info['filesize'] = (!is_null($filesize) ? $filesize : filesize($filename));
 291:             // set redundant parameters - might be needed in some include file
 292:             // filenames / filepaths in getID3 are always expressed with forward slashes (unix-style) for both Windows and other to try and minimize confusion
 293:             $filename = str_replace('\\', '/', $filename);
 294:             $this->info['filepath']     = str_replace('\\', '/', realpath(dirname($filename)));
 295:             $this->info['filename']     = getid3_lib::mb_basename($filename);
 296:             $this->info['filenamepath'] = $this->info['filepath'].'/'.$this->info['filename'];
 297: 
 298: 
 299:             // option_max_2gb_check
 300:             if ($this->option_max_2gb_check) {
 301:                 // PHP (32-bit all, and 64-bit Windows) doesn't support integers larger than 2^31 (~2GB)
 302:                 // filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize
 303:                 // ftell() returns 0 if seeking to the end is beyond the range of unsigned integer
 304:                 $fseek = fseek($this->fp, 0, SEEK_END);
 305:                 if (($fseek < 0) || (($this->info['filesize'] != 0) && (ftell($this->fp) == 0)) ||
 306:                     ($this->info['filesize'] < 0) ||
 307:                     (ftell($this->fp) < 0)) {
 308:                         $real_filesize = getid3_lib::getFileSizeSyscall($this->info['filenamepath']);
 309: 
 310:                         if ($real_filesize === false) {
 311:                             unset($this->info['filesize']);
 312:                             fclose($this->fp);
 313:                             throw new getid3_exception('Unable to determine actual filesize. File is most likely larger than '.round(PHP_INT_MAX / 1073741824).'GB and is not supported by PHP.');
 314:                         } elseif (getid3_lib::intValueSupported($real_filesize)) {
 315:                             unset($this->info['filesize']);
 316:                             fclose($this->fp);
 317:                             throw new getid3_exception('PHP seems to think the file is larger than '.round(PHP_INT_MAX / 1073741824).'GB, but filesystem reports it as '.number_format($real_filesize, 3).'GB, please report to info@getid3.org');
 318:                         }
 319:                         $this->info['filesize'] = $real_filesize;
 320:                         $this->warning('File is larger than '.round(PHP_INT_MAX / 1073741824).'GB (filesystem reports it as '.number_format($real_filesize, 3).'GB) and is not properly supported by PHP.');
 321:                 }
 322:             }
 323: 
 324:             // set more parameters
 325:             $this->info['avdataoffset']        = 0;
 326:             $this->info['avdataend']           = $this->info['filesize'];
 327:             $this->info['fileformat']          = '';                // filled in later
 328:             $this->info['audio']['dataformat'] = '';                // filled in later, unset if not used
 329:             $this->info['video']['dataformat'] = '';                // filled in later, unset if not used
 330:             $this->info['tags']                = array();           // filled in later, unset if not used
 331:             $this->info['error']               = array();           // filled in later, unset if not used
 332:             $this->info['warning']             = array();           // filled in later, unset if not used
 333:             $this->info['comments']            = array();           // filled in later, unset if not used
 334:             $this->info['encoding']            = $this->encoding;   // required by id3v2 and iso modules - can be unset at the end if desired
 335: 
 336:             return true;
 337: 
 338:         } catch (Exception $e) {
 339:             $this->error($e->getMessage());
 340:         }
 341:         return false;
 342:     }
 343: 
 344:     // public: analyze file
 345:     public function analyze($filename, $filesize=null, $original_filename='') {
 346:         try {
 347:             if (!$this->openfile($filename, $filesize)) {
 348:                 return $this->info;
 349:             }
 350: 
 351:             // Handle tags
 352:             foreach (array('id3v2'=>'id3v2', 'id3v1'=>'id3v1', 'apetag'=>'ape', 'lyrics3'=>'lyrics3') as $tag_name => $tag_key) {
 353:                 $option_tag = 'option_tag_'.$tag_name;
 354:                 if ($this->$option_tag) {
 355:                     $this->include_module('tag.'.$tag_name);
 356:                     try {
 357:                         $tag_class = 'getid3_'.$tag_name;
 358:                         $tag = new $tag_class($this);
 359:                         $tag->Analyze();
 360:                     }
 361:                     catch (getid3_exception $e) {
 362:                         throw $e;
 363:                     }
 364:                 }
 365:             }
 366:             if (isset($this->info['id3v2']['tag_offset_start'])) {
 367:                 $this->info['avdataoffset'] = max($this->info['avdataoffset'], $this->info['id3v2']['tag_offset_end']);
 368:             }
 369:             foreach (array('id3v1'=>'id3v1', 'apetag'=>'ape', 'lyrics3'=>'lyrics3') as $tag_name => $tag_key) {
 370:                 if (isset($this->info[$tag_key]['tag_offset_start'])) {
 371:                     $this->info['avdataend'] = min($this->info['avdataend'], $this->info[$tag_key]['tag_offset_start']);
 372:                 }
 373:             }
 374: 
 375:             // ID3v2 detection (NOT parsing), even if ($this->option_tag_id3v2 == false) done to make fileformat easier
 376:             if (!$this->option_tag_id3v2) {
 377:                 fseek($this->fp, 0);
 378:                 $header = fread($this->fp, 10);
 379:                 if ((substr($header, 0, 3) == 'ID3') && (strlen($header) == 10)) {
 380:                     $this->info['id3v2']['header']        = true;
 381:                     $this->info['id3v2']['majorversion']  = ord($header{3});
 382:                     $this->info['id3v2']['minorversion']  = ord($header{4});
 383:                     $this->info['avdataoffset']          += getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length
 384:                 }
 385:             }
 386: 
 387:             // read 32 kb file data
 388:             fseek($this->fp, $this->info['avdataoffset']);
 389:             $formattest = fread($this->fp, 32774);
 390: 
 391:             // determine format
 392:             $determined_format = $this->GetFileFormat($formattest, ($original_filename ? $original_filename : $filename));
 393: 
 394:             // unable to determine file format
 395:             if (!$determined_format) {
 396:                 fclose($this->fp);
 397:                 return $this->error('unable to determine file format');
 398:             }
 399: 
 400:             // check for illegal ID3 tags
 401:             if (isset($determined_format['fail_id3']) && (in_array('id3v1', $this->info['tags']) || in_array('id3v2', $this->info['tags']))) {
 402:                 if ($determined_format['fail_id3'] === 'ERROR') {
 403:                     fclose($this->fp);
 404:                     return $this->error('ID3 tags not allowed on this file type.');
 405:                 } elseif ($determined_format['fail_id3'] === 'WARNING') {
 406:                     $this->warning('ID3 tags not allowed on this file type.');
 407:                 }
 408:             }
 409: 
 410:             // check for illegal APE tags
 411:             if (isset($determined_format['fail_ape']) && in_array('ape', $this->info['tags'])) {
 412:                 if ($determined_format['fail_ape'] === 'ERROR') {
 413:                     fclose($this->fp);
 414:                     return $this->error('APE tags not allowed on this file type.');
 415:                 } elseif ($determined_format['fail_ape'] === 'WARNING') {
 416:                     $this->warning('APE tags not allowed on this file type.');
 417:                 }
 418:             }
 419: 
 420:             // set mime type
 421:             $this->info['mime_type'] = $determined_format['mime_type'];
 422: 
 423:             // supported format signature pattern detected, but module deleted
 424:             if (!file_exists(GETID3_INCLUDEPATH.$determined_format['include'])) {
 425:                 fclose($this->fp);
 426:                 return $this->error('Format not supported, module "'.$determined_format['include'].'" was removed.');
 427:             }
 428: 
 429:             // module requires iconv support
 430:             // Check encoding/iconv support
 431:             if (!empty($determined_format['iconv_req']) && !function_exists('iconv') && !in_array($this->encoding, array('ISO-8859-1', 'UTF-8', 'UTF-16LE', 'UTF-16BE', 'UTF-16'))) {
 432:                 $errormessage = 'iconv() support is required for this module ('.$determined_format['include'].') for encodings other than ISO-8859-1, UTF-8, UTF-16LE, UTF16-BE, UTF-16. ';
 433:                 if (GETID3_OS_ISWINDOWS) {
 434:                     $errormessage .= 'PHP does not have iconv() support. Please enable php_iconv.dll in php.ini, and copy iconv.dll from c:/php/dlls to c:/windows/system32';
 435:                 } else {
 436:                     $errormessage .= 'PHP is not compiled with iconv() support. Please recompile with the --with-iconv switch';
 437:                 }
 438:                 return $this->error($errormessage);
 439:             }
 440: 
 441:             // include module
 442:             include_once(GETID3_INCLUDEPATH.$determined_format['include']);
 443: 
 444:             // instantiate module class
 445:             $class_name = 'getid3_'.$determined_format['module'];
 446:             if (!class_exists($class_name)) {
 447:                 return $this->error('Format not supported, module "'.$determined_format['include'].'" is corrupt.');
 448:             }
 449:             $class = new $class_name($this);
 450:             $class->Analyze();
 451:             unset($class);
 452: 
 453:             // close file
 454:             fclose($this->fp);
 455: 
 456:             // process all tags - copy to 'tags' and convert charsets
 457:             if ($this->option_tags_process) {
 458:                 $this->HandleAllTags();
 459:             }
 460: 
 461:             // perform more calculations
 462:             if ($this->option_extra_info) {
 463:                 $this->ChannelsBitratePlaytimeCalculations();
 464:                 $this->CalculateCompressionRatioVideo();
 465:                 $this->CalculateCompressionRatioAudio();
 466:                 $this->CalculateReplayGain();
 467:                 $this->ProcessAudioStreams();
 468:             }
 469: 
 470:             // get the MD5 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags
 471:             if ($this->option_md5_data) {
 472:                 // do not calc md5_data if md5_data_source is present - set by flac only - future MPC/SV8 too
 473:                 if (!$this->option_md5_data_source || empty($this->info['md5_data_source'])) {
 474:                     $this->getHashdata('md5');
 475:                 }
 476:             }
 477: 
 478:             // get the SHA1 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags
 479:             if ($this->option_sha1_data) {
 480:                 $this->getHashdata('sha1');
 481:             }
 482: 
 483:             // remove undesired keys
 484:             $this->CleanUp();
 485: 
 486:         } catch (Exception $e) {
 487:             $this->error('Caught exception: '.$e->getMessage());
 488:         }
 489: 
 490:         // return info array
 491:         return $this->info;
 492:     }
 493: 
 494: 
 495:     // private: error handling
 496:     public function error($message) {
 497:         $this->CleanUp();
 498:         if (!isset($this->info['error'])) {
 499:             $this->info['error'] = array();
 500:         }
 501:         $this->info['error'][] = $message;
 502:         return $this->info;
 503:     }
 504: 
 505: 
 506:     // private: warning handling
 507:     public function warning($message) {
 508:         $this->info['warning'][] = $message;
 509:         return true;
 510:     }
 511: 
 512: 
 513:     // private: CleanUp
 514:     private function CleanUp() {
 515: 
 516:         // remove possible empty keys
 517:         $AVpossibleEmptyKeys = array('dataformat', 'bits_per_sample', 'encoder_options', 'streams', 'bitrate');
 518:         foreach ($AVpossibleEmptyKeys as $dummy => $key) {
 519:             if (empty($this->info['audio'][$key]) && isset($this->info['audio'][$key])) {
 520:                 unset($this->info['audio'][$key]);
 521:             }
 522:             if (empty($this->info['video'][$key]) && isset($this->info['video'][$key])) {
 523:                 unset($this->info['video'][$key]);
 524:             }
 525:         }
 526: 
 527:         // remove empty root keys
 528:         if (!empty($this->info)) {
 529:             foreach ($this->info as $key => $value) {
 530:                 if (empty($this->info[$key]) && ($this->info[$key] !== 0) && ($this->info[$key] !== '0')) {
 531:                     unset($this->info[$key]);
 532:                 }
 533:             }
 534:         }
 535: 
 536:         // remove meaningless entries from unknown-format files
 537:         if (empty($this->info['fileformat'])) {
 538:             if (isset($this->info['avdataoffset'])) {
 539:                 unset($this->info['avdataoffset']);
 540:             }
 541:             if (isset($this->info['avdataend'])) {
 542:                 unset($this->info['avdataend']);
 543:             }
 544:         }
 545: 
 546:         // remove possible duplicated identical entries
 547:         if (!empty($this->info['error'])) {
 548:             $this->info['error'] = array_values(array_unique($this->info['error']));
 549:         }
 550:         if (!empty($this->info['warning'])) {
 551:             $this->info['warning'] = array_values(array_unique($this->info['warning']));
 552:         }
 553: 
 554:         // remove "global variable" type keys
 555:         unset($this->info['php_memory_limit']);
 556: 
 557:         return true;
 558:     }
 559: 
 560: 
 561:     // return array containing information about all supported formats
 562:     public function GetFileFormatArray() {
 563:         static $format_info = array();
 564:         if (empty($format_info)) {
 565:             $format_info = array(
 566: 
 567:                 // Audio formats
 568: 
 569:                 // AC-3   - audio      - Dolby AC-3 / Dolby Digital
 570:                 'ac3'  => array(
 571:                             'pattern'   => '^\x0B\x77',
 572:                             'group'     => 'audio',
 573:                             'module'    => 'ac3',
 574:                             'mime_type' => 'audio/ac3',
 575:                         ),
 576: 
 577:                 // AAC  - audio       - Advanced Audio Coding (AAC) - ADIF format
 578:                 'adif' => array(
 579:                             'pattern'   => '^ADIF',
 580:                             'group'     => 'audio',
 581:                             'module'    => 'aac',
 582:                             'mime_type' => 'application/octet-stream',
 583:                             'fail_ape'  => 'WARNING',
 584:                         ),
 585: 
 586: /*
 587:                 // AA   - audio       - Audible Audiobook
 588:                 'aa'   => array(
 589:                             'pattern'   => '^.{4}\x57\x90\x75\x36',
 590:                             'group'     => 'audio',
 591:                             'module'    => 'aa',
 592:                             'mime_type' => 'audio/audible',
 593:                         ),
 594: */
 595:                 // AAC  - audio       - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3)
 596:                 'adts' => array(
 597:                             'pattern'   => '^\xFF[\xF0-\xF1\xF8-\xF9]',
 598:                             'group'     => 'audio',
 599:                             'module'    => 'aac',
 600:                             'mime_type' => 'application/octet-stream',
 601:                             'fail_ape'  => 'WARNING',
 602:                         ),
 603: 
 604: 
 605:                 // AU   - audio       - NeXT/Sun AUdio (AU)
 606:                 'au'   => array(
 607:                             'pattern'   => '^\.snd',
 608:                             'group'     => 'audio',
 609:                             'module'    => 'au',
 610:                             'mime_type' => 'audio/basic',
 611:                         ),
 612: 
 613:                 // AMR  - audio       - Adaptive Multi Rate
 614:                 'amr'  => array(
 615:                             'pattern'   => '^\x23\x21AMR\x0A', // #!AMR[0A]
 616:                             'group'     => 'audio',
 617:                             'module'    => 'amr',
 618:                             'mime_type' => 'audio/amr',
 619:                         ),
 620: 
 621:                 // AVR  - audio       - Audio Visual Research
 622:                 'avr'  => array(
 623:                             'pattern'   => '^2BIT',
 624:                             'group'     => 'audio',
 625:                             'module'    => 'avr',
 626:                             'mime_type' => 'application/octet-stream',
 627:                         ),
 628: 
 629:                 // BONK - audio       - Bonk v0.9+
 630:                 'bonk' => array(
 631:                             'pattern'   => '^\x00(BONK|INFO|META| ID3)',
 632:                             'group'     => 'audio',
 633:                             'module'    => 'bonk',
 634:                             'mime_type' => 'audio/xmms-bonk',
 635:                         ),
 636: 
 637:                 // DSS  - audio       - Digital Speech Standard
 638:                 'dss'  => array(
 639:                             'pattern'   => '^[\x02-\x03]ds[s2]',
 640:                             'group'     => 'audio',
 641:                             'module'    => 'dss',
 642:                             'mime_type' => 'application/octet-stream',
 643:                         ),
 644: 
 645:                 // DTS  - audio       - Dolby Theatre System
 646:                 'dts'  => array(
 647:                             'pattern'   => '^\x7F\xFE\x80\x01',
 648:                             'group'     => 'audio',
 649:                             'module'    => 'dts',
 650:                             'mime_type' => 'audio/dts',
 651:                         ),
 652: 
 653:                 // FLAC - audio       - Free Lossless Audio Codec
 654:                 'flac' => array(
 655:                             'pattern'   => '^fLaC',
 656:                             'group'     => 'audio',
 657:                             'module'    => 'flac',
 658:                             'mime_type' => 'audio/x-flac',
 659:                         ),
 660: 
 661:                 // LA   - audio       - Lossless Audio (LA)
 662:                 'la'   => array(
 663:                             'pattern'   => '^LA0[2-4]',
 664:                             'group'     => 'audio',
 665:                             'module'    => 'la',
 666:                             'mime_type' => 'application/octet-stream',
 667:                         ),
 668: 
 669:                 // LPAC - audio       - Lossless Predictive Audio Compression (LPAC)
 670:                 'lpac' => array(
 671:                             'pattern'   => '^LPAC',
 672:                             'group'     => 'audio',
 673:                             'module'    => 'lpac',
 674:                             'mime_type' => 'application/octet-stream',
 675:                         ),
 676: 
 677:                 // MIDI - audio       - MIDI (Musical Instrument Digital Interface)
 678:                 'midi' => array(
 679:                             'pattern'   => '^MThd',
 680:                             'group'     => 'audio',
 681:                             'module'    => 'midi',
 682:                             'mime_type' => 'audio/midi',
 683:                         ),
 684: 
 685:                 // MAC  - audio       - Monkey's Audio Compressor
 686:                 'mac'  => array(
 687:                             'pattern'   => '^MAC ',
 688:                             'group'     => 'audio',
 689:                             'module'    => 'monkey',
 690:                             'mime_type' => 'application/octet-stream',
 691:                         ),
 692: 
 693: // has been known to produce false matches in random files (e.g. JPEGs), leave out until more precise matching available
 694: //              // MOD  - audio       - MODule (assorted sub-formats)
 695: //              'mod'  => array(
 696: //                          'pattern'   => '^.{1080}(M\\.K\\.|M!K!|FLT4|FLT8|[5-9]CHN|[1-3][0-9]CH)',
 697: //                          'group'     => 'audio',
 698: //                          'module'    => 'mod',
 699: //                          'option'    => 'mod',
 700: //                          'mime_type' => 'audio/mod',
 701: //                      ),
 702: 
 703:                 // MOD  - audio       - MODule (Impulse Tracker)
 704:                 'it'   => array(
 705:                             'pattern'   => '^IMPM',
 706:                             'group'     => 'audio',
 707:                             'module'    => 'mod',
 708:                             //'option'    => 'it',
 709:                             'mime_type' => 'audio/it',
 710:                         ),
 711: 
 712:                 // MOD  - audio       - MODule (eXtended Module, various sub-formats)
 713:                 'xm'   => array(
 714:                             'pattern'   => '^Extended Module',
 715:                             'group'     => 'audio',
 716:                             'module'    => 'mod',
 717:                             //'option'    => 'xm',
 718:                             'mime_type' => 'audio/xm',
 719:                         ),
 720: 
 721:                 // MOD  - audio       - MODule (ScreamTracker)
 722:                 's3m'  => array(
 723:                             'pattern'   => '^.{44}SCRM',
 724:                             'group'     => 'audio',
 725:                             'module'    => 'mod',
 726:                             //'option'    => 's3m',
 727:                             'mime_type' => 'audio/s3m',
 728:                         ),
 729: 
 730:                 // MPC  - audio       - Musepack / MPEGplus
 731:                 'mpc'  => array(
 732:                             'pattern'   => '^(MPCK|MP\+|[\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0])',
 733:                             'group'     => 'audio',
 734:                             'module'    => 'mpc',
 735:                             'mime_type' => 'audio/x-musepack',
 736:                         ),
 737: 
 738:                 // MP3  - audio       - MPEG-audio Layer 3 (very similar to AAC-ADTS)
 739:                 'mp3'  => array(
 740:                             'pattern'   => '^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\x0B\x10-\x1B\x20-\x2B\x30-\x3B\x40-\x4B\x50-\x5B\x60-\x6B\x70-\x7B\x80-\x8B\x90-\x9B\xA0-\xAB\xB0-\xBB\xC0-\xCB\xD0-\xDB\xE0-\xEB\xF0-\xFB]',
 741:                             'group'     => 'audio',
 742:                             'module'    => 'mp3',
 743:                             'mime_type' => 'audio/mpeg',
 744:                         ),
 745: 
 746:                 // OFR  - audio       - OptimFROG
 747:                 'ofr'  => array(
 748:                             'pattern'   => '^(\*RIFF|OFR)',
 749:                             'group'     => 'audio',
 750:                             'module'    => 'optimfrog',
 751:                             'mime_type' => 'application/octet-stream',
 752:                         ),
 753: 
 754:                 // RKAU - audio       - RKive AUdio compressor
 755:                 'rkau' => array(
 756:                             'pattern'   => '^RKA',
 757:                             'group'     => 'audio',
 758:                             'module'    => 'rkau',
 759:                             'mime_type' => 'application/octet-stream',
 760:                         ),
 761: 
 762:                 // SHN  - audio       - Shorten
 763:                 'shn'  => array(
 764:                             'pattern'   => '^ajkg',
 765:                             'group'     => 'audio',
 766:                             'module'    => 'shorten',
 767:                             'mime_type' => 'audio/xmms-shn',
 768:                             'fail_id3'  => 'ERROR',
 769:                             'fail_ape'  => 'ERROR',
 770:                         ),
 771: 
 772:                 // TTA  - audio       - TTA Lossless Audio Compressor (http://tta.corecodec.org)
 773:                 'tta'  => array(
 774:                             'pattern'   => '^TTA',  // could also be '^TTA(\x01|\x02|\x03|2|1)'
 775:                             'group'     => 'audio',
 776:                             'module'    => 'tta',
 777:                             'mime_type' => 'application/octet-stream',
 778:                         ),
 779: 
 780:                 // VOC  - audio       - Creative Voice (VOC)
 781:                 'voc'  => array(
 782:                             'pattern'   => '^Creative Voice File',
 783:                             'group'     => 'audio',
 784:                             'module'    => 'voc',
 785:                             'mime_type' => 'audio/voc',
 786:                         ),
 787: 
 788:                 // VQF  - audio       - transform-domain weighted interleave Vector Quantization Format (VQF)
 789:                 'vqf'  => array(
 790:                             'pattern'   => '^TWIN',
 791:                             'group'     => 'audio',
 792:                             'module'    => 'vqf',
 793:                             'mime_type' => 'application/octet-stream',
 794:                         ),
 795: 
 796:                 // WV  - audio        - WavPack (v4.0+)
 797:                 'wv'   => array(
 798:                             'pattern'   => '^wvpk',
 799:                             'group'     => 'audio',
 800:                             'module'    => 'wavpack',
 801:                             'mime_type' => 'application/octet-stream',
 802:                         ),
 803: 
 804: 
 805:                 // Audio-Video formats
 806: 
 807:                 // ASF  - audio/video - Advanced Streaming Format, Windows Media Video, Windows Media Audio
 808:                 'asf'  => array(
 809:                             'pattern'   => '^\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C',
 810:                             'group'     => 'audio-video',
 811:                             'module'    => 'asf',
 812:                             'mime_type' => 'video/x-ms-asf',
 813:                             'iconv_req' => false,
 814:                         ),
 815: 
 816:                 // BINK - audio/video - Bink / Smacker
 817:                 'bink' => array(
 818:                             'pattern'   => '^(BIK|SMK)',
 819:                             'group'     => 'audio-video',
 820:                             'module'    => 'bink',
 821:                             'mime_type' => 'application/octet-stream',
 822:                         ),
 823: 
 824:                 // FLV  - audio/video - FLash Video
 825:                 'flv' => array(
 826:                             'pattern'   => '^FLV\x01',
 827:                             'group'     => 'audio-video',
 828:                             'module'    => 'flv',
 829:                             'mime_type' => 'video/x-flv',
 830:                         ),
 831: 
 832:                 // MKAV - audio/video - Mastroka
 833:                 'matroska' => array(
 834:                             'pattern'   => '^\x1A\x45\xDF\xA3',
 835:                             'group'     => 'audio-video',
 836:                             'module'    => 'matroska',
 837:                             'mime_type' => 'video/x-matroska', // may also be audio/x-matroska
 838:                         ),
 839: 
 840:                 // MPEG - audio/video - MPEG (Moving Pictures Experts Group)
 841:                 'mpeg' => array(
 842:                             'pattern'   => '^\x00\x00\x01(\xBA|\xB3)',
 843:                             'group'     => 'audio-video',
 844:                             'module'    => 'mpeg',
 845:                             'mime_type' => 'video/mpeg',
 846:                         ),
 847: 
 848:                 // NSV  - audio/video - Nullsoft Streaming Video (NSV)
 849:                 'nsv'  => array(
 850:                             'pattern'   => '^NSV[sf]',
 851:                             'group'     => 'audio-video',
 852:                             'module'    => 'nsv',
 853:                             'mime_type' => 'application/octet-stream',
 854:                         ),
 855: 
 856:                 // Ogg  - audio/video - Ogg (Ogg-Vorbis, Ogg-FLAC, Speex, Ogg-Theora(*), Ogg-Tarkin(*))
 857:                 'ogg'  => array(
 858:                             'pattern'   => '^OggS',
 859:                             'group'     => 'audio',
 860:                             'module'    => 'ogg',
 861:                             'mime_type' => 'application/ogg',
 862:                             'fail_id3'  => 'WARNING',
 863:                             'fail_ape'  => 'WARNING',
 864:                         ),
 865: 
 866:                 // QT   - audio/video - Quicktime
 867:                 'quicktime' => array(
 868:                             'pattern'   => '^.{4}(cmov|free|ftyp|mdat|moov|pnot|skip|wide)',
 869:                             'group'     => 'audio-video',
 870:                             'module'    => 'quicktime',
 871:                             'mime_type' => 'video/quicktime',
 872:                         ),
 873: 
 874:                 // RIFF - audio/video - Resource Interchange File Format (RIFF) / WAV / AVI / CD-audio / SDSS = renamed variant used by SmartSound QuickTracks (www.smartsound.com) / FORM = Audio Interchange File Format (AIFF)
 875:                 'riff' => array(
 876:                             'pattern'   => '^(RIFF|SDSS|FORM)',
 877:                             'group'     => 'audio-video',
 878:                             'module'    => 'riff',
 879:                             'mime_type' => 'audio/x-wav',
 880:                             'fail_ape'  => 'WARNING',
 881:                         ),
 882: 
 883:                 // Real - audio/video - RealAudio, RealVideo
 884:                 'real' => array(
 885:                             'pattern'   => '^(\\.RMF|\\.ra)',
 886:                             'group'     => 'audio-video',
 887:                             'module'    => 'real',
 888:                             'mime_type' => 'audio/x-realaudio',
 889:                         ),
 890: 
 891:                 // SWF - audio/video - ShockWave Flash
 892:                 'swf' => array(
 893:                             'pattern'   => '^(F|C)WS',
 894:                             'group'     => 'audio-video',
 895:                             'module'    => 'swf',
 896:                             'mime_type' => 'application/x-shockwave-flash',
 897:                         ),
 898: 
 899:                 // TS - audio/video - MPEG-2 Transport Stream
 900:                 'ts' => array(
 901:                             'pattern'   => '^(\x47.{187}){10,}', // packets are 188 bytes long and start with 0x47 "G".  Check for at least 10 packets matching this pattern
 902:                             'group'     => 'audio-video',
 903:                             'module'    => 'ts',
 904:                             'mime_type' => 'video/MP2T',
 905:                         ),
 906: 
 907: 
 908:                 // Still-Image formats
 909: 
 910:                 // BMP  - still image - Bitmap (Windows, OS/2; uncompressed, RLE8, RLE4)
 911:                 'bmp'  => array(
 912:                             'pattern'   => '^BM',
 913:                             'group'     => 'graphic',
 914:                             'module'    => 'bmp',
 915:                             'mime_type' => 'image/bmp',
 916:                             'fail_id3'  => 'ERROR',
 917:                             'fail_ape'  => 'ERROR',
 918:                         ),
 919: 
 920:                 // GIF  - still image - Graphics Interchange Format
 921:                 'gif'  => array(
 922:                             'pattern'   => '^GIF',
 923:                             'group'     => 'graphic',
 924:                             'module'    => 'gif',
 925:                             'mime_type' => 'image/gif',
 926:                             'fail_id3'  => 'ERROR',
 927:                             'fail_ape'  => 'ERROR',
 928:                         ),
 929: 
 930:                 // JPEG - still image - Joint Photographic Experts Group (JPEG)
 931:                 'jpg'  => array(
 932:                             'pattern'   => '^\xFF\xD8\xFF',
 933:                             'group'     => 'graphic',
 934:                             'module'    => 'jpg',
 935:                             'mime_type' => 'image/jpeg',
 936:                             'fail_id3'  => 'ERROR',
 937:                             'fail_ape'  => 'ERROR',
 938:                         ),
 939: 
 940:                 // PCD  - still image - Kodak Photo CD
 941:                 'pcd'  => array(
 942:                             'pattern'   => '^.{2048}PCD_IPI\x00',
 943:                             'group'     => 'graphic',
 944:                             'module'    => 'pcd',
 945:                             'mime_type' => 'image/x-photo-cd',
 946:                             'fail_id3'  => 'ERROR',
 947:                             'fail_ape'  => 'ERROR',
 948:                         ),
 949: 
 950: 
 951:                 // PNG  - still image - Portable Network Graphics (PNG)
 952:                 'png'  => array(
 953:                             'pattern'   => '^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A',
 954:                             'group'     => 'graphic',
 955:                             'module'    => 'png',
 956:                             'mime_type' => 'image/png',
 957:                             'fail_id3'  => 'ERROR',
 958:                             'fail_ape'  => 'ERROR',
 959:                         ),
 960: 
 961: 
 962:                 // SVG  - still image - Scalable Vector Graphics (SVG)
 963:                 'svg'  => array(
 964:                             'pattern'   => '(<!DOCTYPE svg PUBLIC |xmlns="http:\/\/www\.w3\.org\/2000\/svg")',
 965:                             'group'     => 'graphic',
 966:                             'module'    => 'svg',
 967:                             'mime_type' => 'image/svg+xml',
 968:                             'fail_id3'  => 'ERROR',
 969:                             'fail_ape'  => 'ERROR',
 970:                         ),
 971: 
 972: 
 973:                 // TIFF - still image - Tagged Information File Format (TIFF)
 974:                 'tiff' => array(
 975:                             'pattern'   => '^(II\x2A\x00|MM\x00\x2A)',
 976:                             'group'     => 'graphic',
 977:                             'module'    => 'tiff',
 978:                             'mime_type' => 'image/tiff',
 979:                             'fail_id3'  => 'ERROR',
 980:                             'fail_ape'  => 'ERROR',
 981:                         ),
 982: 
 983: 
 984:                 // EFAX - still image - eFax (TIFF derivative)
 985:                 'efax'  => array(
 986:                             'pattern'   => '^\xDC\xFE',
 987:                             'group'     => 'graphic',
 988:                             'module'    => 'efax',
 989:                             'mime_type' => 'image/efax',
 990:                             'fail_id3'  => 'ERROR',
 991:                             'fail_ape'  => 'ERROR',
 992:                         ),
 993: 
 994: 
 995:                 // Data formats
 996: 
 997:                 // ISO  - data        - International Standards Organization (ISO) CD-ROM Image
 998:                 'iso'  => array(
 999:                             'pattern'   => '^.{32769}CD001',
1000:                             'group'     => 'misc',
1001:                             'module'    => 'iso',
1002:                             'mime_type' => 'application/octet-stream',
1003:                             'fail_id3'  => 'ERROR',
1004:                             'fail_ape'  => 'ERROR',
1005:                             'iconv_req' => false,
1006:                         ),
1007: 
1008:                 // RAR  - data        - RAR compressed data
1009:                 'rar'  => array(
1010:                             'pattern'   => '^Rar\!',
1011:                             'group'     => 'archive',
1012:                             'module'    => 'rar',
1013:                             'mime_type' => 'application/octet-stream',
1014:                             'fail_id3'  => 'ERROR',
1015:                             'fail_ape'  => 'ERROR',
1016:                         ),
1017: 
1018:                 // SZIP - audio/data  - SZIP compressed data
1019:                 'szip' => array(
1020:                             'pattern'   => '^SZ\x0A\x04',
1021:                             'group'     => 'archive',
1022:                             'module'    => 'szip',
1023:                             'mime_type' => 'application/octet-stream',
1024:                             'fail_id3'  => 'ERROR',
1025:                             'fail_ape'  => 'ERROR',
1026:                         ),
1027: 
1028:                 // TAR  - data        - TAR compressed data
1029:                 'tar'  => array(
1030:                             'pattern'   => '^.{100}[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20\x00]{12}[0-9\x20\x00]{12}',
1031:                             'group'     => 'archive',
1032:                             'module'    => 'tar',
1033:                             'mime_type' => 'application/x-tar',
1034:                             'fail_id3'  => 'ERROR',
1035:                             'fail_ape'  => 'ERROR',
1036:                         ),
1037: 
1038:                 // GZIP  - data        - GZIP compressed data
1039:                 'gz'  => array(
1040:                             'pattern'   => '^\x1F\x8B\x08',
1041:                             'group'     => 'archive',
1042:                             'module'    => 'gzip',
1043:                             'mime_type' => 'application/x-gzip',
1044:                             'fail_id3'  => 'ERROR',
1045:                             'fail_ape'  => 'ERROR',
1046:                         ),
1047: 
1048:                 // ZIP  - data         - ZIP compressed data
1049:                 'zip'  => array(
1050:                             'pattern'   => '^PK\x03\x04',
1051:                             'group'     => 'archive',
1052:                             'module'    => 'zip',
1053:                             'mime_type' => 'application/zip',
1054:                             'fail_id3'  => 'ERROR',
1055:                             'fail_ape'  => 'ERROR',
1056:                         ),
1057: 
1058: 
1059:                 // Misc other formats
1060: 
1061:                 // PAR2 - data        - Parity Volume Set Specification 2.0
1062:                 'par2' => array (
1063:                             'pattern'   => '^PAR2\x00PKT',
1064:                             'group'     => 'misc',
1065:                             'module'    => 'par2',
1066:                             'mime_type' => 'application/octet-stream',
1067:                             'fail_id3'  => 'ERROR',
1068:                             'fail_ape'  => 'ERROR',
1069:                         ),
1070: 
1071:                 // PDF  - data        - Portable Document Format
1072:                 'pdf'  => array(
1073:                             'pattern'   => '^\x25PDF',
1074:                             'group'     => 'misc',
1075:                             'module'    => 'pdf',
1076:                             'mime_type' => 'application/pdf',
1077:                             'fail_id3'  => 'ERROR',
1078:                             'fail_ape'  => 'ERROR',
1079:                         ),
1080: 
1081:                 // MSOFFICE  - data   - ZIP compressed data
1082:                 'msoffice' => array(
1083:                             'pattern'   => '^\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1', // D0CF11E == DOCFILE == Microsoft Office Document
1084:                             'group'     => 'misc',
1085:                             'module'    => 'msoffice',
1086:                             'mime_type' => 'application/octet-stream',
1087:                             'fail_id3'  => 'ERROR',
1088:                             'fail_ape'  => 'ERROR',
1089:                         ),
1090: 
1091:                  // CUE  - data       - CUEsheet (index to single-file disc images)
1092:                  'cue' => array(
1093:                             'pattern'   => '', // empty pattern means cannot be automatically detected, will fall through all other formats and match based on filename and very basic file contents
1094:                             'group'     => 'misc',
1095:                             'module'    => 'cue',
1096:                             'mime_type' => 'application/octet-stream',
1097:                            ),
1098: 
1099:             );
1100:         }
1101: 
1102:         return $format_info;
1103:     }
1104: 
1105: 
1106: 
1107:     public function GetFileFormat(&$filedata, $filename='') {
1108:         // this function will determine the format of a file based on usually
1109:         // the first 2-4 bytes of the file (8 bytes for PNG, 16 bytes for JPG,
1110:         // and in the case of ISO CD image, 6 bytes offset 32kb from the start
1111:         // of the file).
1112: 
1113:         // Identify file format - loop through $format_info and detect with reg expr
1114:         foreach ($this->GetFileFormatArray() as $format_name => $info) {
1115:             // The /s switch on preg_match() forces preg_match() NOT to treat
1116:             // newline (0x0A) characters as special chars but do a binary match
1117:             if (!empty($info['pattern']) && preg_match('#'.$info['pattern'].'#s', $filedata)) {
1118:                 $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
1119:                 return $info;
1120:             }
1121:         }
1122: 
1123: 
1124:         if (preg_match('#\.mp[123a]$#i', $filename)) {
1125:             // Too many mp3 encoders on the market put gabage in front of mpeg files
1126:             // use assume format on these if format detection failed
1127:             $GetFileFormatArray = $this->GetFileFormatArray();
1128:             $info = $GetFileFormatArray['mp3'];
1129:             $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
1130:             return $info;
1131:         } elseif (preg_match('/\.cue$/i', $filename) && preg_match('#FILE "[^"]+" (BINARY|MOTOROLA|AIFF|WAVE|MP3)#', $filedata)) {
1132:             // there's not really a useful consistent "magic" at the beginning of .cue files to identify them
1133:             // so until I think of something better, just go by filename if all other format checks fail
1134:             // and verify there's at least one instance of "TRACK xx AUDIO" in the file
1135:             $GetFileFormatArray = $this->GetFileFormatArray();
1136:             $info = $GetFileFormatArray['cue'];
1137:             $info['include']   = 'module.'.$info['group'].'.'.$info['module'].'.php';
1138:             return $info;
1139:         }
1140: 
1141:         return false;
1142:     }
1143: 
1144: 
1145:     // converts array to $encoding charset from $this->encoding
1146:     public function CharConvert(&$array, $encoding) {
1147: 
1148:         // identical encoding - end here
1149:         if ($encoding == $this->encoding) {
1150:             return;
1151:         }
1152: 
1153:         // loop thru array
1154:         foreach ($array as $key => $value) {
1155: 
1156:             // go recursive
1157:             if (is_array($value)) {
1158:                 $this->CharConvert($array[$key], $encoding);
1159:             }
1160: 
1161:             // convert string
1162:             elseif (is_string($value)) {
1163:                 $array[$key] = trim(getid3_lib::iconv_fallback($encoding, $this->encoding, $value));
1164:             }
1165:         }
1166:     }
1167: 
1168: 
1169:     public function HandleAllTags() {
1170: 
1171:         // key name => array (tag name, character encoding)
1172:         static $tags;
1173:         if (empty($tags)) {
1174:             $tags = array(
1175:                 'asf'       => array('asf'           , 'UTF-16LE'),
1176:                 'midi'      => array('midi'          , 'ISO-8859-1'),
1177:                 'nsv'       => array('nsv'           , 'ISO-8859-1'),
1178:                 'ogg'       => array('vorbiscomment' , 'UTF-8'),
1179:                 'png'       => array('png'           , 'UTF-8'),
1180:                 'tiff'      => array('tiff'          , 'ISO-8859-1'),
1181:                 'quicktime' => array('quicktime'     , 'UTF-8'),
1182:                 'real'      => array('real'          , 'ISO-8859-1'),
1183:                 'vqf'       => array('vqf'           , 'ISO-8859-1'),
1184:                 'zip'       => array('zip'           , 'ISO-8859-1'),
1185:                 'riff'      => array('riff'          , 'ISO-8859-1'),
1186:                 'lyrics3'   => array('lyrics3'       , 'ISO-8859-1'),
1187:                 'id3v1'     => array('id3v1'         , $this->encoding_id3v1),
1188:                 'id3v2'     => array('id3v2'         , 'UTF-8'), // not according to the specs (every frame can have a different encoding), but getID3() force-converts all encodings to UTF-8
1189:                 'ape'       => array('ape'           , 'UTF-8'),
1190:                 'cue'       => array('cue'           , 'ISO-8859-1'),
1191:                 'matroska'  => array('matroska'      , 'UTF-8'),
1192:                 'flac'      => array('vorbiscomment' , 'UTF-8'),
1193:                 'divxtag'   => array('divx'          , 'ISO-8859-1'),
1194:                 'iptc'      => array('iptc'          , 'ISO-8859-1'),
1195:             );
1196:         }
1197: 
1198:         // loop through comments array
1199:         foreach ($tags as $comment_name => $tagname_encoding_array) {
1200:             list($tag_name, $encoding) = $tagname_encoding_array;
1201: 
1202:             // fill in default encoding type if not already present
1203:             if (isset($this->info[$comment_name]) && !isset($this->info[$comment_name]['encoding'])) {
1204:                 $this->info[$comment_name]['encoding'] = $encoding;
1205:             }
1206: 
1207:             // copy comments if key name set
1208:             if (!empty($this->info[$comment_name]['comments'])) {
1209:                 foreach ($this->info[$comment_name]['comments'] as $tag_key => $valuearray) {
1210:                     foreach ($valuearray as $key => $value) {
1211:                         if (is_string($value)) {
1212:                             $value = trim($value, " \r\n\t"); // do not trim nulls from $value!! Unicode characters will get mangled if trailing nulls are removed!
1213:                         }
1214:                         if ($value) {
1215:                             if (!is_numeric($key)) {
1216:                                 $this->info['tags'][trim($tag_name)][trim($tag_key)][$key] = $value;
1217:                             } else {
1218:                                 $this->info['tags'][trim($tag_name)][trim($tag_key)][]     = $value;
1219:                             }
1220:                         }
1221:                     }
1222:                     if ($tag_key == 'picture') {
1223:                         unset($this->info[$comment_name]['comments'][$tag_key]);
1224:                     }
1225:                 }
1226: 
1227:                 if (!isset($this->info['tags'][$tag_name])) {
1228:                     // comments are set but contain nothing but empty strings, so skip
1229:                     continue;
1230:                 }
1231: 
1232:                 if ($this->option_tags_html) {
1233:                     foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) {
1234:                         $this->info['tags_html'][$tag_name][$tag_key] = getid3_lib::recursiveMultiByteCharString2HTML($valuearray, $encoding);
1235:                     }
1236:                 }
1237: 
1238:                 // ID3v1 encoding detection hack start
1239:                 // ID3v1 is defined as always using ISO-8859-1 encoding, but it is not uncommon to find files tagged with ID3v1 using Windows-1251 or other character sets
1240:                 // Since ID3v1 has no concept of character sets there is no certain way to know we have the correct non-ISO-8859-1 character set, but we can guess
1241:                 if ($comment_name == 'id3v1') {
1242:                     if ($encoding == 'ISO-8859-1') {
1243:                         if (function_exists('iconv')) {
1244:                             foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) {
1245:                                 foreach ($valuearray as $key => $value) {
1246:                                     if (preg_match('#^[\\x80-\\xFF]+$#', $value)) {
1247:                                         foreach (array('windows-1251', 'KOI8-R') as $id3v1_bad_encoding) {
1248:                                             if (@iconv($id3v1_bad_encoding, $id3v1_bad_encoding, $value) === $value) {
1249:                                                 $encoding = $id3v1_bad_encoding;
1250:                                                 break 3;
1251:                                             }
1252:                                         }
1253:                                     }
1254:                                 }
1255:                             }
1256:                         }
1257:                     }
1258:                 }
1259:                 // ID3v1 encoding detection hack end
1260: 
1261:                 $this->CharConvert($this->info['tags'][$tag_name], $encoding);           // only copy gets converted!
1262:             }
1263: 
1264:         }
1265: 
1266:         // pictures can take up a lot of space, and we don't need multiple copies of them
1267:         // let there be a single copy in [comments][picture], and not elsewhere
1268:         if (!empty($this->info['tags'])) {
1269:             $unset_keys = array('tags', 'tags_html');
1270:             foreach ($this->info['tags'] as $tagtype => $tagarray) {
1271:                 foreach ($tagarray as $tagname => $tagdata) {
1272:                     if ($tagname == 'picture') {
1273:                         foreach ($tagdata as $key => $tagarray) {
1274:                             $this->info['comments']['picture'][] = $tagarray;
1275:                             if (isset($tagarray['data']) && isset($tagarray['image_mime'])) {
1276:                                 if (isset($this->info['tags'][$tagtype][$tagname][$key])) {
1277:                                     unset($this->info['tags'][$tagtype][$tagname][$key]);
1278:                                 }
1279:                                 if (isset($this->info['tags_html'][$tagtype][$tagname][$key])) {
1280:                                     unset($this->info['tags_html'][$tagtype][$tagname][$key]);
1281:                                 }
1282:                             }
1283:                         }
1284:                     }
1285:                 }
1286:                 foreach ($unset_keys as $unset_key) {
1287:                     // remove possible empty keys from (e.g. [tags][id3v2][picture])
1288:                     if (empty($this->info[$unset_key][$tagtype]['picture'])) {
1289:                         unset($this->info[$unset_key][$tagtype]['picture']);
1290:                     }
1291:                     if (empty($this->info[$unset_key][$tagtype])) {
1292:                         unset($this->info[$unset_key][$tagtype]);
1293:                     }
1294:                     if (empty($this->info[$unset_key])) {
1295:                         unset($this->info[$unset_key]);
1296:                     }
1297:                 }
1298:                 // remove duplicate copy of picture data from (e.g. [id3v2][comments][picture])
1299:                 if (isset($this->info[$tagtype]['comments']['picture'])) {
1300:                     unset($this->info[$tagtype]['comments']['picture']);
1301:                 }
1302:                 if (empty($this->info[$tagtype]['comments'])) {
1303:                     unset($this->info[$tagtype]['comments']);
1304:                 }
1305:                 if (empty($this->info[$tagtype])) {
1306:                     unset($this->info[$tagtype]);
1307:                 }
1308:             }
1309:         }
1310:         return true;
1311:     }
1312: 
1313:     public function getHashdata($algorithm) {
1314:         switch ($algorithm) {
1315:             case 'md5':
1316:             case 'sha1':
1317:                 break;
1318: 
1319:             default:
1320:                 return $this->error('bad algorithm "'.$algorithm.'" in getHashdata()');
1321:                 break;
1322:         }
1323: 
1324:         if (!empty($this->info['fileformat']) && !empty($this->info['dataformat']) && ($this->info['fileformat'] == 'ogg') && ($this->info['audio']['dataformat'] == 'vorbis')) {
1325: 
1326:             // We cannot get an identical md5_data value for Ogg files where the comments
1327:             // span more than 1 Ogg page (compared to the same audio data with smaller
1328:             // comments) using the normal getID3() method of MD5'ing the data between the
1329:             // end of the comments and the end of the file (minus any trailing tags),
1330:             // because the page sequence numbers of the pages that the audio data is on
1331:             // do not match. Under normal circumstances, where comments are smaller than
1332:             // the nominal 4-8kB page size, then this is not a problem, but if there are
1333:             // very large comments, the only way around it is to strip off the comment
1334:             // tags with vorbiscomment and MD5 that file.
1335:             // This procedure must be applied to ALL Ogg files, not just the ones with
1336:             // comments larger than 1 page, because the below method simply MD5's the
1337:             // whole file with the comments stripped, not just the portion after the
1338:             // comments block (which is the standard getID3() method.
1339: 
1340:             // The above-mentioned problem of comments spanning multiple pages and changing
1341:             // page sequence numbers likely happens for OggSpeex and OggFLAC as well, but
1342:             // currently vorbiscomment only works on OggVorbis files.
1343: 
1344:             if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
1345: 
1346:                 $this->warning('Failed making system call to vorbiscomment.exe - '.$algorithm.'_data is incorrect - error returned: PHP running in Safe Mode (backtick operator not available)');
1347:                 $this->info[$algorithm.'_data'] = false;
1348: 
1349:             } else {
1350: 
1351:                 // Prevent user from aborting script
1352:                 $old_abort = ignore_user_abort(true);
1353: 
1354:                 // Create empty file
1355:                 $empty = tempnam(GETID3_TEMP_DIR, 'getID3');
1356:                 touch($empty);
1357: 
1358:                 // Use vorbiscomment to make temp file without comments
1359:                 $temp = tempnam(GETID3_TEMP_DIR, 'getID3');
1360:                 $file = $this->info['filenamepath'];
1361: 
1362:                 if (GETID3_OS_ISWINDOWS) {
1363: 
1364:                     if (file_exists(GETID3_HELPERAPPSDIR.'vorbiscomment.exe')) {
1365: 
1366:                         $commandline = '"'.GETID3_HELPERAPPSDIR.'vorbiscomment.exe" -w -c "'.$empty.'" "'.$file.'" "'.$temp.'"';
1367:                         $VorbisCommentError = `$commandline`;
1368: 
1369:                     } else {
1370: 
1371:                         $VorbisCommentError = 'vorbiscomment.exe not found in '.GETID3_HELPERAPPSDIR;
1372: 
1373:                     }
1374: 
1375:                 } else {
1376: 
1377:                     $commandline = 'vorbiscomment -w -c "'.$empty.'" "'.$file.'" "'.$temp.'" 2>&1';
1378:                     $commandline = 'vorbiscomment -w -c '.escapeshellarg($empty).' '.escapeshellarg($file).' '.escapeshellarg($temp).' 2>&1';
1379:                     $VorbisCommentError = `$commandline`;
1380: 
1381:                 }
1382: 
1383:                 if (!empty($VorbisCommentError)) {
1384: 
1385:                     $this->info['warning'][]         = 'Failed making system call to vorbiscomment(.exe) - '.$algorithm.'_data will be incorrect. If vorbiscomment is unavailable, please download from http://www.vorbis.com/download.psp and put in the getID3() directory. Error returned: '.$VorbisCommentError;
1386:                     $this->info[$algorithm.'_data']  = false;
1387: 
1388:                 } else {
1389: 
1390:                     // Get hash of newly created file
1391:                     switch ($algorithm) {
1392:                         case 'md5':
1393:                             $this->info[$algorithm.'_data'] = md5_file($temp);
1394:                             break;
1395: 
1396:                         case 'sha1':
1397:                             $this->info[$algorithm.'_data'] = sha1_file($temp);
1398:                             break;
1399:                     }
1400:                 }
1401: 
1402:                 // Clean up
1403:                 unlink($empty);
1404:                 unlink($temp);
1405: 
1406:                 // Reset abort setting
1407:                 ignore_user_abort($old_abort);
1408: 
1409:             }
1410: 
1411:         } else {
1412: 
1413:             if (!empty($this->info['avdataoffset']) || (isset($this->info['avdataend']) && ($this->info['avdataend'] < $this->info['filesize']))) {
1414: 
1415:                 // get hash from part of file
1416:                 $this->info[$algorithm.'_data'] = getid3_lib::hash_data($this->info['filenamepath'], $this->info['avdataoffset'], $this->info['avdataend'], $algorithm);
1417: 
1418:             } else {
1419: 
1420:                 // get hash from whole file
1421:                 switch ($algorithm) {
1422:                     case 'md5':
1423:                         $this->info[$algorithm.'_data'] = md5_file($this->info['filenamepath']);
1424:                         break;
1425: 
1426:                     case 'sha1':
1427:                         $this->info[$algorithm.'_data'] = sha1_file($this->info['filenamepath']);
1428:                         break;
1429:                 }
1430:             }
1431: 
1432:         }
1433:         return true;
1434:     }
1435: 
1436: 
1437:     public function ChannelsBitratePlaytimeCalculations() {
1438: 
1439:         // set channelmode on audio
1440:         if (!empty($this->info['audio']['channelmode']) || !isset($this->info['audio']['channels'])) {
1441:             // ignore
1442:         } elseif ($this->info['audio']['channels'] == 1) {
1443:             $this->info['audio']['channelmode'] = 'mono';
1444:         } elseif ($this->info['audio']['channels'] == 2) {
1445:             $this->info['audio']['channelmode'] = 'stereo';
1446:         }
1447: 
1448:         // Calculate combined bitrate - audio + video
1449:         $CombinedBitrate  = 0;
1450:         $CombinedBitrate += (isset($this->info['audio']['bitrate']) ? $this->info['audio']['bitrate'] : 0);
1451:         $CombinedBitrate += (isset($this->info['video']['bitrate']) ? $this->info['video']['bitrate'] : 0);
1452:         if (($CombinedBitrate > 0) && empty($this->info['bitrate'])) {
1453:             $this->info['bitrate'] = $CombinedBitrate;
1454:         }
1455:         //if ((isset($this->info['video']) && !isset($this->info['video']['bitrate'])) || (isset($this->info['audio']) && !isset($this->info['audio']['bitrate']))) {
1456:         //  // for example, VBR MPEG video files cannot determine video bitrate:
1457:         //  // should not set overall bitrate and playtime from audio bitrate only
1458:         //  unset($this->info['bitrate']);
1459:         //}
1460: 
1461:         // video bitrate undetermined, but calculable
1462:         if (isset($this->info['video']['dataformat']) && $this->info['video']['dataformat'] && (!isset($this->info['video']['bitrate']) || ($this->info['video']['bitrate'] == 0))) {
1463:             // if video bitrate not set
1464:             if (isset($this->info['audio']['bitrate']) && ($this->info['audio']['bitrate'] > 0) && ($this->info['audio']['bitrate'] == $this->info['bitrate'])) {
1465:                 // AND if audio bitrate is set to same as overall bitrate
1466:                 if (isset($this->info['playtime_seconds']) && ($this->info['playtime_seconds'] > 0)) {
1467:                     // AND if playtime is set
1468:                     if (isset($this->info['avdataend']) && isset($this->info['avdataoffset'])) {
1469:                         // AND if AV data offset start/end is known
1470:                         // THEN we can calculate the video bitrate
1471:                         $this->info['bitrate'] = round((($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['playtime_seconds']);
1472:                         $this->info['video']['bitrate'] = $this->info['bitrate'] - $this->info['audio']['bitrate'];
1473:                     }
1474:                 }
1475:             }
1476:         }
1477: 
1478:         if ((!isset($this->info['playtime_seconds']) || ($this->info['playtime_seconds'] <= 0)) && !empty($this->info['bitrate'])) {
1479:             $this->info['playtime_seconds'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['bitrate'];
1480:         }
1481: 
1482:         if (!isset($this->info['bitrate']) && !empty($this->info['playtime_seconds'])) {
1483:             $this->info['bitrate'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['playtime_seconds'];
1484:         }
1485:         if (isset($this->info['bitrate']) && empty($this->info['audio']['bitrate']) && empty($this->info['video']['bitrate'])) {
1486:             if (isset($this->info['audio']['dataformat']) && empty($this->info['video']['resolution_x'])) {
1487:                 // audio only
1488:                 $this->info['audio']['bitrate'] = $this->info['bitrate'];
1489:             } elseif (isset($this->info['video']['resolution_x']) && empty($this->info['audio']['dataformat'])) {
1490:                 // video only
1491:                 $this->info['video']['bitrate'] = $this->info['bitrate'];
1492:             }
1493:         }
1494: 
1495:         // Set playtime string
1496:         if (!empty($this->info['playtime_seconds']) && empty($this->info['playtime_string'])) {
1497:             $this->info['playtime_string'] = getid3_lib::PlaytimeString($this->info['playtime_seconds']);
1498:         }
1499:     }
1500: 
1501: 
1502:     public function CalculateCompressionRatioVideo() {
1503:         if (empty($this->info['video'])) {
1504:             return false;
1505:         }
1506:         if (empty($this->info['video']['resolution_x']) || empty($this->info['video']['resolution_y'])) {
1507:             return false;
1508:         }
1509:         if (empty($this->info['video']['bits_per_sample'])) {
1510:             return false;
1511:         }
1512: 
1513:         switch ($this->info['video']['dataformat']) {
1514:             case 'bmp':
1515:             case 'gif':
1516:             case 'jpeg':
1517:             case 'jpg':
1518:             case 'png':
1519:             case 'tiff':
1520:                 $FrameRate = 1;
1521:                 $PlaytimeSeconds = 1;
1522:                 $BitrateCompressed = $this->info['filesize'] * 8;
1523:                 break;
1524: 
1525:             default:
1526:                 if (!empty($this->info['video']['frame_rate'])) {
1527:                     $FrameRate = $this->info['video']['frame_rate'];
1528:                 } else {
1529:                     return false;
1530:                 }
1531:                 if (!empty($this->info['playtime_seconds'])) {
1532:                     $PlaytimeSeconds = $this->info['playtime_seconds'];
1533:                 } else {
1534:                     return false;
1535:                 }
1536:                 if (!empty($this->info['video']['bitrate'])) {
1537:                     $BitrateCompressed = $this->info['video']['bitrate'];
1538:                 } else {
1539:                     return false;
1540:                 }
1541:                 break;
1542:         }
1543:         $BitrateUncompressed = $this->info['video']['resolution_x'] * $this->info['video']['resolution_y'] * $this->info['video']['bits_per_sample'] * $FrameRate;
1544: 
1545:         $this->info['video']['compression_ratio'] = $BitrateCompressed / $BitrateUncompressed;
1546:         return true;
1547:     }
1548: 
1549: 
1550:     public function CalculateCompressionRatioAudio() {
1551:         if (empty($this->info['audio']['bitrate']) || empty($this->info['audio']['channels']) || empty($this->info['audio']['sample_rate']) || !is_numeric($this->info['audio']['sample_rate'])) {
1552:             return false;
1553:         }
1554:         $this->info['audio']['compression_ratio'] = $this->info['audio']['bitrate'] / ($this->info['audio']['channels'] * $this->info['audio']['sample_rate'] * (!empty($this->info['audio']['bits_per_sample']) ? $this->info['audio']['bits_per_sample'] : 16));
1555: 
1556:         if (!empty($this->info['audio']['streams'])) {
1557:             foreach ($this->info['audio']['streams'] as $streamnumber => $streamdata) {
1558:                 if (!empty($streamdata['bitrate']) && !empty($streamdata['channels']) && !empty($streamdata['sample_rate'])) {
1559:                     $this->info['audio']['streams'][$streamnumber]['compression_ratio'] = $streamdata['bitrate'] / ($streamdata['channels'] * $streamdata['sample_rate'] * (!empty($streamdata['bits_per_sample']) ? $streamdata['bits_per_sample'] : 16));
1560:                 }
1561:             }
1562:         }
1563:         return true;
1564:     }
1565: 
1566: 
1567:     public function CalculateReplayGain() {
1568:         if (isset($this->info['replay_gain'])) {
1569:             if (!isset($this->info['replay_gain']['reference_volume'])) {
1570:                 $this->info['replay_gain']['reference_volume'] = (double) 89.0;
1571:             }
1572:             if (isset($this->info['replay_gain']['track']['adjustment'])) {
1573:                 $this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment'];
1574:             }
1575:             if (isset($this->info['replay_gain']['album']['adjustment'])) {
1576:                 $this->info['replay_gain']['album']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['album']['adjustment'];
1577:             }
1578: 
1579:             if (isset($this->info['replay_gain']['track']['peak'])) {
1580:                 $this->info['replay_gain']['track']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['track']['peak']);
1581:             }
1582:             if (isset($this->info['replay_gain']['album']['peak'])) {
1583:                 $this->info['replay_gain']['album']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['album']['peak']);
1584:             }
1585:         }
1586:         return true;
1587:     }
1588: 
1589:     public function ProcessAudioStreams() {
1590:         if (!empty($this->info['audio']['bitrate']) || !empty($this->info['audio']['channels']) || !empty($this->info['audio']['sample_rate'])) {
1591:             if (!isset($this->info['audio']['streams'])) {
1592:                 foreach ($this->info['audio'] as $key => $value) {
1593:                     if ($key != 'streams') {
1594:                         $this->info['audio']['streams'][0][$key] = $value;
1595:                     }
1596:                 }
1597:             }
1598:         }
1599:         return true;
1600:     }
1601: 
1602:     public function getid3_tempnam() {
1603:         return tempnam($this->tempdir, 'gI3');
1604:     }
1605: 
1606:     public function include_module($name) {
1607:         //if (!file_exists($this->include_path.'module.'.$name.'.php')) {
1608:         if (!file_exists(GETID3_INCLUDEPATH.'module.'.$name.'.php')) {
1609:             throw new getid3_exception('Required module.'.$name.'.php is missing.');
1610:         }
1611:         include_once(GETID3_INCLUDEPATH.'module.'.$name.'.php');
1612:         return true;
1613:     }
1614: 
1615: }
1616: 
1617: 
1618: abstract class getid3_handler {
1619: 
1620:     /**
1621:     * @var getID3
1622:     */
1623:     protected $getid3;                       // pointer
1624: 
1625:     protected $data_string_flag     = false; // analyzing filepointer or string
1626:     protected $data_string          = '';    // string to analyze
1627:     protected $data_string_position = 0;     // seek position in string
1628:     protected $data_string_length   = 0;     // string length
1629: 
1630:     private $dependency_to = null;
1631: 
1632: 
1633:     public function __construct(getID3 $getid3, $call_module=null) {
1634:         $this->getid3 = $getid3;
1635: 
1636:         if ($call_module) {
1637:             $this->dependency_to = str_replace('getid3_', '', $call_module);
1638:         }
1639:     }
1640: 
1641: 
1642:     // Analyze from file pointer
1643:     abstract public function Analyze();
1644: 
1645: 
1646:     // Analyze from string instead
1647:     public function AnalyzeString($string) {
1648:         // Enter string mode
1649:         $this->setStringMode($string);
1650: 
1651:         // Save info
1652:         $saved_avdataoffset = $this->getid3->info['avdataoffset'];
1653:         $saved_avdataend    = $this->getid3->info['avdataend'];
1654:         $saved_filesize     = (isset($this->getid3->info['filesize']) ? $this->getid3->info['filesize'] : null); // may be not set if called as dependency without openfile() call
1655: 
1656:         // Reset some info
1657:         $this->getid3->info['avdataoffset'] = 0;
1658:         $this->getid3->info['avdataend']    = $this->getid3->info['filesize'] = $this->data_string_length;
1659: 
1660:         // Analyze
1661:         $this->Analyze();
1662: 
1663:         // Restore some info
1664:         $this->getid3->info['avdataoffset'] = $saved_avdataoffset;
1665:         $this->getid3->info['avdataend']    = $saved_avdataend;
1666:         $this->getid3->info['filesize']     = $saved_filesize;
1667: 
1668:         // Exit string mode
1669:         $this->data_string_flag = false;
1670:     }
1671: 
1672:     public function setStringMode($string) {
1673:         $this->data_string_flag   = true;
1674:         $this->data_string        = $string;
1675:         $this->data_string_length = strlen($string);
1676:     }
1677: 
1678:     protected function ftell() {
1679:         if ($this->data_string_flag) {
1680:             return $this->data_string_position;
1681:         }
1682:         return ftell($this->getid3->fp);
1683:     }
1684: 
1685:     protected function fread($bytes) {
1686:         if ($this->data_string_flag) {
1687:             $this->data_string_position += $bytes;
1688:             return substr($this->data_string, $this->data_string_position - $bytes, $bytes);
1689:         }
1690:         $pos = $this->ftell() + $bytes;
1691:         if (!getid3_lib::intValueSupported($pos)) {
1692:             throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') because beyond PHP filesystem limit', 10);
1693:         }
1694:         return fread($this->getid3->fp, $bytes);
1695:     }
1696: 
1697:     protected function fseek($bytes, $whence=SEEK_SET) {
1698:         if ($this->data_string_flag) {
1699:             switch ($whence) {
1700:                 case SEEK_SET:
1701:                     $this->data_string_position = $bytes;
1702:                     break;
1703: 
1704:                 case SEEK_CUR:
1705:                     $this->data_string_position += $bytes;
1706:                     break;
1707: 
1708:                 case SEEK_END:
1709:                     $this->data_string_position = $this->data_string_length + $bytes;
1710:                     break;
1711:             }
1712:             return 0;
1713:         } else {
1714:             $pos = $bytes;
1715:             if ($whence == SEEK_CUR) {
1716:                 $pos = $this->ftell() + $bytes;
1717:             } elseif ($whence == SEEK_END) {
1718:                 $pos = $this->getid3->info['filesize'] + $bytes;
1719:             }
1720:             if (!getid3_lib::intValueSupported($pos)) {
1721:                 throw new getid3_exception('cannot fseek('.$pos.') because beyond PHP filesystem limit', 10);
1722:             }
1723:         }
1724:         return fseek($this->getid3->fp, $bytes, $whence);
1725:     }
1726: 
1727:     protected function feof() {
1728:         if ($this->data_string_flag) {
1729:             return $this->data_string_position >= $this->data_string_length;
1730:         }
1731:         return feof($this->getid3->fp);
1732:     }
1733: 
1734:     final protected function isDependencyFor($module) {
1735:         return $this->dependency_to == $module;
1736:     }
1737: 
1738:     protected function error($text) {
1739:         $this->getid3->info['error'][] = $text;
1740: 
1741:         return false;
1742:     }
1743: 
1744:     protected function warning($text) {
1745:         return $this->getid3->warning($text);
1746:     }
1747: 
1748:     protected function notice($text) {
1749:         // does nothing for now
1750:     }
1751: 
1752:     public function saveAttachment($name, $offset, $length, $image_mime=null) {
1753:         try {
1754: 
1755:             // do not extract at all
1756:             if ($this->getid3->option_save_attachments === getID3::ATTACHMENTS_NONE) {
1757: 
1758:                 $attachment = null; // do not set any
1759: 
1760:             // extract to return array
1761:             } elseif ($this->getid3->option_save_attachments === getID3::ATTACHMENTS_INLINE) {
1762: 
1763:                 $this->fseek($offset);
1764:                 $attachment = $this->fread($length); // get whole data in one pass, till it is anyway stored in memory
1765:                 if ($attachment === false || strlen($attachment) != $length) {
1766:                     throw new Exception('failed to read attachment data');
1767:                 }
1768: 
1769:             // assume directory path is given
1770:             } else {
1771: 
1772:                 // set up destination path
1773:                 $dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR);
1774:                 if (!is_dir($dir) || !is_writable($dir)) { // check supplied directory
1775:                     throw new Exception('supplied path ('.$dir.') does not exist, or is not writable');
1776:                 }
1777:                 $dest = $dir.DIRECTORY_SEPARATOR.$name.($image_mime ? '.'.getid3_lib::ImageExtFromMime($image_mime) : '');
1778: 
1779:                 // create dest file
1780:                 if (($fp_dest = fopen($dest, 'wb')) == false) {
1781:                     throw new Exception('failed to create file '.$dest);
1782:                 }
1783: 
1784:                 // copy data
1785:                 $this->fseek($offset);
1786:                 $buffersize = ($this->data_string_flag ? $length : $this->getid3->fread_buffer_size());
1787:                 $bytesleft = $length;
1788:                 while ($bytesleft > 0) {
1789:                     if (($buffer = $this->fread(min($buffersize, $bytesleft))) === false || ($byteswritten = fwrite($fp_dest, $buffer)) === false || ($byteswritten === 0)) {
1790:                         throw new Exception($buffer === false ? 'not enough data to read' : 'failed to write to destination file, may be not enough disk space');
1791:                     }
1792:                     $bytesleft -= $byteswritten;
1793:                 }
1794: 
1795:                 fclose($fp_dest);
1796:                 $attachment = $dest;
1797: 
1798:             }
1799: 
1800:         } catch (Exception $e) {
1801: 
1802:             // close and remove dest file if created
1803:             if (isset($fp_dest) && is_resource($fp_dest)) {
1804:                 fclose($fp_dest);
1805:                 unlink($dest);
1806:             }
1807: 
1808:             // do not set any is case of error
1809:             $attachment = null;
1810:             $this->warning('Failed to extract attachment '.$name.': '.$e->getMessage());
1811: 
1812:         }
1813: 
1814:         // seek to the end of attachment
1815:         $this->fseek($offset + $length);
1816: 
1817:         return $attachment;
1818:     }
1819: 
1820: }
1821: 
1822: 
1823: class getid3_exception extends Exception
1824: {
1825:     public $message;
1826: }
1827: 
Zenphoto doc API documentation generated by ApiGen