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:  * basic functions used by zenphoto
   4:  *
   5:  * @package core
   6:  *
   7:  */
   8: // force UTF-8 Ø
   9: 
  10: global $_zp_current_context_stack, $_zp_HTML_cache;
  11: 
  12: if (!function_exists("json_encode")) {
  13:     // load the drop-in replacement library
  14:     require_once(dirname(__FILE__) . '/lib-json.php');
  15: }
  16: 
  17: require_once(dirname(__FILE__) . '/functions-basic.php');
  18: require_once(dirname(__FILE__) . '/functions-filter.php');
  19: require_once(SERVERPATH . '/' . ZENFOLDER . '/lib-kses.php');
  20: 
  21: $_zp_captcha = new _zp_captcha(); // this will be overridden by the plugin if enabled.
  22: $_zp_HTML_cache = new _zp_HTML_cache(); // this will be overridden by the plugin if enabled.
  23: //setup session before checking for logon cookie
  24: require_once(dirname(__FILE__) . '/functions-i18n.php');
  25: 
  26: if (GALLERY_SESSION) {
  27:     zp_session_start();
  28: }
  29: 
  30: define('ZENPHOTO_LOCALE', setMainDomain());
  31: define('SITE_LOCALE', getOptionFromDB('locale'));
  32: 
  33: require_once(dirname(__FILE__) . '/load_objectClasses.php');
  34: 
  35: $_zp_current_context_stack = array();
  36: 
  37: $_zp_albumthumb_selector = array(array('field' => '', 'direction' => '', 'desc' => 'random'),
  38:                 array('field' => 'id', 'direction' => 'DESC', 'desc' => gettext('most recent')),
  39:                 array('field' => 'mtime', 'direction' => '', 'desc' => gettext('oldest')),
  40:                 array('field' => 'title', 'direction' => '', 'desc' => gettext('first alphabetically')),
  41:                 array('field' => 'hitcounter', 'direction' => 'DESC', 'desc' => gettext('most viewed'))
  42: );
  43: 
  44: $_zp_missing_album = new AlbumBase(gettext('missing'), false);
  45: $_zp_missing_image = new Transientimage($_zp_missing_album, SERVERPATH . '/' . ZENFOLDER . '/images/err-imagenotfound.png');
  46: 
  47: /**
  48:  * parses the allowed HTML tags for use by htmLawed
  49:  *
  50:  * @param string &$source by name, contains the string with the tag options
  51:  * @return array the allowed_tags array.
  52:  * @since 1.1.3
  53:  * */
  54: function parseAllowedTags(&$source) {
  55:     $source = trim($source);
  56:     if (substr($source, 0, 1) != "(") {
  57:         return false;
  58:     }
  59:     $source = substr($source, 1); //strip off the open paren
  60:     $a = array();
  61:     while ((strlen($source) > 1) && (substr($source, 0, 1) != ")")) {
  62:         $i = strpos($source, '=>');
  63:         if ($i === false) {
  64:             return false;
  65:         }
  66:         $tag = trim(substr($source, 0, $i));
  67:         //strip forbidden tags from list
  68:         if ($tag == 'script') {
  69:             return 0;
  70:         }
  71:         $source = trim(substr($source, $i + 2));
  72:         if (substr($source, 0, 1) != "(") {
  73:             return false;
  74:         }
  75:         $x = parseAllowedTags($source);
  76:         if ($x === false) {
  77:             return false;
  78:         }
  79:         $a[$tag] = $x;
  80:     }
  81:     if (substr($source, 0, 1) != ')') {
  82:         return false;
  83:     }
  84:     $source = trim(substr($source, 1)); //strip the close paren
  85:     return $a;
  86: }
  87: 
  88: /**
  89:  * Search for a thumbnail for the image
  90:  *
  91:  * @param $localpath local path of the image
  92:  * @return string
  93:  */
  94: function checkObjectsThumb($localpath) {
  95:     global $_zp_supported_images;
  96:     $image = stripSuffix($localpath);
  97:     $candidates = safe_glob($image . '.*');
  98:     foreach ($candidates as $file) {
  99:         $ext = substr($file, strrpos($file, '.') + 1);
 100:         if (in_array(strtolower($ext), $_zp_supported_images)) {
 101:             return basename($image . '.' . $ext);
 102:         }
 103:     }
 104:     return NULL;
 105: }
 106: 
 107: /**
 108:  * Returns a truncated string
 109:  *
 110:  * @param string $string souirce string
 111:  * @param int $length how long it should be
 112:  * @param string $elipsis the text to tack on indicating shortening
 113:  * @return string
 114:  */
 115: function truncate_string($string, $length, $elipsis = '...') {
 116:     if (mb_strlen($string) > $length) {
 117:         $string = mb_substr($string, 0, $length);
 118:         $pos = mb_strrpos(strtr($string, array('~' => ' ', '!' => ' ', '@' => ' ', '#' => ' ', '$' => ' ', '%' => ' ', '^' => ' ', '&' => ' ', '*' => ' ', '(' => ' ', ')' => ' ', '+' => ' ', '=' => ' ', '-' => ' ', '{' => ' ', '}' => ' ', '[' => ' ', ']' => ' ', '|' => ' ', ':' => ' ', ';' => ' ', '<' => ' ', '>' => ' ', '.' => ' ', '?' => ' ', '/' => ' ', '\\', '\\' => ' ', "'" => ' ', "`" => ' ', '"' => ' ')), ' ');
 119:         if ($pos === FALSE) {
 120:             $string .= $elipsis;
 121:         } else {
 122:             $string = mb_substr($string, 0, $pos) . $elipsis;
 123:         }
 124:     }
 125:     return $string;
 126: }
 127: 
 128: /**
 129:  *
 130:  * fixes unbalanced HTML tags. Used by shortenContent when PHP tidy is not present
 131:  * @param string $html
 132:  * @return string
 133:  */
 134: function cleanHTML($html) {
 135: 
 136:     preg_match_all('#<(?!meta|img|br|hr|input\b)\b([a-z]+)(?: .*)?(?<![/|/ ])>#iU', $html, $result);
 137:     $openedtags = $result[1];
 138: 
 139:     preg_match_all('#</([a-z]+)>#iU', $html, $result);
 140:     $closedtags = $result[1];
 141: 
 142:     $len_opened = count($openedtags);
 143: 
 144:     if (count($closedtags) == $len_opened) {
 145:         return $html;
 146:     }
 147: 
 148:     $openedtags = array_reverse($openedtags);
 149:     for ($i = 0; $i < $len_opened; $i++) {
 150:         if (!in_array($openedtags[$i], $closedtags)) {
 151:             $html .= '</' . $openedtags[$i] . '>';
 152:         } else {
 153:             unset($closedtags[array_search($openedtags[$i], $closedtags)]);
 154:         }
 155:     }
 156: 
 157:     return $html;
 158: }
 159: 
 160: /**
 161:  * Returns truncated html formatted content
 162:  *
 163:  * @param string $articlecontent the source string
 164:  * @param int $shorten new size
 165:  * @param string $shortenindicator
 166:  * @param bool $forceindicator set to true to include the indicator no matter what
 167:  * @return string
 168:  */
 169: function shortenContent($articlecontent, $shorten, $shortenindicator, $forceindicator = false) {
 170:     global $_user_tags;
 171:     if ($shorten && ($forceindicator || (mb_strlen($articlecontent) > $shorten))) {
 172:         $allowed_tags = getAllowedTags('allowed_tags');
 173:         //remove script to be replaced later
 174:         $articlecontent = preg_replace('~<script.*?/script>~is', '', $articlecontent);
 175:         //remove HTML comments
 176:         $articlecontent = preg_replace('~<!--.*?-->~is', '', $articlecontent);
 177:         $short = mb_substr($articlecontent, 0, $shorten);
 178:         $short2 = kses($short . '</p>', $allowed_tags);
 179: 
 180:         if (($l2 = mb_strlen($short2)) < $shorten) {
 181:             $c = 0;
 182:             $l1 = $shorten;
 183:             $delta = $shorten - $l2;
 184:             while ($l2 < $shorten && $c++ < 5) {
 185:                 $open = mb_strrpos($short, '<');
 186:                 if ($open > mb_strrpos($short, '>')) {
 187:                     $l1 = mb_strpos($articlecontent, '>', $l1 + 1) + $delta;
 188:                 } else {
 189:                     $l1 = $l1 + $delta;
 190:                 }
 191:                 $short = mb_substr($articlecontent, 0, $l1);
 192:                 preg_match_all('/(<p>)/', $short, $open);
 193:                 preg_match_all('/(<\/p>)/', $short, $close);
 194:                 if (count($open) > count($close))
 195:                     $short .= '</p>';
 196:                 $short2 = kses($short, $allowed_tags);
 197:                 $l2 = mb_strlen($short2);
 198:             }
 199:             $shorten = $l1;
 200:         }
 201:         $short = truncate_string($articlecontent, $shorten, '');
 202:         if ($short != $articlecontent) { // we actually did remove some stuff
 203:             // drop open tag strings
 204:             $open = mb_strrpos($short, '<');
 205:             if ($open > mb_strrpos($short, '>')) {
 206:                 $short = mb_substr($short, 0, $open);
 207:             }
 208:             if (class_exists('tidy')) {
 209:                 $short = zpFunctions::tidyHTML($short . $shortenindicator);
 210:             } else {
 211:                 $short = trim(cleanHTML($short . $shortenindicator));
 212:             }
 213:         }
 214:         $articlecontent = $short;
 215:     }
 216:     if (isset($matches)) {
 217:         //replace the script text
 218:         foreach ($matches[0] as $script) {
 219:             $articlecontent = $script . $articlecontent;
 220:         }
 221:     }
 222:     return $articlecontent;
 223: }
 224: 
 225: /**
 226:  * Returns the oldest ancestor of an alubm;
 227:  *
 228:  * @param string $album an album object
 229:  * @return object
 230:  */
 231: function getUrAlbum($album) {
 232:     if (!is_object($album))
 233:         return NULL;
 234:     while (true) {
 235:         $parent = $album->getParent();
 236:         if (is_null($parent)) {
 237:             return $album;
 238:         }
 239:         $album = $parent;
 240:     }
 241: }
 242: 
 243: /**
 244:  * Returns a sort field part for querying
 245:  * Note: $sorttype may be a comma separated list of field names. If so,
 246:  *       these are peckmarked and returned otherwise unchanged.
 247:  *
 248:  * @param string $sorttype the 'Display" name of the sort
 249:  * @param string $default the default if $sorttype is empty
 250:  * @param string $table the database table being used.
 251:  * @return string
 252:  */
 253: function lookupSortKey($sorttype, $default, $table) {
 254:     global $_zp_fieldLists;
 255:     switch (strtolower($sorttype)) {
 256:         case 'random':
 257:             return 'RAND()';
 258:         case "manual":
 259:             return '`sort_order`';
 260:         case "filename":
 261:             switch ($table) {
 262:                 case 'images':
 263:                     return '`filename`';
 264:                 case 'albums':
 265:                     return '`folder`';
 266:             }
 267:         default:
 268:             if (empty($sorttype)) {
 269:                 return '`' . $default . '`';
 270:             }
 271:             if (substr($sorttype, 0) == '(') {
 272:                 return $sorttype;
 273:             }
 274:             if (is_array($_zp_fieldLists) && isset($_zp_fieldLists[$table])) {
 275:                 $dbfields = $_zp_fieldLists[$table];
 276:             } else {
 277:                 $result = db_list_fields($table);
 278:                 $dbfields = array();
 279:                 if ($result) {
 280:                     foreach ($result as $row) {
 281:                         $dbfields[strtolower($row['Field'])] = $row['Field'];
 282:                     }
 283:                 }
 284:                 $_zp_fieldLists[$table] = $dbfields;
 285:             }
 286:             $sorttype = strtolower($sorttype);
 287:             $list = explode(',', $sorttype);
 288:             foreach ($list as $key => $field) {
 289:                 if (array_key_exists($field, $dbfields)) {
 290:                     $list[$key] = '`' . trim($dbfields[$field]) . '`';
 291:                 }
 292:             }
 293:             return implode(',', $list);
 294:     }
 295: }
 296: 
 297: /**
 298:  * Returns a formated date for output
 299:  *
 300:  * @param string $format the "strftime" format string
 301:  * @param date $dt the date to be output
 302:  * @return string
 303:  */
 304: function zpFormattedDate($format, $dt) {
 305:     global $_zp_UTF8;
 306:     $fdate = strftime($format, $dt);
 307:     $charset = 'ISO-8859-1';
 308:     $outputset = LOCAL_CHARSET;
 309:     if (function_exists('mb_internal_encoding')) {
 310:         if (($charset = mb_internal_encoding()) == $outputset) {
 311:             return $fdate;
 312:         }
 313:     }
 314:     return $_zp_UTF8->convert($fdate, $charset, $outputset);
 315: }
 316: 
 317: /**
 318:  * Simple SQL timestamp formatting function.
 319:  *
 320:  * @param string $format formatting template
 321:  * @param int $mytimestamp timestamp
 322:  * @return string
 323:  */
 324: function myts_date($format, $mytimestamp) {
 325:     $timezoneadjust = getOption('time_offset');
 326: 
 327:     $month = substr($mytimestamp, 4, 2);
 328:     $day = substr($mytimestamp, 6, 2);
 329:     $year = substr($mytimestamp, 0, 4);
 330: 
 331:     $hour = substr($mytimestamp, 8, 2);
 332:     $min = substr($mytimestamp, 10, 2);
 333:     $sec = substr($mytimestamp, 12, 2);
 334: 
 335:     $epoch = mktime($hour + $timezoneadjust, $min, $sec, $month, $day, $year);
 336:     $date = zpFormattedDate($format, $epoch);
 337:     return $date;
 338: }
 339: 
 340: /**
 341:  * Determines if the input is an e-mail address. Adapted from WordPress.
 342:  * Name changed to avoid conflicts in WP integrations.
 343:  *
 344:  * @param string $input_email email address?
 345:  * @return bool
 346:  */
 347: function is_valid_email_zp($input_email) {
 348:     $chars = "/^([a-z0-9+_]|\\-|\\.)+@(([a-z0-9_]|\\-)+\\.)+[a-z]{2,6}\$/i";
 349:     if (strstr($input_email, '@') && strstr($input_email, '.')) {
 350:         if (preg_match($chars, $input_email)) {
 351:             return true;
 352:         }
 353:     }
 354:     return false;
 355: }
 356: 
 357: /**
 358:  * Send an mail to the mailing list. We also attempt to intercept any form injection
 359:  * attacks by slime ball spammers. Returns error message if send failure.
 360:  *
 361:  * @param string $subject  The subject of the email.
 362:  * @param string $message  The message contents of the email.
 363:  * @param array $email_list a list of email addresses to send to
 364:  * @param array $cc_addresses a list of addresses to send copies to.
 365:  * @param array $bcc_addresses a list of addresses to send blind copies to.
 366:  * @param string $replyTo reply-to address
 367:  *
 368:  * @return string
 369:  *
 370:  * @author Todd Papaioannou (lucky@luckyspin.org)
 371:  * @since  1.0.0
 372:  */
 373: function zp_mail($subject, $message, $email_list = NULL, $cc_addresses = NULL, $bcc_addresses = NULL, $replyTo = NULL) {
 374:     global $_zp_authority, $_zp_gallery, $_zp_UTF8;
 375:     $result = '';
 376:     if ($replyTo) {
 377:         $t = $replyTo;
 378:         if (!is_valid_email_zp($m = array_shift($t))) {
 379:             if (empty($result)) {
 380:                 $result = gettext('Mail send failed.');
 381:             }
 382:             $result .= sprintf(gettext('Invalid “reply-to” mail address %s.'), $m);
 383:         }
 384:     }
 385:     if (is_null($email_list)) {
 386:         $email_list = $_zp_authority->getAdminEmail();
 387:     } else {
 388:         foreach ($email_list as $key => $email) {
 389:             if (!is_valid_email_zp($email)) {
 390:                 unset($email_list[$key]);
 391:                 if (empty($result)) {
 392:                     $result = gettext('Mail send failed.');
 393:                 }
 394:                 $result .= ' ' . sprintf(gettext('Invalid “to” mail address %s.'), $email);
 395:             }
 396:         }
 397:     }
 398:     if (is_null($cc_addresses)) {
 399:         $cc_addresses = array();
 400:     } else {
 401:         if (empty($email_list) && !empty($cc_addresses)) {
 402:             if (empty($result)) {
 403:                 $result = gettext('Mail send failed.');
 404:             }
 405:             $result .= ' ' . gettext('“cc” list provided without “to” address list.');
 406:             return $result;
 407:         }
 408:         foreach ($cc_addresses as $key => $email) {
 409:             if (!is_valid_email_zp($email)) {
 410:                 unset($cc_addresses[$key]);
 411:                 if (empty($result)) {
 412:                     $result = gettext('Mail send failed.');
 413:                 }
 414:                 $result = ' ' . sprintf(gettext('Invalid “cc” mail address %s.'), $email);
 415:             }
 416:         }
 417:     }
 418:     if (is_null($bcc_addresses)) {
 419:         $bcc_addresses = array();
 420:     } else {
 421:         foreach ($bcc_addresses as $key => $email) {
 422:             if (!is_valid_email_zp($email)) {
 423:                 unset($bcc_addresses[$key]);
 424:                 if (empty($result)) {
 425:                     $result = gettext('Mail send failed.');
 426:                 }
 427:                 $result = ' ' . sprintf(gettext('Invalid “bcc” mail address %s.'), $email);
 428:             }
 429:         }
 430:     }
 431:     if (count($email_list) + count($bcc_addresses) > 0) {
 432:         if (zp_has_filter('sendmail')) {
 433: 
 434:             $from_mail = getOption('site_email');
 435:             $from_name = get_language_string(getOption('site_email_name'));
 436: 
 437:             // Convert to UTF-8
 438:             if (LOCAL_CHARSET != 'UTF-8') {
 439:                 $subject = $_zp_UTF8->convert($subject, LOCAL_CHARSET);
 440:                 $message = $_zp_UTF8->convert($message, LOCAL_CHARSET);
 441:             }
 442: 
 443:             //  we do not support rich text
 444:             $message = preg_replace('~<p[^>]*>~', "\n", $message); // Replace the start <p> or <p attr="">
 445:             $message = preg_replace('~</p>~', "\n", $message); // Replace the end
 446:             $message = preg_replace('~<br[^>]*>~', "\n", $message); // Replace <br> or <br ...>
 447:             $message = preg_replace('~<ol[^>]*>~', "", $message); // Replace the start <ol> or <ol attr="">
 448:             $message = preg_replace('~</ol>~', "", $message); // Replace the end
 449:             $message = preg_replace('~<ul[^>]*>~', "", $message); // Replace the start <ul> or <ul attr="">
 450:             $message = preg_replace('~</ul>~', "", $message); // Replace the end
 451:             $message = preg_replace('~<li[^>]*>~', ".\t", $message); // Replace the start <li> or <li attr="">
 452:             $message = preg_replace('~</li>~', "", $message); // Replace the end
 453:             $message = getBare($message);
 454:             $message = preg_replace('~\n\n\n+~', "\n\n", $message);
 455: 
 456:             // Send the mail
 457:             if (count($email_list) > 0) {
 458:                 $result = zp_apply_filter('sendmail', '', $email_list, $subject, $message, $from_mail, $from_name, $cc_addresses, $replyTo); // will be true if all mailers succeeded
 459:             }
 460:             if (count($bcc_addresses) > 0) {
 461:                 foreach ($bcc_addresses as $bcc) {
 462:                     $result = zp_apply_filter('sendmail', '', array($bcc), $subject, $message, $from_mail, $from_name, array(), $replyTo); // will be true if all mailers succeeded
 463:                 }
 464:             }
 465:         } else {
 466:             $result = gettext('Mail send failed. There is no mail handler configured.');
 467:         }
 468:     } else {
 469:         if (empty($result)) {
 470:             $result = gettext('Mail send failed.');
 471:         }
 472:         $result .= ' ' . gettext('No “to” address list provided.');
 473:     }
 474:     return $result;
 475: }
 476: 
 477: /**
 478:  * Sorts the results of a DB search by the current locale string for $field
 479:  *
 480:  * @param array $dbresult the result of the DB query
 481:  * @param string $field the field name to sort on
 482:  * @param bool $descending the direction of the sort
 483:  * @return array the sorted result
 484:  */
 485: function sortByMultilingual($dbresult, $field, $descending) {
 486:     $temp = array();
 487:     foreach ($dbresult as $key => $row) {
 488:         $temp[$key] = get_language_string($row[$field]);
 489:     }
 490:     natcasesort($temp);
 491:     if ($descending) {
 492:         $temp = array_reverse($temp, true);
 493:     }
 494:     $result = array();
 495:     foreach ($temp as $key => $v) {
 496:         $result[] = $dbresult[$key];
 497:     }
 498:     return $result;
 499: }
 500: 
 501: /**
 502:  * Checks to see access is allowed to an album
 503:  * Returns true if access is allowed.
 504:  * There is no password dialog--you must have already had authorization via a cookie.
 505:  *
 506:  * @param string $album album object or name of the album
 507:  * @param string &$hint becomes populated with the password hint.
 508:  * @return bool
 509:  */
 510: function checkAlbumPassword($album, &$hint = NULL) {
 511:     global $_zp_pre_authorization, $_zp_gallery;
 512:     if (is_object($album)) {
 513:         $albumname = $album->name;
 514:     } else {
 515:         $album = newAlbum($albumname = $album, true, true);
 516:     }
 517:     if (isset($_zp_pre_authorization[$albumname])) {
 518:         return $_zp_pre_authorization[$albumname];
 519:     }
 520:     $hash = $album->getPassword();
 521:     if (empty($hash)) {
 522:         $album = $album->getParent();
 523:         while (!is_null($album)) {
 524:             $hash = $album->getPassword();
 525:             $authType = "zp_album_auth_" . $album->getID();
 526:             $saved_auth = zp_getCookie($authType);
 527: 
 528:             if (!empty($hash)) {
 529:                 if ($saved_auth == $hash) {
 530:                     $_zp_pre_authorization[$albumname] = $authType;
 531:                     return $authType;
 532:                 } else {
 533:                     $hint = $album->getPasswordHint();
 534:                     return false;
 535:                 }
 536:             }
 537:             $album = $album->getParent();
 538:         }
 539:         // revert all tlhe way to the gallery
 540:         $hash = $_zp_gallery->getPassword();
 541:         $authType = 'zp_gallery_auth';
 542:         $saved_auth = zp_getCookie($authType);
 543:         if (empty($hash)) {
 544:             $authType = 'zp_public_access';
 545:         } else {
 546:             if ($saved_auth != $hash) {
 547:                 $hint = $_zp_gallery->getPasswordHint();
 548:                 return false;
 549:             }
 550:         }
 551:     } else {
 552:         $authType = "zp_album_auth_" . $album->getID();
 553:         $saved_auth = zp_getCookie($authType);
 554:         if ($saved_auth != $hash) {
 555:             $hint = $album->getPasswordHint();
 556:             return false;
 557:         }
 558:     }
 559:     $_zp_pre_authorization[$albumname] = $authType;
 560:     return $authType;
 561: }
 562: 
 563: /**
 564:  * Returns a consolidated list of plugins
 565:  * The array structure is key=plugin name, value=plugin path
 566:  *
 567:  * @param string $pattern File system wildcard matching pattern to limit the search
 568:  * @param string $folder subfolder within the plugin folders to search
 569:  * @param bool $stripsuffix set to true to remove the suffix from the key name in the array
 570:  * @return array
 571:  */
 572: function getPluginFiles($pattern, $folder = '', $stripsuffix = true) {
 573:     if (!empty($folder) && substr($folder, -1) != '/')
 574:         $folder .= '/';
 575:     $list = array();
 576:     $curdir = getcwd();
 577:     $basepath = SERVERPATH . "/" . USER_PLUGIN_FOLDER . '/' . $folder;
 578:     if (is_dir($basepath)) {
 579:         chdir($basepath);
 580:         $filelist = safe_glob($pattern);
 581:         foreach ($filelist as $file) {
 582:             $key = filesystemToInternal($file);
 583:             if ($stripsuffix) {
 584:                 $key = stripSuffix($key);
 585:             }
 586:             $list[$key] = $basepath . $file;
 587:         }
 588:     }
 589:     $basepath = SERVERPATH . "/" . ZENFOLDER . '/' . PLUGIN_FOLDER . '/' . $folder;
 590:     if (file_exists($basepath)) {
 591:         chdir($basepath);
 592:         $filelist = safe_glob($pattern);
 593:         foreach ($filelist as $file) {
 594:             $key = filesystemToInternal($file);
 595:             if ($stripsuffix) {
 596:                 $key = stripSuffix($key);
 597:             }
 598:             $list[$key] = $basepath . $file;
 599:         }
 600:     }
 601:     chdir($curdir);
 602:     return $list;
 603: }
 604: 
 605: /**
 606:  * Returns the fully qualified file name of the plugin file.
 607:  *
 608:  * Note: order of selection is:
 609:  *  1-theme folder file (if $inTheme is set)
 610:  *  2-user plugin folder file
 611:  *  3-zp-extensions file
 612:  * first file found is used
 613:  *
 614:  * @param string $plugin is the name of the plugin file, typically something.php
 615:  * @param bool $inTheme tells where to find the plugin.
 616:  *   true means look in the current theme
 617:  *   false means look in the zp-core/plugins folder.
 618:  * @param bool $webpath return a WEBPATH rather than a SERVERPATH
 619:  *
 620:  * @return string
 621:  */
 622: function getPlugin($plugin, $inTheme = false, $webpath = false) {
 623:     global $_zp_gallery;
 624:     $pluginFile = NULL;
 625:     if ($inTheme === true) {
 626:         $inTheme = $_zp_gallery->getCurrentTheme();
 627:     }
 628:     if ($inTheme) {
 629:         $pluginFile = '/' . THEMEFOLDER . '/' . internalToFilesystem($inTheme . '/' . $plugin);
 630:         if (!file_exists(SERVERPATH . $pluginFile)) {
 631:             $pluginFile = false;
 632:         }
 633:     }
 634:     if (!$pluginFile) {
 635:         $pluginFile = '/' . USER_PLUGIN_FOLDER . '/' . internalToFilesystem($plugin);
 636:         if (!file_exists(SERVERPATH . $pluginFile)) {
 637:             $pluginFile = '/' . ZENFOLDER . '/' . PLUGIN_FOLDER . '/' . internalToFilesystem($plugin);
 638:             if (!file_exists(SERVERPATH . $pluginFile)) {
 639:                 $pluginFile = false;
 640:             }
 641:         }
 642:     }
 643:     if ($pluginFile) {
 644:         if ($webpath) {
 645:             if (is_string($webpath)) {
 646:                 return $webpath . filesystemToInternal($pluginFile);
 647:             } else {
 648:                 return WEBPATH . filesystemToInternal($pluginFile);
 649:             }
 650:         } else {
 651:             return SERVERPATH . $pluginFile;
 652:         }
 653:     }
 654:     return false;
 655: }
 656: 
 657: /**
 658:  * Returns an array of the currently enabled plugins
 659:  *
 660:  * @return array
 661:  */
 662: function getEnabledPlugins() {
 663:     global $_EnabledPlugins;
 664:     if (is_array($_EnabledPlugins)) {
 665:         return $_EnabledPlugins;
 666:     }
 667:     $_EnabledPlugins = array();
 668:     $sortlist = getPluginFiles('*.php');
 669:     foreach ($sortlist as $extension => $path) {
 670:         $opt = 'zp_plugin_' . $extension;
 671:         if ($option = getOption($opt)) {
 672:             $_EnabledPlugins[$extension] = array('priority' => $option, 'path' => $path);
 673:         }
 674:     }
 675:     $_EnabledPlugins = sortMultiArray($_EnabledPlugins, 'priority', true);
 676:     return $_EnabledPlugins;
 677: }
 678: 
 679: /**
 680:  * Returns if a plugin is enabled
 681:  * @param string $extension
 682:  * @return bool
 683:  */
 684: function extensionEnabled($extension) {
 685:     return getOption('zp_plugin_' . $extension);
 686: }
 687: 
 688: /**
 689:  * Enables a plugin
 690:  * @param string $extension
 691:  * @param int $priority
 692:  * @param bool $persistent
 693:  */
 694: function enableExtension($extension, $priority, $persistent = true) {
 695:     setOption('zp_plugin_' . $extension, $priority, $persistent);
 696: }
 697: 
 698: /**
 699:  * Gets an array of comments for the current admin
 700:  *
 701:  * @param int $number how many comments desired
 702:  * @return array
 703:  */
 704: function fetchComments($number) {
 705:     if ($number) {
 706:         $limit = " LIMIT $number";
 707:     } else {
 708:         $limit = '';
 709:     }
 710: 
 711:     $comments = array();
 712:     if (zp_loggedin(ADMIN_RIGHTS | COMMENT_RIGHTS)) {
 713:         if (zp_loggedin(ADMIN_RIGHTS | MANAGE_ALL_ALBUM_RIGHTS)) {
 714:             $sql = "SELECT *, (date + 0) AS date FROM " . prefix('comments') . " ORDER BY id DESC$limit";
 715:             $comments = query_full_array($sql);
 716:         } else {
 717:             $albumlist = getManagedAlbumList();
 718:             $albumIDs = array();
 719:             foreach ($albumlist as $albumname) {
 720:                 $subalbums = getAllSubAlbumIDs($albumname);
 721:                 foreach ($subalbums as $ID) {
 722:                     $albumIDs[] = $ID['id'];
 723:                 }
 724:             }
 725:             if (count($albumIDs) > 0) {
 726:                 $sql = "SELECT  *, (`date` + 0) AS date FROM " . prefix('comments') . " WHERE ";
 727: 
 728:                 $sql .= " (`type`='albums' AND (";
 729:                 $i = 0;
 730:                 foreach ($albumIDs as $ID) {
 731:                     if ($i > 0) {
 732:                         $sql .= " OR ";
 733:                     }
 734:                     $sql .= "(" . prefix('comments') . ".ownerid=$ID)";
 735:                     $i++;
 736:                 }
 737:                 $sql .= ")) ";
 738:                 $sql .= " ORDER BY id DESC$limit";
 739:                 $albumcomments = query($sql);
 740:                 if ($albumcomments) {
 741:                     while ($comment = db_fetch_assoc($albumcomments)) {
 742:                         $comments[$comment['id']] = $comment;
 743:                     }
 744:                     db_free_result($albumcomments);
 745:                 }
 746:                 $sql = "SELECT *, " . prefix('comments') . ".id as id, " .
 747:                                 prefix('comments') . ".name as name, (" . prefix('comments') . ".date + 0) AS date, " .
 748:                                 prefix('images') . ".`albumid` as albumid," .
 749:                                 prefix('images') . ".`id` as imageid" .
 750:                                 " FROM " . prefix('comments') . "," . prefix('images') . " WHERE ";
 751: 
 752:                 $sql .= "(`type` IN (" . zp_image_types("'") . ") AND (";
 753:                 $i = 0;
 754:                 foreach ($albumIDs as $ID) {
 755:                     if ($i > 0) {
 756:                         $sql .= " OR ";
 757:                     }
 758:                     $sql .= "(" . prefix('comments') . ".ownerid=" . prefix('images') . ".id AND " . prefix('images') . ".albumid=$ID)";
 759:                     $i++;
 760:                 }
 761:                 $sql .= "))";
 762:                 $sql .= " ORDER BY " . prefix('images') . ".`id` DESC$limit";
 763:                 $imagecomments = query($sql);
 764:                 if ($imagecomments) {
 765:                     while ($comment = db_fetch_assoc($imagecomments)) {
 766:                         $comments[$comment['id']] = $comment;
 767:                     }
 768:                     db_free_result($imagecomments);
 769:                 }
 770:                 krsort($comments);
 771:                 if ($number) {
 772:                     if ($number < count($comments)) {
 773:                         $comments = array_slice($comments, 0, $number);
 774:                     }
 775:                 }
 776:             }
 777:         }
 778:     }
 779:     return $comments;
 780: }
 781: 
 782: /**
 783:  * Populates and returns the $_zp_admin_album_list array
 784:  * @return array
 785:  */
 786: function getManagedAlbumList() {
 787:     global $_zp_admin_album_list, $_zp_current_admin_obj;
 788:     $_zp_admin_album_list = array();
 789:     if (zp_loggedin(MANAGE_ALL_ALBUM_RIGHTS)) {
 790:         $sql = "SELECT `folder` FROM " . prefix('albums') . ' WHERE `parentid` IS NULL';
 791:         $albums = query($sql);
 792:         if ($albums) {
 793:             while ($album = db_fetch_assoc($albums)) {
 794:                 $_zp_admin_album_list[$album['folder']] = 32767;
 795:             }
 796:             db_free_result($albums);
 797:         }
 798:     } else {
 799:         if ($_zp_current_admin_obj) {
 800:             $_zp_admin_album_list = array();
 801:             $objects = $_zp_current_admin_obj->getObjects();
 802:             foreach ($objects as $object) {
 803:                 if ($object['type'] == 'album') {
 804:                     $_zp_admin_album_list[$object['data']] = $object['edit'];
 805:                 }
 806:             }
 807:         }
 808:     }
 809:     return array_keys($_zp_admin_album_list);
 810: }
 811: 
 812: /**
 813:  * Returns a list of album names managed by $id
 814:  *
 815:  * @param string $type which kind of object
 816:  * @param int $id admin ID
 817:  * @param bool $rights set true for album sub-rights
 818:  * @return array
 819:  */
 820: function populateManagedObjectsList($type, $id, $rights = false) {
 821:     if ($id <= 0) {
 822:         return array();
 823:     }
 824:     $cv = array();
 825:     if (empty($type) || substr($type, 0, 5) == 'album') {
 826:         $sql = "SELECT " . prefix('albums') . ".`folder`," . prefix('albums') . ".`title`," . prefix('admin_to_object') . ".`edit` FROM " . prefix('albums') . ", " .
 827:                         prefix('admin_to_object') . " WHERE " . prefix('admin_to_object') . ".adminid=" . $id .
 828:                         " AND " . prefix('albums') . ".id=" . prefix('admin_to_object') . ".objectid AND " . prefix('admin_to_object') . ".type LIKE 'album%'";
 829:         $currentvalues = query($sql, false);
 830:         if ($currentvalues) {
 831:             while ($albumitem = db_fetch_assoc($currentvalues)) {
 832:                 $folder = $albumitem['folder'];
 833:                 $name = get_language_string($albumitem['title']);
 834:                 if ($type && !$rights) {
 835:                     $cv[$name] = $folder;
 836:                 } else {
 837:                     $cv[] = array('data' => $folder, 'name' => $name, 'type' => 'album', 'edit' => $albumitem['edit'] + 0);
 838:                 }
 839:             }
 840:             db_free_result($currentvalues);
 841:         }
 842:     }
 843:     if (empty($type) || $type == 'pages') {
 844:         $sql = 'SELECT ' . prefix('pages') . '.`title`,' . prefix('pages') . '.`titlelink` FROM ' . prefix('pages') . ', ' .
 845:                         prefix('admin_to_object') . " WHERE " . prefix('admin_to_object') . ".adminid=" . $id .
 846:                         " AND " . prefix('pages') . ".id=" . prefix('admin_to_object') . ".objectid AND " . prefix('admin_to_object') . ".type='pages'";
 847:         $currentvalues = query($sql, false);
 848:         if ($currentvalues) {
 849:             while ($item = db_fetch_assoc($currentvalues)) {
 850:                 if ($type) {
 851:                     $cv[get_language_string($item['title'])] = $item['titlelink'];
 852:                 } else {
 853:                     $cv[] = array('data' => $item['titlelink'], 'name' => $item['title'], 'type' => 'pages');
 854:                 }
 855:             }
 856:             db_free_result($currentvalues);
 857:         }
 858:     }
 859:     if (empty($type) || $type == 'news') {
 860:         $sql = 'SELECT ' . prefix('news_categories') . '.`titlelink`,' . prefix('news_categories') . '.`title` FROM ' . prefix('news_categories') . ', ' .
 861:                         prefix('admin_to_object') . " WHERE " . prefix('admin_to_object') . ".adminid=" . $id .
 862:                         " AND " . prefix('news_categories') . ".id=" . prefix('admin_to_object') . ".objectid AND " . prefix('admin_to_object') . ".type='news'";
 863:         $currentvalues = query($sql, false);
 864:         if ($currentvalues) {
 865:             while ($item = db_fetch_assoc($currentvalues)) {
 866:                 if ($type) {
 867:                     $cv[get_language_string($item['title'])] = $item['titlelink'];
 868:                 } else {
 869:                     $cv[] = array('data' => $item['titlelink'], 'name' => $item['title'], 'type' => 'news');
 870:                 }
 871:             }
 872:             db_free_result($currentvalues);
 873:         }
 874:     }
 875:     return $cv;
 876: }
 877: 
 878: /**
 879:  * Returns  an array of album ids whose parent is the folder
 880:  * @param string $albumfolder folder name if you want a album different >>from the current album
 881:  * @return array
 882:  */
 883: function getAllSubAlbumIDs($albumfolder = '') {
 884:     global $_zp_current_album;
 885:     if (empty($albumfolder)) {
 886:         if (isset($_zp_current_album)) {
 887:             $albumfolder = $_zp_current_album->getFileName();
 888:         } else {
 889:             return null;
 890:         }
 891:     }
 892:     $query = "SELECT `id`,`folder`, `show` FROM " . prefix('albums') . " WHERE `folder` LIKE " . db_quote(db_LIKE_escape($albumfolder) . '%');
 893:     $subIDs = query_full_array($query);
 894:     return $subIDs;
 895: }
 896: 
 897: /**
 898:  * recovers search parameters from stored cookie, clears the cookie
 899:  *
 900:  * @param string $what the page type
 901:  * @param string $album Name of the album
 902:  * @param string $image Name of the image
 903:  */
 904: function handleSearchParms($what, $album = NULL, $image = NULL) {
 905:     global $_zp_current_search, $zp_request, $_zp_last_album, $_zp_current_album,
 906:     $_zp_current_zenpage_news, $_zp_current_zenpage_page, $_zp_gallery, $_zp_loggedin;
 907:     $_zp_last_album = zp_getCookie('zenphoto_last_album');
 908:     if (is_object($zp_request) && get_class($zp_request) == 'SearchEngine') { //    we are are on a search
 909:         return $zp_request->getAlbumList();
 910:     }
 911:     $params = zp_getCookie('zenphoto_search_params');
 912:     if (!empty($params)) {
 913:         $context = get_context();
 914:         $_zp_current_search = new SearchEngine();
 915:         $_zp_current_search->setSearchParams($params);
 916:         // check to see if we are still "in the search context"
 917:         if (!is_null($image)) {
 918:             $dynamic_album = $_zp_current_search->getDynamicAlbum();
 919:             if ($_zp_current_search->getImageIndex($album->name, $image->filename) !== false) {
 920:                 if ($dynamic_album) {
 921:                     $_zp_current_album = $dynamic_album;
 922:                 }
 923:                 $context = $context | ZP_SEARCH_LINKED | ZP_IMAGE_LINKED;
 924:             }
 925:         }
 926:         if (!is_null($album)) {
 927:             $albumname = $album->name;
 928:             zp_setCookie('zenphoto_last_album', $albumname);
 929:             if (hasDynamicAlbumSuffix($albumname) && !is_dir(ALBUM_FOLDER_SERVERPATH . $albumname)) {
 930:                 $albumname = stripSuffix($albumname); // strip off the suffix as it will not be reflected in the search path
 931:             }
 932:             //  see if the album is within the search context. NB for these purposes we need to look at all albums!
 933:             $save_logon = $_zp_loggedin;
 934:             $_zp_loggedin = $_zp_loggedin | VIEW_ALL_RIGHTS;
 935:             $search_album_list = $_zp_current_search->getAlbums(0);
 936:             $_zp_loggedin = $save_logon;
 937:             foreach ($search_album_list as $searchalbum) {
 938:                 if (strpos($albumname, $searchalbum) !== false) {
 939:                     $context = $context | ZP_SEARCH_LINKED | ZP_ALBUM_LINKED;
 940:                     break;
 941:                 }
 942:             }
 943:         } else {
 944:             zp_clearCookie('zenphoto_last_album');
 945:         }
 946:         if (!is_null($_zp_current_zenpage_page)) {
 947:             $pages = $_zp_current_search->getPages();
 948:             if (!empty($pages)) {
 949:                 $tltlelink = $_zp_current_zenpage_page->getTitlelink();
 950:                 foreach ($pages as $apage) {
 951:                     if ($apage == $tltlelink) {
 952:                         $context = $context | ZP_SEARCH_LINKED;
 953:                         break;
 954:                     }
 955:                 }
 956:             }
 957:         }
 958:         if (!is_null($_zp_current_zenpage_news)) {
 959:             $news = $_zp_current_search->getArticles(0, NULL, true);
 960:             if (!empty($news)) {
 961:                 $tltlelink = $_zp_current_zenpage_news->getTitlelink();
 962:                 foreach ($news as $anews) {
 963:                     if ($anews['titlelink'] == $tltlelink) {
 964:                         $context = $context | ZP_SEARCH_LINKED;
 965:                         break;
 966:                     }
 967:                 }
 968:             }
 969:         }
 970:         if (($context & ZP_SEARCH_LINKED)) {
 971:             set_context($context);
 972:         } else { // not an object in the current search path
 973:             $_zp_current_search = null;
 974:             rem_context(ZP_SEARCH);
 975:             if (!isset($_REQUEST['preserve_serch_params'])) {
 976:                 zp_clearCookie("zenphoto_search_params");
 977:             }
 978:         }
 979:     }
 980: }
 981: 
 982: /**
 983:  *
 984:  * checks if the item has expired
 985:  * @param array $row database row of the object
 986:  */
 987: function checkPublishDates($row) {
 988:     if (@$row['show']) {
 989:         if (isset($row['expiredate']) && $row['expiredate'] && $row['expiredate'] != '0000-00-00 00:00:00') {
 990:             if ($row['expiredate'] <= date('Y-m-d H:i:s')) {
 991:                 return 1;
 992:             }
 993:         }
 994:         if (isset($row['publishdate']) && $row['publishdate'] && $row['publishdate'] != '0000-00-00 00:00:00') {
 995:             if ($row['publishdate'] >= date('Y-m-d H:i:s')) {
 996:                 return 2;
 997:             }
 998:         }
 999:         return null;
1000:     }
1001: }
1002: 
1003: /**
1004:  * Returns the number of album thumbs that go on a gallery page
1005:  *
1006:  * @return int
1007:  */
1008: function galleryAlbumsPerPage() {
1009:     return max(1, getOption('albums_per_page'));
1010: }
1011: 
1012: /**
1013:  * Returns the theme folder
1014:  * If there is an album theme, loads the theme options.
1015:  *
1016:  * @param object $album album object if override desired
1017:  *
1018:  * @return string
1019:  */
1020: function setupTheme($album = NULL) {
1021:     global $_zp_gallery, $_zp_current_album, $_zp_current_search, $_zp_themeroot;
1022:     $albumtheme = '';
1023:     if (is_null($album)) {
1024:         if (in_context(ZP_SEARCH_LINKED)) {
1025:             if (!$album = $_zp_current_search->getDynamicAlbum()) {
1026:                 $album = $_zp_current_album;
1027:             }
1028:         } else {
1029:             $album = $_zp_current_album;
1030:         }
1031:     }
1032:     $theme = $_zp_gallery->getCurrentTheme();
1033:     $id = 0;
1034:     if (!is_null($album)) {
1035:         $parent = getUrAlbum($album);
1036:         $albumtheme = $parent->getAlbumTheme();
1037:         if (!empty($albumtheme)) {
1038:             $theme = $albumtheme;
1039:             $id = $parent->getID();
1040:         }
1041:     }
1042:     $theme = zp_apply_filter('setupTheme', $theme);
1043:     $_zp_gallery->setCurrentTheme($theme);
1044:     $themeindex = getPlugin('index.php', $theme);
1045:     if (empty($theme) || empty($themeindex)) {
1046:         header('Last-Modified: ' . ZP_LAST_MODIFIED);
1047:         header('Content-Type: text/html; charset=' . LOCAL_CHARSET);
1048:         ?>
1049:         <!DOCTYPE html>
1050:         <html xmlns="http://www.w3.org/1999/xhtml">
1051:             <head>
1052:             </head>
1053:             <body>
1054:                 <strong><?php printf(gettext('Zenphoto found no theme scripts. Please check the <em>%s</em> folder of your installation.'), THEMEFOLDER); ?></strong>
1055:             </body>
1056:         </html>
1057:         <?php
1058:         exitZP();
1059:     } else {
1060:         loadLocalOptions($id, $theme);
1061:         $_zp_themeroot = WEBPATH . "/" . THEMEFOLDER . "/$theme";
1062:     }
1063:     return $theme;
1064: }
1065: 
1066: /**
1067:  * Returns an array of unique tag names
1068:  *
1069:  * @param bool $checkaccess Set to true if you wish to exclude tags that are assigned to items (or are not assigned at all) the visitor is not allowed to see
1070:  * Beware that this may cause overhead on large sites. Usage of the static_html_cache plugin is strongely recommended.
1071:  * @return array
1072:  */
1073: function getAllTagsUnique($checkaccess = false) {
1074:   global $_zp_unique_tags, $_zp_unique_tags_excluded;
1075:   if(zp_loggedin(VIEW_ALL_RIGHTS)) {
1076:     $checkaccess = false;
1077:   }
1078:   //need to cache all and filtered tags indiviually
1079:   if ($checkaccess) {
1080:     if (!is_null($_zp_unique_tags_excluded)) {
1081:       return $_zp_unique_tags_excluded; // cache them.
1082:     }
1083:   } else {
1084:     if (!is_null($_zp_unique_tags)) {
1085:       return $_zp_unique_tags; // cache them.
1086:     }
1087:   }
1088:   $all_unique_tags = array();
1089:   $sql = "SELECT DISTINCT `name`, `id` FROM " . prefix('tags') . ' ORDER BY `name`';
1090:   $unique_tags = query($sql);
1091:   if ($unique_tags) {
1092:     while ($tagrow = db_fetch_assoc($unique_tags)) {
1093:       if ($checkaccess) {
1094:         if (getTagCountByAccess($tagrow) != 0) {
1095:           $all_unique_tags[] = $tagrow['name'];
1096:         }
1097:       } else {
1098:         $all_unique_tags[] = $tagrow['name'];
1099:       }
1100:     }
1101:     db_free_result($unique_tags);
1102:   }
1103:   if ($checkaccess) {
1104:     $_zp_unique_tags_excluded = $all_unique_tags;
1105:     return $_zp_unique_tags_excluded;
1106:   } else {
1107:     $_zp_unique_tags = $all_unique_tags;
1108:     return $_zp_unique_tags;
1109:   }
1110: }
1111: 
1112: /**
1113:  * Returns an array indexed by 'tag' with the element value the count of the tag
1114:  *
1115:  * @param bool $exclude_unassigned Set to true if you wish to exclude tags that are not assigne to any item
1116:  * @param bool $checkaccess Set to true if you wish to exclude tags that are assigned to items (or are not assigned at all) the visitor is not allowed to see
1117:  * If set to true it overrides the $exclude_unassigned parameter.
1118:  * Beware that this may cause overhead on large sites. Usage of the static_html_cache plugin is strongely recommended.
1119:  * @return array
1120:  */
1121: function getAllTagsCount($exclude_unassigned = false, $checkaccess = false) {
1122:   global $_zp_count_tags;
1123:   if (!is_null($_zp_count_tags)) {
1124:     return $_zp_count_tags;
1125:   }
1126:   if(zp_loggedin(VIEW_ALL_RIGHTS)) {
1127:     $exclude_unassigned = false;
1128:     $checkaccess = false;
1129:   }
1130:   $_zp_count_tags = array();
1131:   $sql = "SELECT DISTINCT tags.name, tags.id, (SELECT COUNT(*) FROM " . prefix('obj_to_tag') . " as object WHERE object.tagid = tags.id) AS count FROM " . prefix('tags') . " as tags ORDER BY `name`";
1132:   $tagresult = query($sql);
1133:   if ($tagresult) {
1134:     while ($tag = db_fetch_assoc($tagresult)) {
1135:       if($checkaccess) {
1136:         $count = getTagCountByAccess($tag);
1137:         if($count != 0) {
1138:           $_zp_count_tags[$tag['name']] = $count;
1139:         }
1140:       } else {
1141:         if($exclude_unassigned) {
1142:           if($tag['count'] != 0) {
1143:             $_zp_count_tags[$tag['name']] = $tag['count'];
1144:           }
1145:         } else {
1146:           $_zp_count_tags[$tag['name']] = $tag['count'];
1147:         }
1148:       }
1149:     }
1150:     db_free_result($tagresult);
1151:   }
1152:   return $_zp_count_tags;
1153: }
1154: 
1155: /**
1156:  * Checks if a tag is assigned at all and if it can be viewed by the current visitor and returns the corrected count
1157:  * Helper function used optionally within getAllTagsCount() and getAllTagsUnique()
1158:  *
1159:  * @global obj $_zp_zenpage
1160:  * @param array $tag Array representing a tag containing at least its name and id
1161:  * @return int
1162:  */
1163: function getTagCountByAccess($tag) {
1164:   global $_zp_zenpage, $_zp_object_to_tags;
1165:   if (array_key_exists('count', $tag) && $tag['count'] == 0) {
1166:     return $tag['count'];
1167:   }
1168:   $hidealbums = getNotViewableAlbums();
1169:   $hideimages = getNotViewableImages();
1170:   $hidenews = array();
1171:   $hidepages = array();
1172:   if (extensionEnabled('Zenpage')) {
1173:     $hidenews = $_zp_zenpage->getNotViewableNews();
1174:     $hidepages = $_zp_zenpage->getNotViewablePages();
1175:   }
1176:   //skip checks if there are no unviewable items at all
1177:   if (empty($hidealbums) && empty($hideimages) && empty($hidenews) && empty($hidepages)) {
1178:     if (array_key_exists('count', $tag)) {
1179:       return $tag['count'];
1180:     }
1181:     return 0;
1182:   }
1183:   if (is_null($_zp_object_to_tags)) {
1184:     $sql = "SELECT tagid, type, objectid FROM " . prefix('obj_to_tag') . " ORDER BY tagid";
1185:     $_zp_object_to_tags = query_full_array($sql);
1186:   }
1187:   $count = '';
1188:   if ($_zp_object_to_tags) {
1189:     foreach($_zp_object_to_tags as $tagcheck) {
1190:       if ($tagcheck['tagid'] == $tag['id']) {
1191:         switch ($tagcheck['type']) {
1192:           case 'albums':
1193:             if (!in_array($tagcheck['objectid'], $hidealbums)) {
1194:               $count++;
1195:             }
1196:             break;
1197:           case 'images':
1198:             if (!in_array($tagcheck['objectid'], $hideimages)) {
1199:               $count++;
1200:             }
1201:             break;
1202:           case 'news':
1203:             if (extensionEnabled('Zenpage') && ZP_NEWS_ENABLED) {
1204:               if (!in_array($tagcheck['objectid'], $hidenews)) {
1205:                 $count++;
1206:               }
1207:             }
1208:             break;
1209:           case 'pages':
1210:             if (extensionEnabled('Zenpage') && ZP_PAGES_ENABLED) {
1211:               if (!in_array($tagcheck['objectid'], $hidepages)) {
1212:                 $count++;
1213:               }
1214:             }
1215:             break;
1216:         }
1217:       }
1218:     }
1219:   }
1220:   if (empty($count)) {
1221:     $count = 0;
1222:   }
1223:   return $count;
1224: }
1225: 
1226: /**
1227:  * Stores tags for an object
1228:  *
1229:  * @param array $tags the tag values
1230:  * @param int $id the record id of the album/image
1231:  * @param string $tbl database table of the object
1232:  */
1233: function storeTags($tags, $id, $tbl) {
1234:     if ($id) {
1235:         $tagsLC = array();
1236:         foreach ($tags as $key => $tag) {
1237:             $tag = trim($tag);
1238:             if (!empty($tag)) {
1239:                 $lc_tag = mb_strtolower($tag);
1240:                 if (!in_array($lc_tag, $tagsLC)) {
1241:                     $tagsLC[$tag] = $lc_tag;
1242:                 }
1243:             }
1244:         }
1245:         $sql = "SELECT `id`, `tagid` from " . prefix('obj_to_tag') . " WHERE `objectid`='" . $id . "' AND `type`='" . $tbl . "'";
1246:         $result = query($sql);
1247:         $existing = array();
1248:         if ($result) {
1249:             while ($row = db_fetch_assoc($result)) {
1250:                 $dbtag = query_single_row("SELECT `name` FROM " . prefix('tags') . " WHERE `id`='" . $row['tagid'] . "'");
1251:                 $existingLC = mb_strtolower($dbtag['name']);
1252:                 if (in_array($existingLC, $tagsLC)) { // tag already set no action needed
1253:                     $existing[] = $existingLC;
1254:                 } else { // tag no longer set, remove it
1255:                     query("DELETE FROM " . prefix('obj_to_tag') . " WHERE `id`='" . $row['id'] . "'");
1256:                 }
1257:             }
1258:             db_free_result($result);
1259:         }
1260:         $tags = array_diff($tagsLC, $existing); // new tags for the object
1261:         foreach ($tags as $key => $tag) {
1262:             $dbtag = query_single_row("SELECT `id` FROM " . prefix('tags') . " WHERE `name`=" . db_quote($key));
1263:             if (!is_array($dbtag)) { // tag does not exist
1264:                 query("INSERT INTO " . prefix('tags') . " (name) VALUES (" . db_quote($key) . ")", false);
1265:                 $dbtag = array('id' => db_insert_id());
1266:             }
1267:             query("INSERT INTO " . prefix('obj_to_tag') . "(`objectid`, `tagid`, `type`) VALUES (" . $id . "," . $dbtag['id'] . ",'" . $tbl . "')");
1268:         }
1269:     }
1270: }
1271: 
1272: /**
1273:  * Retrieves the tags for an object
1274:  * Returns them in an array
1275:  *
1276:  * @param int $id the record id of the album/image
1277:  * @param string $tbl 'albums' or 'images', etc.
1278:  * @return unknown
1279:  */
1280: function readTags($id, $tbl) {
1281:     $tags = array();
1282:     $result = query("SELECT `tagid` FROM " . prefix('obj_to_tag') . " WHERE `type`='" . $tbl . "' AND `objectid`='" . $id . "'");
1283:     if ($result) {
1284:         while ($row = db_fetch_assoc($result)) {
1285:             $dbtag = query_single_row("SELECT `name` FROM" . prefix('tags') . " WHERE `id`='" . $row['tagid'] . "'");
1286:             if ($dbtag) {
1287:                 $tags[] = $dbtag['name'];
1288:             }
1289:         }
1290:         db_free_result($result);
1291:     }
1292:     natcasesort($tags);
1293:     return $tags;
1294: }
1295: 
1296: /**
1297:  * Creates the body of a select list
1298:  *
1299:  * @param array $currentValue list of items to be flagged as checked
1300:  * @param array $list the elements of the select list
1301:  * @param bool $descending set true for a reverse order sort
1302:  */
1303: function generateListFromArray($currentValue, $list, $descending, $localize) {
1304:     if ($localize) {
1305:         $list = array_flip($list);
1306:         if ($descending) {
1307:             arsort($list);
1308:         } else {
1309:             natcasesort($list);
1310:         }
1311:         $list = array_flip($list);
1312:     } else {
1313:         if ($descending) {
1314:             rsort($list);
1315:         } else {
1316:             natcasesort($list);
1317:         }
1318:     }
1319:     foreach ($list as $key => $item) {
1320:         echo '<option value="' . html_encode($item) . '"';
1321:         if (in_array($item, $currentValue)) {
1322:             echo ' selected="selected"';
1323:         }
1324:         if ($localize)
1325:             $display = $key;
1326:         else
1327:             $display = $item;
1328:         echo '>' . $display . "</option>" . "\n";
1329:     }
1330: }
1331: 
1332: /**
1333:  * Generates a selection list from files found on disk
1334:  *
1335:  * @param strig $currentValue the current value of the selector
1336:  * @param string $root directory path to search
1337:  * @param string $suffix suffix to select for
1338:  * @param bool $descending set true to get a reverse order sort
1339:  */
1340: function generateListFromFiles($currentValue, $root, $suffix, $descending = false) {
1341:     if (is_dir($root)) {
1342:         $curdir = getcwd();
1343:         chdir($root);
1344:         $filelist = safe_glob('*' . $suffix);
1345:         $list = array();
1346:         foreach ($filelist as $file) {
1347:             $file = str_replace($suffix, '', $file);
1348:             $list[] = filesystemToInternal($file);
1349:         }
1350:         generateListFromArray(array($currentValue), $list, $descending, false);
1351:         chdir($curdir);
1352:     }
1353: }
1354: 
1355: /**
1356:  * @param string $url The link URL
1357:  * @param string $text The text to go with the link
1358:  * @param string $title Text for the title tag
1359:  * @param string $class optional class
1360:  * @param string $id optional id
1361:  */
1362: function getLinkHTML($url, $text, $title = NULL, $class = NULL, $id = NULL) {
1363:     return "<a href=\"" . html_encode($url) . "\"" .
1364:                     (($title) ? " title=\"" . html_encode(getBare($title)) . "\"" : "") .
1365:                     (($class) ? " class=\"$class\"" : "") .
1366:                     (($id) ? " id=\"$id\"" : "") . ">" .
1367:                     html_encode($text) . "</a>";
1368: }
1369: 
1370: /**
1371:  * General link printing function
1372:  * @param string $url The link URL
1373:  * @param string $text The text to go with the link
1374:  * @param string $title Text for the title tag
1375:  * @param string $class optional class
1376:  * @param string $id optional id
1377:  */
1378: function printLinkHTML($url, $text, $title = NULL, $class = NULL, $id = NULL) {
1379:     echo getLinkHTML($url, $text, $title, $class, $id);
1380: }
1381: 
1382: /**
1383:  * shuffles an array maintaining the keys
1384:  *
1385:  * @param array $array
1386:  * @return boolean
1387:  */
1388: function shuffle_assoc(&$array) {
1389:     $keys = array_keys($array);
1390:     shuffle($keys);
1391:     foreach ($keys as $key) {
1392:         $new[$key] = $array[$key];
1393:     }
1394:     $array = $new;
1395:     return true;
1396: }
1397: 
1398: /**
1399:  * sorts the found albums (images) by the required key(s)
1400:  *
1401:  * NB: this sort is sensitive to the key(s) chosen and makes
1402:  * the appropriate sorts based on same. Some multi-key sorts
1403:  * will not make any sense and will give unexpected results.
1404:  * Most notably any that contain the keys "title" or "desc"
1405:  * as these require multi-lingual sorts.
1406:  *
1407:  * @param array $results
1408:  * @param string $sortkey
1409:  * @param string $order
1410:  */
1411: function sortByKey($results, $sortkey, $order) {
1412:     $sortkey = str_replace('`', '', $sortkey);
1413:     switch ($sortkey) {
1414:         case 'title':
1415:         case 'desc':
1416:             return sortByMultilingual($results, $sortkey, $order);
1417:         case 'RAND()':
1418:             shuffle($results);
1419:             return $results;
1420:         default:
1421:             if (preg_match('`[\/\(\)\*\+\-!\^\%\<\>\=\&\|]`', $sortkey)) {
1422:                 return $results; // We cannot deal with expressions
1423:             }
1424:     }
1425:     $indicies = explode(',', $sortkey);
1426:     foreach ($indicies as $key => $index) {
1427:         $indicies[$key] = trim($index);
1428:     }
1429:     $results = sortMultiArray($results, $indicies, $order, true, false, true);
1430:     return $results;
1431: }
1432: 
1433: /**
1434:  * multidimensional array column sort
1435:  *
1436:  * @param array $array The multidimensional array to be sorted
1437:  * @param mixed $index Which key(s) should be sorted by
1438:  * @param string $order true for descending sorts
1439:  * @param bool $natsort If natural order should be used
1440:  * @param bool $case_sensitive If the sort should be case sensitive
1441:  * @return array
1442:  *
1443:  * @author redoc (http://codingforums.com/showthread.php?t=71904)
1444:  */
1445: function sortMultiArray($array, $index, $descending = false, $natsort = true, $case_sensitive = false, $preservekeys = false, $remove_criteria = array()) {
1446:     if (is_array($array) && count($array) > 0) {
1447:         if (is_array($index)) {
1448:             $indicies = $index;
1449:         } else {
1450:             $indicies = array($index);
1451:         }
1452:         if ($descending) {
1453:             $separator = '~~';
1454:         } else {
1455:             $separator = '  ';
1456:         }
1457:         foreach ($array as $key => $row) {
1458:             $temp[$key] = '';
1459:             foreach ($indicies as $index) {
1460:                 if (is_array($row) && array_key_exists($index, $row)) {
1461:                     $temp[$key] .= get_language_string($row[$index]) . $separator;
1462:                     if (in_array($index, $remove_criteria)) {
1463:                         unset($array[$key][$index]);
1464:                     }
1465:                 }
1466:             }
1467:             $temp[$key] .= $key;
1468:         }
1469:         if ($natsort) {
1470:             if ($case_sensitive) {
1471:                 natsort($temp);
1472:             } else {
1473:                 natcasesort($temp);
1474:             }
1475:             if ($descending) {
1476:                 $temp = array_reverse($temp, TRUE);
1477:             }
1478:         } else {
1479:             if ($descending) {
1480:                 arsort($temp);
1481:             } else {
1482:                 asort($temp);
1483:             }
1484:         }
1485:         foreach (array_keys($temp) as $key) {
1486:             if (!$preservekeys && is_numeric($key)) {
1487:                 $sorted[] = $array[$key];
1488:             } else {
1489:                 $sorted[$key] = $array[$key];
1490:             }
1491:         }
1492:         return $sorted;
1493:     }
1494:     return $array;
1495: }
1496: 
1497: /**
1498:  * Returns a list of album IDs that the current viewer is not allowed to see
1499:  *
1500:  * @return array
1501:  */
1502: function getNotViewableAlbums() {
1503:     global $_zp_not_viewable_album_list;
1504:     if (zp_loggedin(ADMIN_RIGHTS | MANAGE_ALL_ALBUM_RIGHTS))
1505:         return array(); //admins can see all
1506:     if (is_null($_zp_not_viewable_album_list)) {
1507:         $sql = 'SELECT `folder`, `id`, `password`, `show` FROM ' . prefix('albums') . ' WHERE `show`=0 OR `password`!=""';
1508:         $result = query($sql);
1509:         if ($result) {
1510:             $_zp_not_viewable_album_list = array();
1511:             while ($row = db_fetch_assoc($result)) {
1512:                 if (checkAlbumPassword($row['folder'])) {
1513:                     $album = newAlbum($row['folder']);
1514:                     if (!($row['show'] || $album->isMyItem(LIST_RIGHTS))) {
1515:                         $_zp_not_viewable_album_list[] = $row['id'];
1516:                     }
1517:                 } else {
1518:                     $_zp_not_viewable_album_list[] = $row['id'];
1519:                 }
1520:             }
1521:             db_free_result($result);
1522:         }
1523:     }
1524:     return $_zp_not_viewable_album_list;
1525: }
1526: 
1527: /**
1528:  * Returns a list of image IDs that the current viewer is not allowed to see
1529:  *
1530:  * @return array
1531:  */
1532: function getNotViewableImages() {
1533:   global $_zp_not_viewable_image_list;
1534:   if (zp_loggedin(ADMIN_RIGHTS | MANAGE_ALL_ALBUM_RIGHTS)) {
1535:     return array(); //admins can see all
1536:   }
1537:   $hidealbums = getNotViewableAlbums();
1538:   $where = '';
1539:   if (!is_null($hidealbums)) {
1540:     $where = implode(',', $hidealbums);
1541:   }
1542:   if (is_null($_zp_not_viewable_image_list)) {
1543:     $sql = 'SELECT DISTINCT `id` FROM ' . prefix('images') . ' WHERE `show` = 0 OR `albumid` in (' . $where . ')';
1544:     $result = query($sql);
1545:     if ($result) {
1546:       $_zp_not_viewable_image_list = array();
1547:       while ($row = db_fetch_assoc($result)) {
1548:         $_zp_not_viewable_image_list[] = $row['id'];
1549:       }
1550:     }
1551:   }
1552:   return $_zp_not_viewable_image_list;
1553: }
1554: 
1555:   /**
1556:  * Checks to see if a URL is valid
1557:  *
1558:  * @param string $url the URL being checked
1559:  * @return bool
1560:  */
1561: function isValidURL($url) {
1562:     return preg_match('|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i', $url);
1563: }
1564: 
1565: /**
1566:  * pattern match function Works with characters with diacritical marks where the PHP one does not.
1567:  *
1568:  * @param string $pattern pattern
1569:  * @param string $string haystack
1570:  * @return bool
1571:  */
1572: function safe_fnmatch($pattern, $string) {
1573:     return @preg_match('/^' . strtr(addcslashes($pattern, '\\.+^$(){}=!<>|'), array('*' => '.*', '?' => '.?')) . '$/i', $string);
1574: }
1575: 
1576: /**
1577:  * returns a list of comment record 'types' for "images"
1578:  * @param string $quote quotation mark to use
1579:  *
1580:  * @return string
1581:  */
1582: function zp_image_types($quote) {
1583:     global $_zp_extra_filetypes;
1584:     $typelist = $quote . 'images' . $quote . ',' . $quote . '_images' . $quote . ',';
1585:     $types = array_unique($_zp_extra_filetypes);
1586:     foreach ($types as $type) {
1587:         $typelist .= $quote . strtolower($type) . 's' . $quote . ',';
1588:     }
1589:     return substr($typelist, 0, -1);
1590: }
1591: 
1592: /**
1593: 
1594:  * Returns video argument of the current Image.
1595:  *
1596:  * @param object $image optional image object
1597:  * @return bool
1598:  */
1599: function isImageVideo($image = NULL) {
1600:     if (is_null($image)) {
1601:         if (!in_context(ZP_IMAGE))
1602:             return false;
1603:         global $_zp_current_image;
1604:         $image = $_zp_current_image;
1605:     }
1606:     return strtolower(get_class($image)) == 'video';
1607: }
1608: 
1609: /**
1610:  * Returns true if the image is a standard photo type
1611:  *
1612:  * @param object $image optional image object
1613:  * @return bool
1614:  */
1615: function isImagePhoto($image = NULL) {
1616:     if (is_null($image)) {
1617:         if (!in_context(ZP_IMAGE))
1618:             return false;
1619:         global $_zp_current_image;
1620:         $image = $_zp_current_image;
1621:     }
1622:     $class = strtolower(get_class($image));
1623:     return $class == 'image' || $class == 'transientimage';
1624: }
1625: 
1626: /**
1627:  * Copies a directory recursively
1628:  * @param string $srcdir the source directory.
1629:  * @param string $dstdir the destination directory.
1630:  * @return the total number of files copied.
1631:  */
1632: function dircopy($srcdir, $dstdir) {
1633:     $num = 0;
1634:     if (!is_dir($dstdir))
1635:         mkdir($dstdir);
1636:     if ($curdir = opendir($srcdir)) {
1637:         while ($file = readdir($curdir)) {
1638:             if ($file != '.' && $file != '..') {
1639:                 $srcfile = $srcdir . '/' . $file;
1640:                 $dstfile = $dstdir . '/' . $file;
1641:                 if (is_file($srcfile)) {
1642:                     if (is_file($dstfile))
1643:                         $ow = filemtime($srcfile) - filemtime($dstfile);
1644:                     else
1645:                         $ow = 1;
1646:                     if ($ow > 0) {
1647:                         if (copy($srcfile, $dstfile)) {
1648:                             touch($dstfile, filemtime($srcfile));
1649:                             $num++;
1650:                         }
1651:                     }
1652:                 } else if (is_dir($srcfile)) {
1653:                     $num += dircopy($srcfile, $dstfile);
1654:                 }
1655:             }
1656:         }
1657:         closedir($curdir);
1658:     }
1659:     return $num;
1660: }
1661: 
1662: /**
1663:  * Returns a byte size from a size value (eg: 100M).
1664:  *
1665:  * @param int $bytes
1666:  * @return string
1667:  */
1668: function byteConvert($bytes) {
1669:     if ($bytes <= 0)
1670:         return gettext('0 Bytes');
1671:     $convention = 1024; //[1000->10^x|1024->2^x]
1672:     $s = array('Bytes', 'kB', 'mB', 'GB', 'TB', 'PB', 'EB', 'ZB');
1673:     $e = floor(log($bytes, $convention));
1674:     return round($bytes / pow($convention, $e), 2) . ' ' . $s[$e];
1675: }
1676: 
1677: /**
1678:  * Converts a datetime to connoical form
1679:  *
1680:  * @param string $datetime input date/time string
1681:  * @param bool $raw set to true to return the timestamp otherwise you get a string
1682:  * @return mixed
1683:  */
1684: function dateTimeConvert($datetime, $raw = false) {
1685:     // Convert 'yyyy:mm:dd hh:mm:ss' to 'yyyy-mm-dd hh:mm:ss' for Windows' strtotime compatibility
1686:     $datetime = preg_replace('/(\d{4}):(\d{2}):(\d{2})/', ' \1-\2-\3', $datetime);
1687:     $time = strtotime($datetime);
1688:     if ($time == -1 || $time === false)
1689:         return false;
1690:     if ($raw)
1691:         return $time;
1692:     return date('Y-m-d H:i:s', $time);
1693: }
1694: 
1695: /* * * Context Manipulation Functions ****** */
1696: /* * *************************************** */
1697: 
1698: /* Contexts are simply constants that tell us what variables are available to us
1699:  * at any given time. They should be set and unset with those variables.
1700:  */
1701: 
1702: function get_context() {
1703:     global $_zp_current_context;
1704:     return $_zp_current_context;
1705: }
1706: 
1707: function set_context($context) {
1708:     global $_zp_current_context;
1709:     $_zp_current_context = $context;
1710: }
1711: 
1712: function in_context($context) {
1713:     return get_context() & $context;
1714: }
1715: 
1716: function add_context($context) {
1717:     set_context(get_context() | $context);
1718: }
1719: 
1720: function rem_context($context) {
1721:     global $_zp_current_context;
1722:     set_context(get_context() & ~$context);
1723: }
1724: 
1725: // Use save and restore rather than add/remove when modifying contexts.
1726: function save_context() {
1727:     global $_zp_current_context, $_zp_current_context_stack;
1728:     array_push($_zp_current_context_stack, $_zp_current_context);
1729: }
1730: 
1731: function restore_context() {
1732:     global $_zp_current_context, $_zp_current_context_stack;
1733:     $_zp_current_context = array_pop($_zp_current_context_stack);
1734: }
1735: 
1736: /**
1737:  *
1738:  * Sanitizes a "redirect" post
1739:  * @param string $redirectTo
1740:  * @return string
1741:  */
1742: function sanitizeRedirect($redirectTo, $forceHost = false) {
1743:     $redirect = NULL;
1744:     if ($redirectTo && $redir = parse_url($redirectTo)) {
1745:         if (isset($redir['scheme']) && isset($redir['host'])) {
1746:             $redirect .= $redir['scheme'] . '://' . sanitize($redir['host']);
1747:         } else {
1748:             if ($forceHost) {
1749:                 $redirect .= PROTOCOL . '://' . $_SERVER['HTTP_HOST'];
1750:                 if (WEBPATH && strpos($redirectTo, WEBPATH) === false) {
1751:                     $redirect .= WEBPATH;
1752:                 }
1753:             }
1754:         }
1755:         if (isset($redir['path'])) {
1756:             $redirect .= urldecode(sanitize($redir['path']));
1757:         }
1758:         if (isset($redir['query'])) {
1759:             $redirect .= '?' . sanitize($redir['query']);
1760:         }
1761:         if (isset($redir['fragment'])) {
1762:             $redirect .= '#' . sanitize($redir['fragment']);
1763:         }
1764:     }
1765:     return $redirect;
1766: }
1767: 
1768: /**
1769:  * checks password posting
1770:  *
1771:  * @param string $authType override of athorization type
1772:  */
1773: function zp_handle_password($authType = NULL, $check_auth = NULL, $check_user = NULL) {
1774:     global $_zp_loggedin, $_zp_login_error, $_zp_current_album, $_zp_current_zenpage_page, $_zp_current_category, $_zp_current_zenpage_news, $_zp_gallery;
1775:     if (empty($authType)) { // not supplied by caller
1776:         $check_auth = '';
1777:         if (isset($_GET['z']) && @$_GET['p'] == 'full-image' || isset($_GET['p']) && $_GET['p'] == '*full-image') {
1778:             $authType = 'zp_image_auth';
1779:             $check_auth = getOption('protected_image_password');
1780:             $check_user = getOption('protected_image_user');
1781:         } else if (in_context(ZP_SEARCH)) { // search page
1782:             $authType = 'zp_search_auth';
1783:             $check_auth = getOption('search_password');
1784:             $check_user = getOption('search_user');
1785:         } else if (in_context(ZP_ALBUM)) { // album page
1786:             $authType = "zp_album_auth_" . $_zp_current_album->getID();
1787:             $check_auth = $_zp_current_album->getPassword();
1788:             $check_user = $_zp_current_album->getUser();
1789:             if (empty($check_auth)) {
1790:                 $parent = $_zp_current_album->getParent();
1791:                 while (!is_null($parent)) {
1792:                     $check_auth = $parent->getPassword();
1793:                     $check_user = $parent->getUser();
1794:                     $authType = "zp_album_auth_" . $parent->getID();
1795:                     if (!empty($check_auth)) {
1796:                         break;
1797:                     }
1798:                     $parent = $parent->getParent();
1799:                 }
1800:             }
1801:         } else if (in_context(ZP_ZENPAGE_PAGE)) {
1802:             $authType = "zp_page_auth_" . $_zp_current_zenpage_page->getID();
1803:             $check_auth = $_zp_current_zenpage_page->getPassword();
1804:             $check_user = $_zp_current_zenpage_page->getUser();
1805:             if (empty($check_auth)) {
1806:                 $pageobj = $_zp_current_zenpage_page;
1807:                 while (empty($check_auth)) {
1808:                     $parentID = $pageobj->getParentID();
1809:                     if ($parentID == 0)
1810:                         break;
1811:                     $sql = 'SELECT `titlelink` FROM ' . prefix('pages') . ' WHERE `id`=' . $parentID;
1812:                     $result = query_single_row($sql);
1813:                     $pageobj = new ZenpagePage($result['titlelink']);
1814:                     $authType = "zp_page_auth_" . $pageobj->getID();
1815:                     $check_auth = $pageobj->getPassword();
1816:                     $check_user = $pageobj->getUser();
1817:                 }
1818:             }
1819:         } else if (in_context(ZP_ZENPAGE_NEWS_CATEGORY) || in_context(ZP_ZENPAGE_NEWS_ARTICLE)) {
1820:             $check_auth_user = array();
1821:             if (in_context(ZP_ZENPAGE_NEWS_CATEGORY)) {
1822:                 $checkcats = array($_zp_current_category);
1823:             } else if (in_context(ZP_ZENPAGE_NEWS_ARTICLE)) {
1824:                 $checkcats = array();
1825:                 $cats = $_zp_current_zenpage_news->getCategories();
1826:                 foreach ($cats as $cat) {
1827:                     $checkcats[] = new ZenpageCategory($cat['titlelink']);
1828:                 }
1829:             }
1830:             if (!empty($checkcats)) {
1831:                 foreach ($checkcats as $obj) {
1832:                     $authType = "zp_category_auth_" .  $obj->getID();
1833:                     $check_auth =  $obj->getPassword();
1834:                     $check_user =  $obj->getUser();
1835:                     if (empty($check_auth)) {
1836:                         $catobj =  $obj;
1837:                         while (empty($check_auth)) {
1838:                             $parentID = $catobj->getParentID();
1839:                             if ($parentID == 0)
1840:                                 break;
1841:                             $sql = 'SELECT `titlelink` FROM ' . prefix('news_categories') . ' WHERE `id`=' . $parentID;
1842:                             $result = query_single_row($sql);
1843:                             $catobj = new ZenpageCategory($result['titlelink']);
1844:                             $authType = "zp_category_auth_" . $catobj->getID();
1845:                             $check_auth = $catobj->getPassword();
1846:                             $check_user = $catobj->getUser();
1847:                         }
1848:                     }
1849:                     if(!empty($check_auth)) {
1850:                         //collect passwords from all categories
1851:                         $check_auth_user[] = array(
1852:                             'authtype' => $authType,
1853:                             'check_auth' => $check_auth, 
1854:                             'check_user' => $check_user
1855:                         );
1856:                     }
1857:                 }
1858:             }
1859:         }
1860:         if (empty($check_auth)) { // anything else is controlled by the gallery credentials
1861:             $authType = 'zp_gallery_auth';
1862:             $check_auth = $_zp_gallery->getPassword();
1863:             $check_user = $_zp_gallery->getUser();
1864:         }
1865:     }
1866:     if (in_context(ZP_ZENPAGE_NEWS_ARTICLE)) {
1867:         //check every category with password individually
1868:         foreach($check_auth_user as $check) {
1869:             zp_handle_password_single($check['authtype'], $check['check_auth'], $check['check_user']);
1870:         }
1871:     } else {
1872:         zp_handle_password_single($authType, $check_auth, $check_user);
1873:     }
1874: }
1875: /**
1876:  * Handles a passwort 
1877:  * 
1878:  * @param string $authType override of authorization type
1879:  * @param string $check_auth Password
1880:  * @param string $check_user User
1881:  * @return bool
1882:  */
1883: function zp_handle_password_single($authType = NULL, $check_auth = NULL, $check_user = NULL) {
1884:     // Handle the login form.
1885:     if (DEBUG_LOGIN)
1886:         debugLog("zp_handle_password: \$authType=$authType; \$check_auth=$check_auth; \$check_user=$check_user; ");
1887: 
1888:     if (isset($_POST['password']) && isset($_POST['pass'])) { // process login form
1889:         if (isset($_POST['user'])) {
1890:             $post_user = sanitize($_POST['user']);
1891:         } else {
1892:             $post_user = '';
1893:         }
1894:         $post_pass = $_POST['pass']; // We should not sanitize the password
1895: 
1896:         foreach (Zenphoto_Authority::$hashList as $hash => $hi) {
1897:             $auth = Zenphoto_Authority::passwordHash($post_user, $post_pass, $hi);
1898:             $success = ($auth == $check_auth) && $post_user == $check_user;
1899:             if (DEBUG_LOGIN)
1900:                 debugLog("zp_handle_password($success): \$post_user=$post_user; \$post_pass=$post_pass; \$check_auth=$check_auth; \$auth=$auth; \$hash=$hash;");
1901:             if ($success) {
1902:                 break;
1903:             }
1904:         }
1905:         $success = zp_apply_filter('guest_login_attempt', $success, $post_user, $post_pass, $authType);
1906:         if ($success) {
1907:             // Correct auth info. Set the cookie.
1908:             if (DEBUG_LOGIN)
1909:                 debugLog("zp_handle_password: valid credentials");
1910:             zp_setCookie($authType, $auth);
1911:             if (isset($_POST['redirect'])) {
1912:                 $redirect_to = sanitizeRedirect($_POST['redirect'], true);
1913:                 if (!empty($redirect_to)) {
1914:                     header("Location: " . $redirect_to);
1915:                     exitZP();
1916:                 }
1917:             }
1918:         } else {
1919:             // Clear the cookie, just in case
1920:             if (DEBUG_LOGIN)
1921:                 debugLog("zp_handle_password: invalid credentials");
1922:             zp_clearCookie($authType);
1923:             $_zp_login_error = true;
1924:         }
1925:         return;
1926:     }
1927:     if (empty($check_auth)) { //no password on record or admin logged in
1928:         return;
1929:     }
1930:     if (($saved_auth = zp_getCookie($authType)) != '') {
1931:         if ($saved_auth == $check_auth) {
1932:             if (DEBUG_LOGIN)
1933:                 debugLog("zp_handle_password: valid cookie");
1934:             return;
1935:         } else {
1936:             // Clear the cookie
1937:             if (DEBUG_LOGIN)
1938:                 debugLog("zp_handle_password: invalid cookie");
1939:             zp_clearCookie($authType);
1940:         }
1941:     }
1942: }
1943: 
1944: /**
1945:  *
1946:  * Gets an option directly from the database.
1947:  * @param string $key
1948:  */
1949: function getOptionFromDB($key) {
1950:     $sql = "SELECT `value` FROM " . prefix('options') . " WHERE `name`=" . db_quote($key) . " AND `ownerid`=0";
1951:     $optionlist = query_single_row($sql, false);
1952:     return @$optionlist['value'];
1953: }
1954: 
1955: /**
1956:  * Set options local to theme and/or album
1957:  *
1958:  * @param string $key
1959:  * @param string $value
1960:  * @param object $album
1961:  * @param string $theme default theme
1962:  * @param bool $default set to true for setting default theme options (does not set the option if it already exists)
1963:  */
1964: function setThemeOption($key, $value, $album, $theme, $default = false) {
1965:     global $_zp_gallery;
1966:     if (is_null($album)) {
1967:         $id = 0;
1968:     } else {
1969:         $id = $album->getID();
1970:         $theme = $album->getAlbumTheme();
1971:     }
1972:     $creator = THEMEFOLDER . '/' . $theme;
1973: 
1974:     $sql = 'INSERT INTO ' . prefix('options') . ' (`name`,`ownerid`,`theme`,`creator`,`value`) VALUES (' . db_quote($key) . ',0,' . db_quote($theme) . ',' . db_quote($creator) . ',';
1975:     $sqlu = ' ON DUPLICATE KEY UPDATE `value`=';
1976:     if (is_null($value)) {
1977:         $sql .= 'NULL';
1978:         $sqlu .= 'NULL';
1979:     } else {
1980:         $sql .= db_quote($value);
1981:         $sqlu .= db_quote($value);
1982:     }
1983:     $sql .= ') ';
1984:     if (!$default) {
1985:         $sql .= $sqlu;
1986:     }
1987:     $result = query($sql, false);
1988: }
1989: 
1990: /**
1991:  * Used to set default values for theme specific options
1992:  *
1993:  * @param string $key
1994:  * @param mixed $value
1995:  */
1996: function setThemeOptionDefault($key, $value) {
1997:     $bt = debug_backtrace();
1998:     $b = array_shift($bt);
1999:     $theme = basename(dirname($b['file']));
2000:     setThemeOption($key, $value, NULL, $theme, true);
2001: }
2002: 
2003: /**
2004:  * Returns the value of a theme option
2005:  *
2006:  * @param string $option option key
2007:  * @param object $album
2008:  * @param string $theme default theme name
2009:  * @return mixed
2010:  */
2011: function getThemeOption($option, $album = NULL, $theme = NULL) {
2012:     global $_set_theme_album, $_zp_gallery;
2013:     if (is_null($album)) {
2014:         $album = $_set_theme_album;
2015:     }
2016:     if (is_null($album)) {
2017:         $id = 0;
2018:     } else {
2019:         $id = $album->getID();
2020:         $theme = $album->getAlbumTheme();
2021:     }
2022:     if (empty($theme)) {
2023:         $theme = $_zp_gallery->getCurrentTheme();
2024:     }
2025: 
2026:     // album-theme
2027:     $sql = "SELECT `value` FROM " . prefix('options') . " WHERE `name`=" . db_quote($option) . " AND `ownerid`=" . $id . " AND `theme`=" . db_quote($theme);
2028:     $db = query_single_row($sql);
2029:     if (!$db) {
2030:         // raw theme option
2031:         $sql = "SELECT `value` FROM " . prefix('options') . " WHERE `name`=" . db_quote($option) . " AND `ownerid`=0 AND `theme`=" . db_quote($theme);
2032:         $db = query_single_row($sql);
2033:         if (!$db) {
2034:             // raw album option
2035:             $sql = "SELECT `value` FROM " . prefix('options') . " WHERE `name`=" . db_quote($option) . " AND `ownerid`=" . $id . " AND `theme`=NULL";
2036:             $db = query_single_row($sql);
2037:             if (!$db) {
2038:                 return getOption($option);
2039:             }
2040:         }
2041:     }
2042:     return $db['value'];
2043: }
2044: 
2045: /**
2046:  * Returns true if all the right conditions are set to allow comments for the $type
2047:  *
2048:  * @param string $type Which comments
2049:  * @return bool
2050:  */
2051: function commentsAllowed($type) {
2052:     return getOption($type) && (!MEMBERS_ONLY_COMMENTS || zp_loggedin(ADMIN_RIGHTS | POST_COMMENT_RIGHTS));
2053: }
2054: 
2055: /**
2056:  * Returns the viewer's IP address
2057:  * Deals with transparent proxies
2058:  *
2059:  * @return string
2060:  */
2061: function getUserIP() {
2062:     $pattern = '~^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])$~';
2063:     if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
2064:         $ip = sanitize($_SERVER['HTTP_X_FORWARDED_FOR']);
2065:         if (preg_match($pattern, $ip)) {
2066:             return $ip;
2067:         }
2068:     }
2069:     $ip = sanitize($_SERVER['REMOTE_ADDR']);
2070:     if (preg_match($pattern, $ip)) {
2071:         return $ip;
2072:     }
2073:     return NULL;
2074: }
2075: 
2076: /**
2077:  * Strips out and/or replaces characters from the string that are not "soe" friendly
2078:  *
2079:  * @param string $string
2080:  * @return string
2081:  */
2082: function seoFriendly($string) {
2083:     $string = trim(preg_replace('~\s+\.\s*~', '.', $string));
2084:     if (zp_has_filter('seoFriendly')) {
2085:         $string = zp_apply_filter('seoFriendly', $string);
2086:     } else { // no filter, do basic cleanup
2087:         $string = trim($string);
2088:         $string = preg_replace("/\s+/", "-", $string);
2089:         $string = preg_replace("/[^a-zA-Z0-9_.-]/", "-", $string);
2090:         $string = str_replace(array('---', '--'), '-', $string);
2091:     }
2092:     return $string;
2093: }
2094: 
2095: /**
2096:  *
2097:  * emit the javascript seojs() function
2098:  */
2099: function seoFriendlyJS() {
2100:     if (zp_has_filter('seoFriendly_js')) {
2101:         echo zp_apply_filter('seoFriendly_js');
2102:     } else {
2103:         ?>
2104:         function seoFriendlyJS(fname) {
2105:         fname=fname.trim();
2106:         fname=fname.replace(/\s+\.\s*/,'.');
2107:         fname = fname.replace(/\s+/g, '-');
2108:         fname = fname.replace(/[^a-zA-Z0-9_.-]/g, '-');
2109:         fname = fname.replace(/--*/g, '-');
2110:         return fname;
2111:         }
2112:         <?php
2113:     }
2114: }
2115: 
2116: /**
2117:  * Returns true if there is an internet connection
2118:  *
2119:  * @param string $host optional host name to test
2120:  *
2121:  * @return bool
2122:  */
2123: function is_connected($host = 'www.zenphoto.org') {
2124:     $err_no = $err_str = false;
2125:     $connected = @fsockopen($host, 80, $errno, $errstr, 0.5);
2126:     if ($connected) {
2127:         fclose($connected);
2128:         return true;
2129:     }
2130:     return false;
2131: }
2132: 
2133: /**
2134:  * produce debugging information on 404 errors
2135:  * @param string $album
2136:  * @param string $image
2137:  * @param string $theme
2138:  */
2139: function debug404($album, $image, $theme) {
2140:     if (DEBUG_404) {
2141:         $list = explode('/', $album);
2142:         if (array_shift($list) == 'cache') {
2143:             return;
2144:         }
2145:         $ignore = array('/favicon.ico', '/zp-data/tést.jpg');
2146:         $target = getRequestURI();
2147:         foreach ($ignore as $uri) {
2148:             if ($target == $uri)
2149:                 return;
2150:         }
2151:         $server = array();
2152:         foreach (array('REQUEST_URI', 'HTTP_REFERER', 'REMOTE_ADDR', 'REDIRECT_STATUS') as $key) {
2153:             $server[$key] = @$_SERVER[$key];
2154:         }
2155:         $request = $_REQUEST;
2156:         $request['theme'] = $theme;
2157:         if (!empty($image)) {
2158:             $request['image'] = $image;
2159:         }
2160: 
2161:         trigger_error(sprintf(gettext('Zenphoto processed a 404 error on %s. See the debug log for details.'), $target), E_USER_NOTICE);
2162:         ob_start();
2163:         var_dump($server);
2164:         $server = preg_replace('~array\s*\(.*\)\s*~', '', html_decode(getBare(ob_get_contents())));
2165:         ob_end_clean();
2166:         ob_start();
2167:         var_dump($request);
2168:         $request['theme'] = $theme;
2169:         if (!empty($image)) {
2170:             $request['image'] = $image;
2171:         }
2172:         $request = preg_replace('~array\s*\(.*\)\s*~', '', html_decode(getBare(ob_get_contents())));
2173:         ob_end_clean();
2174:         debugLog("404 error details\n" . $server . $request);
2175:     }
2176: }
2177: 
2178: /**
2179:  * returns an XSRF token
2180:  * @param striong $action
2181:  */
2182: function getXSRFToken($action) {
2183:     global $_zp_current_admin_obj;
2184:     return sha1($action . prefix(ZENPHOTO_RELEASE) . serialize($_zp_current_admin_obj) . session_id());
2185: }
2186: 
2187: /**
2188:  * Emits a "hidden" input for the XSRF token
2189:  * @param string $action
2190:  */
2191: function XSRFToken($action) {
2192:     ?>
2193:     <input type="hidden" name="XSRFToken" id="XSRFToken" value="<?php echo getXSRFToken($action); ?>" />
2194:     <?php
2195: }
2196: 
2197: /**
2198:  * Starts a sechedule script run
2199:  * @param string $script The script file to load
2200:  * @param array $params "POST" parameters
2201:  * @param bool $inline set to true to run the task "in-line". Set false run asynchronously
2202:  */
2203: function cron_starter($script, $params, $offsetPath, $inline = false) {
2204:     global $_zp_authority, $_zp_loggedin, $_zp_current_admin_obj, $_zp_HTML_cache;
2205:     $admin = $_zp_authority->getMasterUser();
2206: 
2207:     if ($inline) {
2208:         $_zp_current_admin_obj = $admin;
2209:         $_zp_loggedin = $_zp_current_admin_obj->getRights();
2210:         foreach ($params as $key => $value) {
2211:             if ($key == 'XSRFTag') {
2212:                 $key = 'XSRFToken';
2213:                 $value = getXSRFToken($value);
2214:             }
2215:             $_POST[$key] = $_GET[$key] = $_REQUEST[$key] = $value;
2216:         }
2217:         require_once($script);
2218:     } else {
2219:         $auth = sha1($script . serialize($admin));
2220:         $paramlist = 'link=' . $script;
2221:         foreach ($params as $key => $value) {
2222:             $paramlist .= '&' . $key . '=' . $value;
2223:         }
2224:         $paramlist .= '&auth=' . $auth . '&offsetPath=' . $offsetPath;
2225:         $_zp_HTML_cache->abortHTMLCache();
2226:         ?>
2227:         <script type="text/javascript">
2228:             // <!-- <![CDATA[
2229:             $.ajax({
2230:                 type: 'POST',
2231:                 cache: false,
2232:                 data: '<?php echo $paramlist; ?>',
2233:                 url: '<?php echo WEBPATH . '/' . ZENFOLDER; ?>/cron_runner.php'
2234:             });
2235:             // ]]> -->
2236:         </script>
2237:         <?php
2238:     }
2239: }
2240: 
2241: /**
2242:  *
2243:  * Check if logged in (with specific rights)
2244:  * Returns a true value if there is a user logged on with the required rights
2245:  *
2246:  * @param bit $rights rights required by the caller
2247:  *
2248:  * @return bool
2249:  */
2250: function zp_loggedin($rights = ALL_RIGHTS) {
2251:     global $_zp_loggedin;
2252:     return $_zp_loggedin & ($rights | ADMIN_RIGHTS);
2253: }
2254: 
2255: /**
2256:  * Provides an error protected read of image EXIF/IPTC data
2257:  *
2258:  * @param string $path image path
2259:  * @return array
2260:  *
2261:  */
2262: function read_exif_data_protected($path) {
2263:     if (DEBUG_EXIF) {
2264:         debugLog("Begin read_exif_data_protected($path)");
2265:         $start = microtime(true);
2266:     }
2267:     try {
2268:         $rslt = read_exif_data_raw($path, false);
2269:     } catch (Exception $e) {
2270:         debugLog("read_exif_data($path) exception: " . $e->getMessage());
2271:         $rslt = array();
2272:     }
2273:     if (DEBUG_EXIF) {
2274:         $time = microtime(true) - $start;
2275:         debugLog(sprintf("End read_exif_data_protected($path) [%f]", $time));
2276:     }
2277:     return $rslt;
2278: }
2279: 
2280: /**
2281:  *
2282:  * fetches the path to the flag image
2283:  * @param string $lang whose flag
2284:  * @return string
2285:  */
2286: function getLanguageFlag($lang) {
2287:     if (file_exists(SERVERPATH . '/' . USER_PLUGIN_FOLDER . '/locale/' . $lang . '/flag.png')) {
2288:         $flag = WEBPATH . '/' . USER_PLUGIN_FOLDER . '/locale/' . $lang . '/flag.png';
2289:     } else if (file_exists(SERVERPATH . '/' . ZENFOLDER . '/locale/' . $lang . '/flag.png')) {
2290:         $flag = WEBPATH . '/' . ZENFOLDER . '/locale/' . $lang . '/flag.png';
2291:     } else {
2292:         $flag = WEBPATH . '/' . ZENFOLDER . '/locale/missing_flag.png';
2293:     }
2294:     return $flag;
2295: }
2296: 
2297: /**
2298:  * Gets an item object by id
2299:  *
2300:  * @param string $table database table to search
2301:  * @param int $id id of the item to get
2302:  * @return mixed
2303:  */
2304: function getItemByID($table, $id) {
2305:     if ($result = query_single_row('SELECT * FROM ' . prefix($table) . ' WHERE id =' . (int) $id)) {
2306:         switch ($table) {
2307:             case 'images':
2308:                 if ($alb = getItemByID('albums', $result['albumid'])) {
2309:                     return newImage($alb, $result['filename'], true);
2310:                 }
2311:                 break;
2312:             case 'albums':
2313:                 return newAlbum($result['folder'], false, true);
2314:             case 'news':
2315:                 return new ZenpageNews($result['titlelink']);
2316:             case 'pages':
2317:                 return new ZenpagePage($result['titlelink']);
2318:             case 'news_categories':
2319:                 return new ZenpageCategory($result['titlelink']);
2320:         }
2321:     }
2322:     return NULL;
2323: }
2324: 
2325: /**
2326:  * uses down and up arrow links to show and hide sections of HTML
2327:  *
2328:  * @param string $content the id of the html section to be revealed
2329:  * @param bool $visible true if the content is initially visible
2330:  */
2331: function reveal($content, $visible = false) {
2332:     ?>
2333:     <span id="<?php echo $content; ?>_reveal"<?php if ($visible) echo 'style="display:none;"'; ?> class="icons">
2334:         <a href="javascript:reveal('<?php echo $content; ?>')" title="<?php echo gettext('Click to show content'); ?>">
2335:             <img src="../../images/arrow_down.png" alt="" class="icon-position-top4" />
2336:         </a>
2337:     </span>
2338:     <span id="<?php echo $content; ?>_hide"<?php if (!$visible) echo 'style="display:none;"'; ?> class="icons">
2339:         <a href="javascript:reveal('<?php echo $content; ?>')" title="<?php echo gettext('Click to hide content'); ?>">
2340:             <img src="../../images/arrow_up.png" alt="" class="icon-position-top4" />
2341:         </a>
2342:     </span>
2343:     <?php
2344: }
2345: 
2346: /**
2347:  * Deals with the [macro parameters] substitutions
2348:  *
2349:  * See the macroList plugin for details
2350:  *
2351:  * @param string $text
2352:  * @return string
2353:  */
2354: function applyMacros($text) {
2355:     $content_macros = getMacros();
2356:     preg_match_all('/\[(\w+)(.*?)\]/i', $text, $instances);
2357:     foreach ($instances[0] as $instance => $macro_instance) {
2358:         $macroname = strtoupper($instances[1][$instance]);
2359:         if (array_key_exists($macroname, $content_macros)) {
2360:             $macro = $content_macros[$macroname];
2361:             $p = $instances[2][$instance];
2362:             $data = NULL;
2363:             $class = $macro['class'];
2364:             if ($p) {
2365:                 $p = trim(utf8::sanitize(str_replace("\xC2\xA0", ' ', strip_tags($p)))); // remove hard spaces and invalid characters
2366:                 $p = preg_replace("~\s+=\s+(?=(?:[^\"]*+\"[^\"]*+\")*+[^\"]*+$)~", "=", $p); // deblank assignment operator
2367:                 preg_match_all("~'[^'\"]++'|\"[^\"]++\"|[^\s]++~", $p, $l); //  parse the parameter list
2368:                 $parms = array();
2369:                 $k = 0;
2370:                 foreach ($l[0] as $s) {
2371:                     if ($s != ',') {
2372:                         $parms[$k++] = trim($s, '\'"'); //  remove any quote marks
2373:                     }
2374:                 }
2375:             } else {
2376:                 $parms = array();
2377:             }
2378:             $parameters = array();
2379:             if (!empty($macro['params'])) {
2380:                 $err = false;
2381:                 foreach ($macro['params'] as $key => $type) {
2382:                     $data = false;
2383:                     if (array_key_exists($key, $parms)) {
2384:                         switch (trim($type, '*')) {
2385:                             case 'int':
2386:                                 if (is_numeric($parms[$key])) {
2387:                                     $parameters[] = (int) $parms[$key];
2388:                                 } else {
2389:                                     $data = '<span class="error">' . sprintf(gettext('<em>[%1$s]</em> parameter %2$d should be a number.'), trim($macro_instance, '[]'), $key + 1) . '</span>';
2390:                                     $class = 'error';
2391:                                 }
2392:                                 break;
2393:                             case 'string':
2394:                                 if (is_string($parms[$key])) {
2395:                                     $parameters[] = $parms[$key];
2396:                                 } else {
2397:                                     $data = '<span class="error">' . sprintf(gettext('<em>[%1$s]</em> parameter %2$d should be a string.'), trim($macro_instance, '[]'), $key + 1) . '</span>';
2398:                                     $class = 'error';
2399:                                 }
2400:                                 break;
2401:                             case 'bool':
2402:                                 switch (strtolower($parms[$key])) {
2403:                                     case ("true"):
2404:                                         $parameters[] = true;
2405:                                         break;
2406:                                     case ("false"):
2407:                                         $parameters[] = false;
2408:                                         break;
2409:                                     default:
2410:                                         $data = '<span class="error">' . sprintf(gettext('<em>[%1$s]</em> parameter %2$d should be <code>true</code> or <code>false</code>.'), trim($macro_instance, '[]'), $key + 1) . '</span>';
2411:                                         $class = 'error';
2412:                                         break;
2413:                                 }
2414:                                 break;
2415:                             case 'array':
2416:                                 $l = array_slice($parms, $key);
2417:                                 $parms = array();
2418:                                 foreach ($l as $key => $p) {
2419:                                     $x = explode('=', $p);
2420:                                     if (count($x) == 2) {
2421:                                         $parms[$x[0]] = $x[1];
2422:                                     } else {
2423:                                         $parms[$key] = $x[0];
2424:                                     }
2425:                                 }
2426:                                 $parameters[] = $parms;
2427:                                 break;
2428:                             default:
2429:                                 $data = '<span class="error">' . sprintf(gettext('<em>[%1$s]</em> parameter %2$d is incorrectly defined.'), trim($macro_instance, '[]'), $key + 1) . '</span>';
2430:                                 $class = 'error';
2431:                                 break;
2432:                         }
2433:                     } else {
2434:                         if (strpos($type, '*') === false) {
2435:                             $data = '<span class="error">' . sprintf(gettext('<em>[%1$s]</em> parameter %2$d is missing.'), trim($macro_instance, '[]'), $key + 1) . '</span>';
2436:                             $class = 'error';
2437:                         }
2438:                         break;
2439:                     }
2440:                 }
2441:             } else {
2442:                 if (!empty($p)) {
2443:                     $class = 'error';
2444:                     $data = '<span class="error">' . sprintf(gettext('<em>[%1$s]</em> macro does not take parameters'), trim($macro_instance, '[]')) . '</span>';
2445:                 }
2446:             }
2447:             switch ($class) {
2448:                 case 'error':
2449:                     break;
2450:                 case 'function';
2451:                 case 'procedure':
2452:                     if (is_callable($macro['value'])) {
2453:                         if ($class == 'function') {
2454:                             ob_start();
2455:                             $data = call_user_func_array($macro['value'], $parameters);
2456:                             if (empty($data)) {
2457:                                 $data = ob_get_contents();
2458:                             }
2459:                             ob_end_clean();
2460:                         } else {
2461:                             ob_start();
2462:                             call_user_func_array($macro['value'], $parameters);
2463:                             $data = ob_get_contents();
2464:                             ob_end_clean();
2465:                         }
2466:                         if (empty($data)) {
2467:                             $data = '<span class="error">' . sprintf(gettext('<em>[%1$s]</em> retuned no data'), trim($macro_instance, '[]')) . '</span>';
2468:                         } else {
2469:                             $data = "\n<!--Begin " . $macroname . "-->\n" . $data . "\n<!--End " . $macroname . "-->\n";
2470:                         }
2471:                     } else {
2472:                         $data = '<span class="error">' . sprintf(gettext('<em>[%1$s]</em> <code>%2$s</code> is not callable'), trim($macro_instance, '[]'), $macro['value']) . '</span>';
2473:                     }
2474:                     break;
2475:                 case 'constant':
2476:                     $data = "\n<!--Begin " . $macroname . "-->\n" . $macro['value'] . "\n<!--End " . $macroname . "-->\n";
2477:                     break;
2478:                 case 'expression':
2479:                     $expression = '$data = ' . $macro['value'];
2480:                     $parms = array_reverse($parms, true);
2481:                     preg_match_all('/\$\d+/', $macro['value'], $replacements);
2482:                     foreach ($replacements as $rkey => $v) {
2483:                         if (empty($v))
2484:                             unset($replacements[$rkey]);
2485:                     }
2486:                     if (count($parms) == count($replacements)) {
2487: 
2488:                         foreach ($parms as $key => $value) {
2489:                             $key++;
2490:                             $expression = preg_replace('/\$' . $key . '/', db_quote($value), $expression);
2491:                         }
2492:                         eval($expression);
2493:                         if (!isset($data) || is_null($data)) {
2494:                             $data = '<span class="error">' . sprintf(gettext('<em>[%1$s]</em> retuned no data'), trim($macro_instance, '[]')) . '</span>';
2495:                         } else {
2496:                             $data = "\n<!--Begin " . $macroname . "-->\n" . $data . "\n<!--End " . $macroname . "-->\n";
2497:                         }
2498:                     } else {
2499:                         $data = '<span class="error">' . sprintf(ngettext('<em>[%1$s]</em> takes %2$d parameter', '<em>[%1$s]</em> takes %2$d parameters', count($replacements)), trim($macro_instance, '[]'), count($replacements)) . '</span>';
2500:                     }
2501:                     break;
2502:             }
2503:             $text = str_replace($macro_instance, $data, $text);
2504:         }
2505:     }
2506:     return $text;
2507: }
2508: 
2509: function getMacros() {
2510:     global $_zp_content_macros;
2511:     if (is_null($_zp_content_macros)) {
2512:         $_zp_content_macros = zp_apply_filter('content_macro', array());
2513:     }
2514:     return $_zp_content_macros;
2515: }
2516: 
2517: /**
2518:  * generates a nested list of albums for the album tab sorting
2519:  * Returns an array of "albums" each element contains:
2520:  *                              'name' which is the folder name
2521:  *                              'sort_order' which is an array of the sort order set
2522:  *
2523:  * @param $subalbum root level album (NULL is the gallery)
2524:  * @param $levels how far to nest
2525:  * @param $checkalbumrights TRUE (Default) for album rights for backend usage, FALSE to skip for frontend usage
2526:  * @param $level internal for keeping the sort order elements
2527:  * @return array
2528:  */
2529: function getNestedAlbumList($subalbum, $levels, $checkalbumrights = true, $level = array()) {
2530:     global $_zp_gallery;
2531:     $cur = count($level);
2532:     $levels--; // make it 0 relative to sync with $cur
2533:     if (is_null($subalbum)) {
2534:         $albums = $_zp_gallery->getAlbums();
2535:     } else {
2536:         $albums = $subalbum->getAlbums();
2537:     }
2538:     $list = array();
2539:     foreach ($albums as $analbum) {
2540:         $albumobj = newAlbum($analbum);
2541:   $accessallowed = true;
2542:   if($checkalbumrights) {
2543:     $accessallowed = $albumobj->isMyItem(ALBUM_RIGHTS);
2544:   }
2545:         if (!is_null($subalbum) || $accessallowed) {
2546:             $level[$cur] = sprintf('%03u', $albumobj->getSortOrder());
2547:             $list[] = array('name' => $analbum, 'sort_order' => $level);
2548:             if ($cur < $levels && ($albumobj->getNumAlbums()) && !$albumobj->isDynamic()) {
2549:                 $list = array_merge($list, getNestedAlbumList($albumobj, $levels + 1, $checkalbumrights, $level));
2550:             }
2551:         }
2552:     }
2553:     return $list;
2554: }
2555: 
2556: class zpFunctions {
2557: 
2558:     /**
2559:      *
2560:      * creates an SEO language prefix list
2561:      */
2562:     static function LanguageSubdomains() {
2563:         $domains = array();
2564:         $langs = generateLanguageList();
2565:         $domains = array();
2566:         foreach ($langs as $value) {
2567:             $domains[substr($value, 0, 2)][] = $value;
2568:         }
2569:         $langs = array();
2570:         foreach ($domains as $simple => $full) {
2571:             if (count($full) > 1) {
2572:                 foreach ($full as $loc) {
2573:                     $langs[$loc] = $loc;
2574:                 }
2575:             } else {
2576:                 $langs[$full[0]] = $simple;
2577:             }
2578:         }
2579:         if (isset($langs[SITE_LOCALE])) {
2580:             $langs[SITE_LOCALE] = '';
2581:         }
2582:         return $langs;
2583:     }
2584: 
2585:     /**
2586:      * Returns a canonical language name string for the location
2587:      *
2588:      * @param string $loc the location. If NULL use the current cookie
2589:      * @param string separator will be used between the major and qualifier parts, e.g. en_US
2590:      *
2591:      * @return string
2592:      */
2593:     static function getLanguageText($loc = NULL, $separator = NULL) {
2594:         global $_locale_Subdomains;
2595:         if (is_null($loc)) {
2596:             $text = @$_locale_Subdomains[zp_getCookie('dynamic_locale')];
2597:         } else {
2598:             $text = @$_locale_Subdomains[$loc];
2599:             //en_US always is always empty here so so urls in dynamic locale or html_meta_tags are wrong (Quickfix)
2600:             if(empty($text)) {
2601:                 $text = $loc;
2602:             }
2603:         }
2604:         if (!is_null($separator)) {
2605:             $text = str_replace('_', $separator, $text);
2606:         }
2607:         return $text;
2608:     }
2609: 
2610:     /**
2611:      * initializes the $_zp_exifvars array display state
2612:      *
2613:      */
2614:     static function setexifvars() {
2615:         global $_zp_exifvars;
2616:         /*
2617:          * Note: If fields are added or deleted, setup should be run or the new data won't be stored
2618:          * (but existing fields will still work; nothing breaks).
2619:          *
2620:          * This array should be ordered by logical associations as it will be the order that EXIF information
2621:          * is displayed
2622:          */
2623:         $_zp_exifvars = array(
2624:                         // Database Field                => array('source', 'Metadata Key', 'ZP Display Text', Display? size,   enabled, type)
2625:                         'EXIFMake'                                   => array('IFD0', 'Make', gettext('Camera Maker'), true, 52, true, 'string'),
2626:                         'EXIFModel'                                  => array('IFD0', 'Model', gettext('Camera Model'), true, 52, true, 'string'),
2627:                         'EXIFDescription'                        => array('IFD0', 'ImageDescription', gettext('Image Title'), false, 52, true, 'string'),
2628:                         'IPTCObjectName'                         => array('IPTC', 'ObjectName', gettext('Object Name'), false, 256, true, 'string'),
2629:                         'IPTCImageHeadline'                  => array('IPTC', 'ImageHeadline', gettext('Image Headline'), false, 256, true, 'string'),
2630:                         'IPTCImageCaption'                   => array('IPTC', 'ImageCaption', gettext('Image Caption'), false, 2000, true, 'string'),
2631:                         'IPTCImageCaptionWriter'         => array('IPTC', 'ImageCaptionWriter', gettext('Image Caption Writer'), false, 32, true, 'string'),
2632:                         'EXIFDateTime'                           => array('SubIFD', 'DateTime', gettext('Time Taken'), true, 52, true, 'time'),
2633:                         'EXIFDateTimeOriginal'           => array('SubIFD', 'DateTimeOriginal', gettext('Original Time Taken'), true, 52, true, 'time'),
2634:                         'EXIFDateTimeDigitized'          => array('SubIFD', 'DateTimeDigitized', gettext('Time Digitized'), true, 52, true, 'time'),
2635:                         'IPTCDateCreated'                        => array('IPTC', 'DateCreated', gettext('Date Created'), false, 8, true, 'time'),
2636:                         'IPTCTimeCreated'                        => array('IPTC', 'TimeCreated', gettext('Time Created'), false, 11, true, 'time'),
2637:                         'IPTCDigitizeDate'                   => array('IPTC', 'DigitizeDate', gettext('Digital Creation Date'), false, 8, true, 'time'),
2638:                         'IPTCDigitizeTime'                   => array('IPTC', 'DigitizeTime', gettext('Digital Creation Time'), false, 11, true, 'time'),
2639:                         'EXIFArtist'                                 => array('IFD0', 'Artist', gettext('Artist'), false, 52, true, 'string'),
2640:                         'IPTCImageCredit'                        => array('IPTC', 'ImageCredit', gettext('Image Credit'), false, 32, true, 'string'),
2641:                         'IPTCByLine'                                 => array('IPTC', 'ByLine', gettext('Byline'), false, 32, true, 'string'),
2642:                         'IPTCByLineTitle'                        => array('IPTC', 'ByLineTitle', gettext('Byline Title'), false, 32, true, 'string'),
2643:                         'IPTCSource'                                 => array('IPTC', 'Source', gettext('Image Source'), false, 32, true, 'string'),
2644:                         'IPTCContact'                                => array('IPTC', 'Contact', gettext('Contact'), false, 128, true, 'string'),
2645:                         'EXIFCopyright'                          => array('IFD0', 'Copyright', gettext('Copyright Holder'), false, 128, true, 'string'),
2646:                         'IPTCCopyright'                          => array('IPTC', 'Copyright', gettext('Copyright Notice'), false, 128, true, 'string'),
2647:                         'IPTCKeywords'                           => array('IPTC', 'Keywords', gettext('Keywords'), false, 0, true, 'string'),
2648:                         'EXIFExposureTime'                   => array('SubIFD', 'ExposureTime', gettext('Shutter Speed'), true, 52, true, 'string'),
2649:                         'EXIFFNumber'                                => array('SubIFD', 'FNumber', gettext('Aperture'), true, 52, true, 'number'),
2650:                         'EXIFISOSpeedRatings'                => array('SubIFD', 'ISOSpeedRatings', gettext('ISO Sensitivity'), true, 52, true, 'number'),
2651:                         'EXIFExposureBiasValue'          => array('SubIFD', 'ExposureBiasValue', gettext('Exposure Compensation'), true, 52, true, 'string'),
2652:                         'EXIFMeteringMode'                   => array('SubIFD', 'MeteringMode', gettext('Metering Mode'), true, 52, true, 'string'),
2653:                         'EXIFFlash'                                  => array('SubIFD', 'Flash', gettext('Flash Fired'), true, 52, true, 'string'),
2654:                         'EXIFImageWidth'                         => array('SubIFD', 'ExifImageWidth', gettext('Original Width'), false, 52, true, 'number'),
2655:                         'EXIFImageHeight'                        => array('SubIFD', 'ExifImageHeight', gettext('Original Height'), false, 52, true, 'number'),
2656:                         'EXIFOrientation'                        => array('IFD0', 'Orientation', gettext('Orientation'), false, 52, true, 'string'),
2657:                         'EXIFSoftware'                           => array('IFD0', 'Software', gettext('Software'), false, 999, true, 'string'),
2658:                         'EXIFContrast'                           => array('SubIFD', 'Contrast', gettext('Contrast Setting'), false, 52, true, 'string'),
2659:                         'EXIFSharpness'                          => array('SubIFD', 'Sharpness', gettext('Sharpness Setting'), false, 52, true, 'string'),
2660:                         'EXIFSaturation'                         => array('SubIFD', 'Saturation', gettext('Saturation Setting'), false, 52, true, 'string'),
2661:                         'EXIFWhiteBalance'                   => array('SubIFD', 'WhiteBalance', gettext('White Balance'), false, 52, true, 'string'),
2662:                         'EXIFSubjectDistance'                => array('SubIFD', 'SubjectDistance', gettext('Subject Distance'), false, 52, true, 'number'),
2663:                         'EXIFFocalLength'                        => array('SubIFD', 'FocalLength', gettext('Focal Length'), true, 52, true, 'number'),
2664:                         'EXIFLensType'                           => array('SubIFD', 'LensType', gettext('Lens Type'), false, 52, true, 'string'),
2665:                         'EXIFLensInfo'                           => array('SubIFD', 'LensInfo', gettext('Lens Info'), false, 52, true, 'string'),
2666:                         'EXIFFocalLengthIn35mmFilm'  => array('SubIFD', 'FocalLengthIn35mmFilm', gettext('35mm Focal Length Equivalent'), false, 52, true, 'string'),
2667:                         'IPTCCity'                                   => array('IPTC', 'City', gettext('City'), false, 32, true, 'string'),
2668:                         'IPTCSubLocation'                        => array('IPTC', 'SubLocation', gettext('Sub-location'), false, 32, true, 'string'),
2669:                         'IPTCState'                                  => array('IPTC', 'State', gettext('Province/State'), false, 32, true, 'string'),
2670:                         'IPTCLocationCode'                   => array('IPTC', 'LocationCode', gettext('Country/Primary Location Code'), false, 3, true, 'string'),
2671:                         'IPTCLocationName'                   => array('IPTC', 'LocationName', gettext('Country/Primary Location Name'), false, 64, true, 'string'),
2672:                         'IPTCContentLocationCode'        => array('IPTC', 'ContentLocationCode', gettext('Content Location Code'), false, 3, true, 'string'),
2673:                         'IPTCContentLocationName'        => array('IPTC', 'ContentLocationName', gettext('Content Location Name'), false, 64, true, 'string'),
2674:                         'EXIFGPSLatitude'                        => array('GPS', 'Latitude', gettext('Latitude'), false, 52, true, 'number'),
2675:                         'EXIFGPSLatitudeRef'                 => array('GPS', 'Latitude Reference', gettext('Latitude Reference'), false, 52, true, 'string'),
2676:                         'EXIFGPSLongitude'                   => array('GPS', 'Longitude', gettext('Longitude'), false, 52, true, 'number'),
2677:                         'EXIFGPSLongitudeRef'                => array('GPS', 'Longitude Reference', gettext('Longitude Reference'), false, 52, true, 'string'),
2678:                         'EXIFGPSAltitude'                        => array('GPS', 'Altitude', gettext('Altitude'), false, 52, true, 'number'),
2679:                         'EXIFGPSAltitudeRef'                 => array('GPS', 'Altitude Reference', gettext('Altitude Reference'), false, 52, true, 'string'),
2680:                         'IPTCOriginatingProgram'         => array('IPTC', 'OriginatingProgram', gettext('Originating Program '), false, 32, true, 'string'),
2681:                         'IPTCProgramVersion'                 => array('IPTC', 'ProgramVersion', gettext('Program Version'), false, 10, true, 'string'),
2682:                         'VideoFormat'                                => array('VIDEO', 'fileformat', gettext('Video File Format'), false, 32, true, 'string'),
2683:                         'VideoSize'                                  => array('VIDEO', 'filesize', gettext('Video File Size'), false, 32, true, 'number'),
2684:                         'VideoArtist'                                => array('VIDEO', 'artist', gettext('Video Artist'), false, 256, true, 'string'),
2685:                         'VideoTitle'                                 => array('VIDEO', 'title', gettext('Video Title'), false, 256, true, 'string'),
2686:                         'VideoBitrate'                           => array('VIDEO', 'bitrate', gettext('Bitrate'), false, 32, true, 'number'),
2687:                         'VideoBitrate_mode'                  => array('VIDEO', 'bitrate_mode', gettext('Bitrate_Mode'), false, 32, true, 'string'),
2688:                         'VideoBits_per_sample'           => array('VIDEO', 'bits_per_sample', gettext('Bits per sample'), false, 32, true, 'number'),
2689:                         'VideoCodec'                                 => array('VIDEO', 'codec', gettext('Codec'), false, 32, true, 'string'),
2690:                         'VideoCompression_ratio'         => array('VIDEO', 'compression_ratio', gettext('Compression Ratio'), false, 32, true, 'number'),
2691:                         'VideoDataformat'                        => array('VIDEO', 'dataformat', gettext('Video Dataformat'), false, 32, true, 'string'),
2692:                         'VideoEncoder'                           => array('VIDEO', 'encoder', gettext('File Encoder'), false, 10, true, 'string'),
2693:                         'VideoSamplerate'                        => array('VIDEO', 'Samplerate', gettext('Sample rate'), false, 32, true, 'number'),
2694:                         'VideoChannelmode'                   => array('VIDEO', 'channelmode', gettext('Channel mode'), false, 32, true, 'string'),
2695:                         'VideoFormat'                                => array('VIDEO', 'format', gettext('Format'), false, 10, true, 'string'),
2696:                         'VideoChannels'                          => array('VIDEO', 'channels', gettext('Channels'), false, 10, true, 'number'),
2697:                         'VideoFramerate'                         => array('VIDEO', 'framerate', gettext('Frame rate'), false, 32, true, 'number'),
2698:                         'VideoResolution_x'                  => array('VIDEO', 'resolution_x', gettext('X Resolution'), false, 32, true, 'number'),
2699:                         'VideoResolution_y'                  => array('VIDEO', 'resolution_y', gettext('Y Resolution'), false, 32, true, 'number'),
2700:                         'VideoAspect_ratio'                  => array('VIDEO', 'pixel_aspect_ratio', gettext('Aspect ratio'), false, 32, true, 'number'),
2701:                         'VideoPlaytime'                          => array('VIDEO', 'playtime_string', gettext('Play Time'), false, 10, true, 'number'),
2702:                         'XMPrating'                                  => array('XMP', 'rating', gettext('XMP Rating'), false, 10, true, 'string'),
2703:         );
2704:         foreach ($_zp_exifvars as $key => $item) {
2705:             if (!is_null($disable = getOption($key . '-disabled'))) {
2706:                 $_zp_exifvars[$key][5] = !$disable;
2707:             }
2708:             $_zp_exifvars[$key][3] = getOption($key);
2709:         }
2710:     }
2711: 
2712:     /**
2713:      *
2714:      * Returns true if the install is not a "clone"
2715:      */
2716:     static function hasPrimaryScripts() {
2717:         if (!defined('PRIMARY_INSTALLATION')) {
2718:             if (function_exists('readlink') && ($zen = str_replace('\\', '/', @readlink(SERVERPATH . '/' . ZENFOLDER)))) {
2719:                 // no error reading the link info
2720:                 $os = strtoupper(PHP_OS);
2721:                 $sp = SERVERPATH;
2722:                 if (substr($os, 0, 3) == 'WIN' || $os == 'DARWIN') { // canse insensitive file systems
2723:                     $sp = strtolower($sp);
2724:                     $zen = strtolower($zen);
2725:                 }
2726:                 define('PRIMARY_INSTALLATION', $sp == dirname($zen));
2727:             } else {
2728:                 define('PRIMARY_INSTALLATION', true);
2729:             }
2730:         }
2731:         return PRIMARY_INSTALLATION;
2732:     }
2733: 
2734:     /**
2735:      *
2736:      * Recursively clears and removes a folder
2737:      * @param string $path
2738:      * @return boolean
2739:      */
2740:     static function removeDir($path, $within = false) {
2741:         if (($dir = @opendir($path)) !== false) {
2742:             while (($file = readdir($dir)) !== false) {
2743:                 if ($file != '.' && $file != '..') {
2744:                     if ((is_dir($path . '/' . $file))) {
2745:                         if (!zpFunctions::removeDir($path . '/' . $file)) {
2746:                             return false;
2747:                         }
2748:                     } else {
2749:                         @chmod($path . $file, 0777);
2750:                         if (!@unlink($path . '/' . $file)) {
2751:                             return false;
2752:                         }
2753:                     }
2754:                 }
2755:             }
2756:             closedir($dir);
2757:             if (!$within) {
2758:                 @chmod($path, 0777);
2759:                 if (!@rmdir($path)) {
2760:                     return false;
2761:                 }
2762:             }
2763:             return true;
2764:         }
2765:         return false;
2766:     }
2767: 
2768:     /**
2769:      * inserts location independent WEB path tags in place of site path tags
2770:      * @param string $text
2771:      */
2772:     static function tagURLs($text) {
2773:         if (is_string($text) && preg_match('/^a:[0-9]+:{/', $text)) { //    serialized array
2774:             $text = getSerializedArray($text);
2775:             $serial = true;
2776:         } else {
2777:             $serial = false;
2778:         }
2779:         if (is_array($text)) {
2780:             foreach ($text as $key => $textelement) {
2781:                 $text[$key] = self::TagURLs($textelement);
2782:             }
2783:             if ($serial) {
2784:                 $text = serialize($text);
2785:             }
2786:         } else {
2787:             $text = str_replace(WEBPATH, '{*WEBPATH*}', str_replace(FULLWEBPATH, '{*FULLWEBPATH*}', $text));
2788:         }
2789:         return $text;
2790:     }
2791: 
2792:     /**
2793:      * reverses tagURLs()
2794:      * @param string $text
2795:      * @return string
2796:      */
2797:     static function unTagURLs($text) {
2798:         if (is_string($text) && preg_match('/^a:[0-9]+:{/', $text)) { //    serialized array
2799:             $text = getSerializedArray($text);
2800:             $serial = true;
2801:         } else {
2802:             $serial = false;
2803:         }
2804:         if (is_array($text)) {
2805:             foreach ($text as $key => $textelement) {
2806:                 $text[$key] = self::unTagURLs($textelement);
2807:             }
2808:             if ($serial) {
2809:                 $text = serialize($text);
2810:             }
2811:         } else {
2812:             $text = str_replace('{*WEBPATH*}', WEBPATH, str_replace('{*FULLWEBPATH*}', FULLWEBPATH, $text));
2813:         }
2814:         return $text;
2815:     }
2816: 
2817:     /**
2818:      * Searches out i.php image links and replaces them with cache links if image is cached
2819:      * @param string $text
2820:      * @return string
2821:      */
2822:     static function updateImageProcessorLink($text) {
2823:         if (is_string($text) && preg_match('/^a:[0-9]+:{/', $text)) { //    serialized array
2824:             $text = getSerializedArray($text);
2825:             $serial = true;
2826:         } else {
2827:             $serial = false;
2828:         }
2829:         if (is_array($text)) {
2830:             foreach ($text as $key => $textelement) {
2831:                 $text[$key] = self::updateImageProcessorLink($textelement);
2832:             }
2833:             if ($serial) {
2834:                 $text = serialize($text);
2835:             }
2836:         } else {
2837:             preg_match_all('|<\s*img.*?\ssrc\s*=\s*"([^"]*)?|', $text, $matches);
2838:             foreach ($matches[1] as $key => $match) {
2839:                 preg_match('|.*i\.php\?(.*)|', $match, $imgproc);
2840:                 if ($imgproc) {
2841:                     $match = preg_split('~\&[amp;]*~', $imgproc[1]);
2842:                     $set = array();
2843:                     foreach ($match as $v) {
2844:                         $s = explode('=', $v);
2845:                         $set[$s[0]] = $s[1];
2846:                     }
2847:                     $args = getImageArgs($set);
2848:                     $imageuri = getImageURI($args, urldecode($set['a']), urldecode($set['i']), NULL);
2849:                     if (strpos($imageuri, 'i.php') === false) {
2850:                         $text = str_replace($matches[1][$key], $imageuri, $text);
2851:                     }
2852:                 }
2853:             }
2854:         }
2855:         return $text;
2856:     }
2857: 
2858:     static function pluginDebug($extension, $priority, $start) {
2859:         list($usec, $sec) = explode(" ", microtime());
2860:         $end = (float) $usec + (float) $sec;
2861:         $class = array();
2862:         if ($priority & CLASS_PLUGIN) {
2863:             $class[] = 'CLASS';
2864:         }
2865:         if ($priority & ADMIN_PLUGIN) {
2866:             $class[] = 'ADMIN';
2867:         }
2868:         if ($priority & FEATURE_PLUGIN) {
2869:             $class[] = 'FEATURE';
2870:         }
2871:         if ($priority & THEME_PLUGIN) {
2872:             $class[] = 'THEME';
2873:         }
2874:         if (empty($class))
2875:             $class[] = 'theme';
2876:         debugLog(sprintf('    ' . $extension . '(%s:%u)=>%.4fs', implode('|', $class), $priority & PLUGIN_PRIORITY, $end - $start));
2877:     }
2878:     
2879:     /**
2880:      * Removes a trailing slash from a string if one exists, otherwise just returns the string
2881:      * Used primarily within date and tag searches and news date archive results
2882:      * 
2883:      * @param string $string
2884:      * @return string
2885:      * @since 1.4.12
2886:      */
2887:     static function removeTrailingSlash($string) {
2888:         if (substr($string, -1) == '/') {
2889:             $length = strlen($string) - 1;
2890:             return substr($string, 0, $length);
2891:         }
2892:         return $string;
2893:     }
2894:     
2895:     /**
2896:      * Wrapper for the native PHP tidy() to balance out invalid html if existing on the server
2897:      * Covers newer HTML5 elements
2898:      * 
2899:      * @param string $html The html to tidy, typical from a description or content field of items
2900:      * @param string $shortenindicator If you are using this on truncated text
2901:      * @return string
2902:      * @since 1.4.12
2903:      */
2904:     static function tidyHTML($html) {
2905:         if (class_exists('tidy')) {
2906:             $options = array(
2907:                     'new-blocklevel-tags' => 'article aside audio bdi canvas details dialog figcaption figure footer header main nav section source summary template track video',
2908:                     'new-empty-tags' => 'command embed keygen source track wbr',
2909:                     'new-inline-tags' => 'audio command datalist embed keygen mark menuitem meter output progress source time video wbr',
2910:                     'show-body-only' => true
2911:             );
2912:             $tidy = new tidy();
2913:             $tidy->parseString($html, $options, 'utf8');
2914:             $tidy->cleanRepair();
2915:             return trim($tidy);
2916:         }
2917:         return $html;
2918:     }
2919: 
2920: }
2921: 
2922: /**
2923:  * Standins for when no captcha is enabled
2924:  */
2925: class _zp_captcha {
2926: 
2927:     var $name = NULL; // "captcha" name if no captcha plugin loaded
2928: 
2929:     function getCaptcha($prompt) {
2930:         return array('input' => NULL, 'html' => '<p class="errorbox">' . gettext('No captcha handler is enabled.') . '</p>', 'hidden' => '');
2931:     }
2932: 
2933:     function checkCaptcha($s1, $s2) {
2934:         return false;
2935:     }
2936: 
2937: }
2938: 
2939: /**
2940:  * stand-in for when there is no HTML cache plugin enabled
2941:  */
2942: class _zp_HTML_cache {
2943: 
2944:     function disable() {
2945: 
2946:     }
2947: 
2948:     function startHTMLCache() {
2949: 
2950:     }
2951: 
2952:     function abortHTMLCache() {
2953: 
2954:     }
2955: 
2956:     function endHTMLCache() {
2957: 
2958:     }
2959: 
2960:     function clearHtmlCache() {
2961: 
2962:     }
2963: 
2964: }
2965: 
2966: zpFunctions::setexifvars();
2967: $_locale_Subdomains = zpFunctions::LanguageSubdomains();
2968: ?>
2969: 
Zenphoto doc API documentation generated by ApiGen