JOOMLA中国
  • Joomla中国首页
  • 社区
  • 教程
  • 应用市场
  • B计划
Joomla! Framework TM
  • Namespace
  • Class
  • Tree
  • Deprecated

Namespaces

  • Composer
    • Autoload
  • Joomla
    • Application
      • Cli
        • Output
          • Processor
      • Web
    • Data
    • DI
      • Exception
    • Event
    • Filter
    • Input
    • Ldap
    • Registry
      • Format
    • Session
      • Storage
    • String
    • Uri
    • Utilities
  • None
  • PasswordCompat
    • binary
  • PHP
  • Psr
    • Log
  • Symfony
    • Component
      • Yaml
        • Exception
    • Polyfill
      • Util

Classes

  • CallbackFilterIterator
  • ComposerAutoloaderInit205c915b9c7d3e718e7c95793ee67ffe
  • easyparse
  • EasyPeasyICS
  • FOFAutoloaderComponent
  • FOFAutoloaderFof
  • FOFConfigDomainDispatcher
  • FOFConfigDomainTables
  • FOFConfigDomainViews
  • FOFConfigProvider
  • FOFController
  • FOFDatabase
  • FOFDatabaseDriver
  • FOFDatabaseDriverJoomla
  • FOFDatabaseDriverMysql
  • FOFDatabaseDriverMysqli
  • FOFDatabaseDriverOracle
  • FOFDatabaseDriverPdo
  • FOFDatabaseDriverPdomysql
  • FOFDatabaseDriverPostgresql
  • FOFDatabaseDriverSqlazure
  • FOFDatabaseDriverSqlite
  • FOFDatabaseDriverSqlsrv
  • FOFDatabaseFactory
  • FOFDatabaseInstaller
  • FOFDatabaseIterator
  • FOFDatabaseIteratorAzure
  • FOFDatabaseIteratorMysql
  • FOFDatabaseIteratorMysqli
  • FOFDatabaseIteratorOracle
  • FOFDatabaseIteratorPdo
  • FOFDatabaseIteratorPdomysql
  • FOFDatabaseIteratorPostgresql
  • FOFDatabaseIteratorSqlite
  • FOFDatabaseIteratorSqlsrv
  • FOFDatabaseQuery
  • FOFDatabaseQueryElement
  • FOFDatabaseQueryMysql
  • FOFDatabaseQueryMysqli
  • FOFDatabaseQueryOracle
  • FOFDatabaseQueryPdo
  • FOFDatabaseQueryPdomysql
  • FOFDatabaseQueryPostgresql
  • FOFDatabaseQuerySqlazure
  • FOFDatabaseQuerySqlite
  • FOFDatabaseQuerySqlsrv
  • FOFDispatcher
  • FOFDownload
  • FOFDownloadAdapterAbstract
  • FOFDownloadAdapterCurl
  • FOFDownloadAdapterFopen
  • FOFEncryptAes
  • FOFEncryptAesAbstract
  • FOFEncryptAesMcrypt
  • FOFEncryptAesOpenssl
  • FOFEncryptBase32
  • FOFEncryptRandval
  • FOFEncryptTotp
  • FOFForm
  • FOFFormFieldAccesslevel
  • FOFFormFieldActions
  • FOFFormFieldButton
  • FOFFormFieldCachehandler
  • FOFFormFieldCalendar
  • FOFFormFieldCaptcha
  • FOFFormFieldCheckbox
  • FOFFormFieldCheckboxes
  • FOFFormFieldComponents
  • FOFFormFieldEditor
  • FOFFormFieldEmail
  • FOFFormFieldGroupedbutton
  • FOFFormFieldGroupedlist
  • FOFFormFieldHidden
  • FOFFormFieldImage
  • FOFFormFieldImagelist
  • FOFFormFieldInteger
  • FOFFormFieldLanguage
  • FOFFormFieldList
  • FOFFormFieldMedia
  • FOFFormFieldModel
  • FOFFormFieldOrdering
  • FOFFormFieldPassword
  • FOFFormFieldPlugins
  • FOFFormFieldPublished
  • FOFFormFieldRadio
  • FOFFormFieldRelation
  • FOFFormFieldRules
  • FOFFormFieldSelectrow
  • FOFFormFieldSessionhandler
  • FOFFormFieldSpacer
  • FOFFormFieldSql
  • FOFFormFieldTag
  • FOFFormFieldTel
  • FOFFormFieldText
  • FOFFormFieldTextarea
  • FOFFormFieldTimezone
  • FOFFormFieldTitle
  • FOFFormFieldUrl
  • FOFFormFieldUser
  • FOFFormFieldUsergroup
  • FOFFormHeader
  • FOFFormHeaderAccesslevel
  • FOFFormHeaderField
  • FOFFormHeaderFielddate
  • FOFFormHeaderFieldfilterable
  • FOFFormHeaderFieldsearchable
  • FOFFormHeaderFieldselectable
  • FOFFormHeaderFieldsql
  • FOFFormHeaderFilterdate
  • FOFFormHeaderFilterfilterable
  • FOFFormHeaderFiltersearchable
  • FOFFormHeaderFilterselectable
  • FOFFormHeaderFiltersql
  • FOFFormHeaderLanguage
  • FOFFormHeaderModel
  • FOFFormHeaderOrdering
  • FOFFormHeaderPublished
  • FOFFormHeaderRowselect
  • FOFFormHelper
  • FOFHalDocument
  • FOFHalLink
  • FOFHalLinks
  • FOFHalRenderJson
  • FOFInflector
  • FOFInput
  • FOFIntegrationJoomlaFilesystem
  • FOFIntegrationJoomlaPlatform
  • FOFLayoutFile
  • FOFLayoutHelper
  • FOFLess
  • FOFLessFormatterClassic
  • FOFLessFormatterCompressed
  • FOFLessFormatterJoomla
  • FOFLessFormatterLessjs
  • FOFLessParser
  • FOFModel
  • FOFModelBehavior
  • FOFModelBehaviorAccess
  • FOFModelBehaviorEmptynonzero
  • FOFModelBehaviorEnabled
  • FOFModelBehaviorFilters
  • FOFModelBehaviorLanguage
  • FOFModelBehaviorPrivate
  • FOFModelDispatcherBehavior
  • FOFModelField
  • FOFModelFieldBoolean
  • FOFModelFieldDate
  • FOFModelFieldNumber
  • FOFModelFieldText
  • FOFPlatform
  • FOFPlatformFilesystem
  • FOFQueryAbstract
  • FOFRenderAbstract
  • FOFRenderJoomla
  • FOFRenderJoomla3
  • FOFRenderStrapper
  • FOFStringUtils
  • FOFTable
  • FOFTableBehavior
  • FOFTableBehaviorAssets
  • FOFTableBehaviorContenthistory
  • FOFTableBehaviorTags
  • FOFTableDispatcherBehavior
  • FOFTableNested
  • FOFTableRelations
  • FOFTemplateUtils
  • FOFToolbar
  • FOFUtilsArray
  • FOFUtilsCacheCleaner
  • FOFUtilsConfigHelper
  • FOFUtilsFilescheck
  • FOFUtilsIniParser
  • FOFUtilsInstallscript
  • FOFUtilsIp
  • FOFUtilsObject
  • FOFUtilsObservableDispatcher
  • FOFUtilsObservableEvent
  • FOFUtilsPhpfunc
  • FOFUtilsTimer
  • FOFUtilsUpdate
  • FOFUtilsUpdateCollection
  • FOFUtilsUpdateExtension
  • FOFUtilsUpdateJoomla
  • FOFView
  • FOFViewCsv
  • FOFViewForm
  • FOFViewHtml
  • FOFViewJson
  • FOFViewRaw
  • idna_convert
  • JAccess
  • JAccessRule
  • JAccessRules
  • JAccessWrapperAccess
  • JAdapter
  • JAdapterInstance
  • JApplication
  • JApplicationAdministrator
  • JApplicationBase
  • JApplicationCli
  • JApplicationCms
  • JApplicationDaemon
  • JApplicationHelper
  • JApplicationSite
  • JApplicationWeb
  • JApplicationWebRouter
  • JApplicationWebRouterBase
  • JApplicationWebRouterRest
  • JArchive
  • JArchiveBzip2
  • JArchiveGzip
  • JArchiveTar
  • JArchiveWrapperArchive
  • JArchiveZip
  • JArrayHelper
  • JAssociationExtensionHelper
  • JAuthentication
  • JAuthenticationHelper
  • JAuthenticationResponse
  • JBrowser
  • JBuffer
  • JButton
  • JCache
  • JCacheController
  • JCacheControllerCallback
  • JCacheControllerOutput
  • JCacheControllerPage
  • JCacheControllerView
  • JCacheStorage
  • JCacheStorageApc
  • JCacheStorageApcu
  • JCacheStorageCachelite
  • JCacheStorageFile
  • JCacheStorageHelper
  • JCacheStorageMemcache
  • JCacheStorageMemcached
  • JCacheStorageRedis
  • JCacheStorageWincache
  • JCacheStorageXcache
  • JCaptcha
  • JCategories
  • JCategoryNode
  • JClassLoader
  • JCli
  • JClientFtp
  • JClientHelper
  • JClientLdap
  • JClientWrapperHelper
  • JComponentHelper
  • JComponentRecord
  • JComponentRouterBase
  • JComponentRouterLegacy
  • JComponentRouterRulesMenu
  • JComponentRouterRulesNomenu
  • JComponentRouterRulesStandard
  • JComponentRouterView
  • JComponentRouterViewconfiguration
  • JControllerAdmin
  • JControllerBase
  • JControllerForm
  • JControllerLegacy
  • JCrypt
  • JCryptCipher3Des
  • JCryptCipherBlowfish
  • JCryptCipherCrypto
  • JCryptCipherMcrypt
  • JCryptCipherRijndael256
  • JCryptCipherSimple
  • JCryptKey
  • JCryptPasswordSimple
  • JDaemon
  • JDatabase
  • JDatabaseDriver
  • JDatabaseDriverMysql
  • JDatabaseDriverMysqli
  • JDatabaseDriverOracle
  • JDatabaseDriverPdo
  • JDatabaseDriverPdomysql
  • JDatabaseDriverPostgresql
  • JDatabaseDriverSqlazure
  • JDatabaseDriverSqlite
  • JDatabaseDriverSqlsrv
  • JDatabaseExporter
  • JDatabaseExporterMysql
  • JDatabaseExporterMysqli
  • JDatabaseExporterPdomysql
  • JDatabaseExporterPostgresql
  • JDatabaseFactory
  • JDatabaseImporter
  • JDatabaseImporterMysql
  • JDatabaseImporterMysqli
  • JDatabaseImporterPdomysql
  • JDatabaseImporterPostgresql
  • JDatabaseInterface
  • JDatabaseIterator
  • JDatabaseIteratorMysql
  • JDatabaseIteratorMysqli
  • JDatabaseIteratorOracle
  • JDatabaseIteratorPdo
  • JDatabaseIteratorPdomysql
  • JDatabaseIteratorPostgresql
  • JDatabaseIteratorSqlazure
  • JDatabaseIteratorSqlite
  • JDatabaseIteratorSqlsrv
  • JDatabaseMysql
  • JDatabaseMysqli
  • JDatabaseQuery
  • JDatabaseQueryElement
  • JDatabaseQueryLimitable
  • JDatabaseQueryMysql
  • JDatabaseQueryMysqli
  • JDatabaseQueryOracle
  • JDatabaseQueryPdo
  • JDatabaseQueryPdomysql
  • JDatabaseQueryPostgresql
  • JDatabaseQueryPreparable
  • JDatabaseQuerySqlazure
  • JDatabaseQuerySqlite
  • JDatabaseQuerySqlsrv
  • JDatabaseSqlazure
  • JDatabaseSqlsrv
  • JDate
  • JDispatcher
  • JDocument
  • JDocumentError
  • JDocumentFeed
  • JDocumentHtml
  • JDocumentImage
  • JDocumentJson
  • JDocumentOpensearch
  • JDocumentRaw
  • JDocumentRenderer
  • JDocumentRendererAtom
  • JDocumentRendererComponent
  • JDocumentRendererFeedAtom
  • JDocumentRendererFeedRss
  • JDocumentRendererHead
  • JDocumentRendererHtmlComponent
  • JDocumentRendererHtmlHead
  • JDocumentRendererHtmlMessage
  • JDocumentRendererHtmlModule
  • JDocumentRendererHtmlModules
  • JDocumentRendererMessage
  • JDocumentRendererModule
  • JDocumentRendererModules
  • JDocumentRendererRSS
  • JDocumentXml
  • JEditor
  • JError
  • JErrorPage
  • JEvent
  • JEventDispatcher
  • JExtension
  • JFacebook
  • JFacebookAlbum
  • JFacebookCheckin
  • JFacebookComment
  • JFacebookEvent
  • JFacebookGroup
  • JFacebookLink
  • JFacebookNote
  • JFacebookOAuth
  • JFacebookObject
  • JFacebookPhoto
  • JFacebookPost
  • JFacebookStatus
  • JFacebookUser
  • JFacebookVideo
  • JFactory
  • JFeed
  • JFeedEnclosure
  • JFeedEntry
  • JFeedFactory
  • JFeedImage
  • JFeedItem
  • JFeedLink
  • JFeedParser
  • JFeedParserAtom
  • JFeedParserRss
  • JFeedParserRssItunes
  • JFeedParserRssMedia
  • JFeedPerson
  • JFile
  • JFilesystemHelper
  • JFilesystemPatcher
  • JFilesystemWrapperFile
  • JFilesystemWrapperFolder
  • JFilesystemWrapperPath
  • JFilterInput
  • JFilterOutput
  • JFilterWrapperOutput
  • JFolder
  • JForm
  • JFormField
  • JFormFieldAccessLevel
  • JFormFieldAliastag
  • JFormFieldAuthor
  • JFormFieldCacheHandler
  • JFormFieldCalendar
  • JFormFieldCaptcha
  • JFormFieldCategory
  • JFormFieldCheckbox
  • JFormFieldCheckboxes
  • JFormFieldChromeStyle
  • JFormFieldColor
  • JFormFieldCombo
  • JFormFieldComponentlayout
  • JFormFieldComponents
  • JFormFieldContenthistory
  • JFormFieldContentlanguage
  • JFormFieldContenttype
  • JFormFieldDatabaseConnection
  • JFormFieldEditor
  • JFormFieldEMail
  • JFormFieldFile
  • JFormFieldFileList
  • JFormFieldFolderList
  • JFormFieldFrontend_Language
  • JFormFieldGroupedList
  • JFormFieldHeadertag
  • JFormFieldHelpsite
  • JFormFieldHidden
  • JFormFieldImageList
  • JFormFieldInteger
  • JFormFieldLanguage
  • JFormFieldLastvisitDateRange
  • JFormFieldLimitbox
  • JFormFieldList
  • JFormFieldMedia
  • JFormFieldMenu
  • JFormFieldMenuitem
  • JFormFieldMeter
  • JFormFieldModulelayout
  • JFormFieldModuleOrder
  • JFormFieldModulePosition
  • JFormFieldModuletag
  • JFormFieldNote
  • JFormFieldNumber
  • JFormFieldOrdering
  • JFormFieldPassword
  • JFormFieldPlugin_Status
  • JFormFieldPlugins
  • JFormFieldPredefinedList
  • JFormFieldRadio
  • JFormFieldRange
  • JFormFieldRegistrationDateRange
  • JFormFieldRepeatable
  • JFormFieldRules
  • JFormFieldSessionHandler
  • JFormFieldSpacer
  • JFormFieldSQL
  • JFormFieldStatus
  • JFormFieldSubform
  • JFormFieldTag
  • JFormFieldTel
  • JFormFieldTemplatestyle
  • JFormFieldText
  • JFormFieldTextarea
  • JFormFieldTimezone
  • JFormFieldUrl
  • JFormFieldUser
  • JFormFieldUserActive
  • JFormFieldUsergroup
  • JFormFieldUserGroupList
  • JFormFieldUserState
  • JFormHelper
  • JFormRule
  • JFormRuleBoolean
  • JFormRuleCalendar
  • JFormRuleCaptcha
  • JFormRuleColor
  • JFormRuleEmail
  • JFormRuleEquals
  • JFormRuleNotequals
  • JFormRuleNumber
  • JFormRuleOptions
  • JFormRulePassword
  • JFormRuleRules
  • JFormRuleTel
  • JFormRuleUrl
  • JFormRuleUsername
  • JFormWrapperHelper
  • JFTP
  • JGithub
  • JGithubAccount
  • JGithubCommits
  • JGithubForks
  • JGithubHooks
  • JGithubHttp
  • JGithubMeta
  • JGithubMilestones
  • JGithubObject
  • JGithubPackage
  • JGithubPackageActivity
  • JGithubPackageActivityEvents
  • JGithubPackageActivityNotifications
  • JGithubPackageActivityStarring
  • JGithubPackageActivityWatching
  • JGithubPackageAuthorization
  • JGithubPackageData
  • JGithubPackageDataBlobs
  • JGithubPackageDataCommits
  • JGithubPackageDataRefs
  • JGithubPackageDataTags
  • JGithubPackageDataTrees
  • JGithubPackageGists
  • JGithubPackageGistsComments
  • JGithubPackageGitignore
  • JGithubPackageIssues
  • JGithubPackageIssuesAssignees
  • JGithubPackageIssuesComments
  • JGithubPackageIssuesEvents
  • JGithubPackageIssuesLabels
  • JGithubPackageIssuesMilestones
  • JGithubPackageMarkdown
  • JGithubPackageOrgs
  • JGithubPackageOrgsMembers
  • JGithubPackageOrgsTeams
  • JGithubPackagePulls
  • JGithubPackagePullsComments
  • JGithubPackageRepositories
  • JGithubPackageRepositoriesCollaborators
  • JGithubPackageRepositoriesComments
  • JGithubPackageRepositoriesCommits
  • JGithubPackageRepositoriesContents
  • JGithubPackageRepositoriesDownloads
  • JGithubPackageRepositoriesForks
  • JGithubPackageRepositoriesHooks
  • JGithubPackageRepositoriesKeys
  • JGithubPackageRepositoriesMerging
  • JGithubPackageRepositoriesStatistics
  • JGithubPackageRepositoriesStatuses
  • JGithubPackageSearch
  • JGithubPackageUsers
  • JGithubPackageUsersEmails
  • JGithubPackageUsersFollowers
  • JGithubPackageUsersKeys
  • JGithubRefs
  • JGithubStatuses
  • JGoogle
  • JGoogleAuth
  • JGoogleAuthOauth2
  • JGoogleData
  • JGoogleDataAdsense
  • JGoogleDataCalendar
  • JGoogleDataPicasa
  • JGoogleDataPicasaAlbum
  • JGoogleDataPicasaPhoto
  • JGoogleDataPlus
  • JGoogleDataPlusActivities
  • JGoogleDataPlusComments
  • JGoogleDataPlusPeople
  • JGoogleEmbed
  • JGoogleEmbedAnalytics
  • JGoogleEmbedMaps
  • JGrid
  • JHelp
  • JHelper
  • JHelperContent
  • JHelperContenthistory
  • JHelperMedia
  • JHelperRoute
  • JHelperTags
  • JHelperUsergroups
  • JHtml
  • JHtmlAccess
  • JHtmlActionsDropdown
  • JHtmlBatch
  • JHtmlBehavior
  • JHtmlBootstrap
  • JHtmlCategory
  • JHtmlContent
  • JHtmlContentLanguage
  • JHtmlDate
  • JHtmlDebug
  • JHtmlDropdown
  • JHtmlEmail
  • JHtmlForm
  • JHtmlFormbehavior
  • JHtmlGrid
  • JHtmlIcons
  • JHtmlJGrid
  • JHtmlJquery
  • JHtmlLinks
  • JHtmlList
  • JHtmlMenu
  • JHtmlNumber
  • JHtmlRules
  • JHtmlSearchtools
  • JHtmlSelect
  • JHtmlSidebar
  • JHtmlSliders
  • JHtmlSortablelist
  • JHtmlString
  • JHtmlTabs
  • JHtmlTag
  • JHtmlTel
  • JHtmlUser
  • JHttp
  • JHttpFactory
  • JHttpResponse
  • JHttpTransportCurl
  • JHttpTransportSocket
  • JHttpTransportStream
  • JHttpWrapperFactory
  • JImage
  • JImageFilter
  • JImageFilterBackgroundfill
  • JImageFilterBrightness
  • JImageFilterContrast
  • JImageFilterEdgedetect
  • JImageFilterEmboss
  • JImageFilterGrayscale
  • JImageFilterNegate
  • JImageFilterSketchy
  • JImageFilterSmooth
  • JInput
  • JInputCli
  • JInputCookie
  • JInputFiles
  • JInputJSON
  • JInstaller
  • JInstallerAdapter
  • JInstallerAdapterComponent
  • JInstallerAdapterFile
  • JInstallerAdapterLanguage
  • JInstallerAdapterLibrary
  • JInstallerAdapterModule
  • JInstallerAdapterPackage
  • JInstallerAdapterPlugin
  • JInstallerAdapterTemplate
  • JInstallerComponent
  • JInstallerExtension
  • JInstallerFile
  • JInstallerHelper
  • JInstallerLanguage
  • JInstallerLibrary
  • JInstallerManifest
  • JInstallerManifestLibrary
  • JInstallerManifestPackage
  • JInstallerModule
  • JInstallerPackage
  • JInstallerPlugin
  • JInstallerScript
  • JInstallerTemplate
  • JKeychain
  • JLanguage
  • JLanguageAssociations
  • JLanguageHelper
  • JLanguageMultilang
  • JLanguageStemmer
  • JLanguageStemmerPorteren
  • JLanguageTransliterate
  • JLanguageWrapperHelper
  • JLanguageWrapperText
  • JLanguageWrapperTransliterate
  • JLayoutBase
  • JLayoutFile
  • JLayoutHelper
  • JLDAP
  • JLess
  • JLessFormatterJoomla
  • JLibraryHelper
  • JLinkedin
  • JLinkedinCommunications
  • JLinkedinCompanies
  • JLinkedinGroups
  • JLinkedinJobs
  • JLinkedinOauth
  • JLinkedinObject
  • JLinkedinPeople
  • JLinkedinStream
  • JLoader
  • JLog
  • JLogEntry
  • JLogger
  • JLogLogger
  • JLogLoggerCallback
  • JLogLoggerDatabase
  • JLogLoggerEcho
  • JLogLoggerFormattedtext
  • JLogLoggerMessagequeue
  • JLogLoggerSyslog
  • JLogLoggerW3c
  • JMail
  • JMailHelper
  • JMailWrapperHelper
  • JMediawiki
  • JMediawikiCategories
  • JMediawikiHttp
  • JMediawikiImages
  • JMediawikiLinks
  • JMediawikiObject
  • JMediawikiPages
  • JMediawikiSearch
  • JMediawikiSites
  • JMediawikiUsers
  • JMenu
  • JMenuAdministrator
  • JMenuItem
  • JMenuSite
  • JMicrodata
  • JModelAdmin
  • JModelBase
  • JModelDatabase
  • JModelForm
  • JModelItem
  • JModelLegacy
  • JModelList
  • JModuleHelper
  • JNode
  • JOAuth1Client
  • JOAuth2Client
  • JObject
  • JObservable
  • JObserver
  • JObserverMapper
  • JObserverUpdater
  • JObserverWrapperMapper
  • JOpenSearchImage
  • JOpenSearchUrl
  • JOpenstreetmap
  • JOpenstreetmapChangesets
  • JOpenstreetmapElements
  • JOpenstreetmapGps
  • JOpenstreetmapInfo
  • JOpenstreetmapOauth
  • JOpenstreetmapObject
  • JOpenstreetmapUser
  • JPagination
  • JPaginationObject
  • JPath
  • JPathway
  • JPathwaySite
  • JPlatform
  • JPlugin
  • JPluginHelper
  • JProfiler
  • JRequest
  • JResponse
  • JResponseJson
  • JRoute
  • JRouter
  • JRouterAdministrator
  • JRouterSite
  • JRouteWrapperRoute
  • JRule
  • JRules
  • JSchemaChangeitem
  • JSchemaChangeitemMysql
  • JSchemaChangeitemPostgresql
  • JSchemaChangeitemSqlsrv
  • JSchemaChangeset
  • JSearchHelper
  • JSession
  • JSessionHandlerJoomla
  • JSessionHandlerNative
  • JSessionStorage
  • JSessionStorageApc
  • JSessionStorageDatabase
  • JSessionStorageMemcache
  • JSessionStorageMemcached
  • JSessionStorageNone
  • JSessionStorageWincache
  • JSessionStorageXcache
  • JSimplecrypt
  • JSimplepieFactory
  • JStream
  • JStreamString
  • JString
  • JStringController
  • JStringPunycode
  • JStringWrapperNormalise
  • JStringWrapperPunycode
  • JTable
  • JTableAsset
  • JTableCategory
  • JTableContent
  • JTableContenthistory
  • JTableContenttype
  • JTableCorecontent
  • JTableExtension
  • JTableInterface
  • JTableLanguage
  • JTableMenu
  • JTableMenuType
  • JTableModule
  • JTableNested
  • JTableObserver
  • JTableObserverContenthistory
  • JTableObserverTags
  • JTableSession
  • JTableUcm
  • JTableUpdate
  • JTableUpdatesite
  • JTableUser
  • JTableUsergroup
  • JTableViewlevel
  • JText
  • JToolbar
  • JToolbarButton
  • JToolbarButtonConfirm
  • JToolbarButtonCustom
  • JToolbarButtonHelp
  • JToolbarButtonLink
  • JToolbarButtonPopup
  • JToolbarButtonSeparator
  • JToolbarButtonSlider
  • JToolbarButtonStandard
  • JTree
  • JTwitter
  • JTwitterBlock
  • JTwitterDirectmessages
  • JTwitterFavorites
  • JTwitterFriends
  • JTwitterHelp
  • JTwitterLists
  • JTwitterOAuth
  • JTwitterObject
  • JTwitterPlaces
  • JTwitterProfile
  • JTwittersearch
  • JTwitterStatuses
  • JTwitterTrends
  • JTwitterUsers
  • JUcmBase
  • JUcmContent
  • JUcmType
  • JUpdate
  • JUpdateAdapter
  • JUpdater
  • JUpdaterCollection
  • JUpdaterExtension
  • JUri
  • JUser
  • JUserHelper
  • JUserWrapperHelper
  • JUtility
  • JVersion
  • JViewBase
  • JViewCategories
  • JViewCategory
  • JViewCategoryfeed
  • JViewHtml
  • JViewLegacy
  • JWeb
  • JWebClient
  • JXMLElement
  • lessc
  • lessc_formatter_classic
  • lessc_formatter_compressed
  • lessc_formatter_lessjs
  • lessc_parser
  • lessify
  • Net_IDNA_php4
  • nodecounter
  • ntlm_sasl_client_class
  • PHPMailer
  • PHPMailerOAuth
  • PHPMailerOAuthGoogle
  • POP3
  • SimplePie
  • SimplePie_Author
  • SimplePie_Autoloader
  • SimplePie_Cache
  • SimplePie_Cache_DB
  • SimplePie_Cache_File
  • SimplePie_Cache_Memcache
  • SimplePie_Cache_MySQL
  • SimplePie_Caption
  • SimplePie_Category
  • SimplePie_Content_Type_Sniffer
  • SimplePie_Copyright
  • SimplePie_Core
  • SimplePie_Credit
  • SimplePie_Decode_HTML_Entities
  • SimplePie_Enclosure
  • SimplePie_File
  • SimplePie_gzdecode
  • SimplePie_HTTP_Parser
  • SimplePie_IRI
  • SimplePie_Item
  • SimplePie_Locator
  • SimplePie_Misc
  • SimplePie_Net_IPv6
  • SimplePie_Parse_Date
  • SimplePie_Parser
  • SimplePie_Rating
  • SimplePie_Registry
  • SimplePie_Restriction
  • SimplePie_Sanitize
  • SimplePie_Source
  • SimplePie_XML_Declaration_Parser
  • SMTP
  • tagparse
  • TypeError

Interfaces

  • FOFConfigDomainInterface
  • FOFDatabaseInterface
  • FOFDatabaseQueryLimitable
  • FOFDatabaseQueryPreparable
  • FOFDownloadInterface
  • FOFEncryptAesInterface
  • FOFEncryptRandvalinterface
  • FOFFormField
  • FOFHalRenderInterface
  • FOFPlatformFilesystemInterface
  • FOFPlatformInterface
  • JArchiveExtractable
  • JAssociationExtensionInterface
  • JCacheException
  • JComponentRouterInterface
  • JComponentRouterRulesInterface
  • JController
  • JCryptCipher
  • JCryptPassword
  • JFeedParserNamespace
  • JHttpTransport
  • JLayout
  • JModel
  • JObservableInterface
  • JObserverInterface
  • JObserverUpdaterInterface
  • JSessionHandlerInterface
  • JsonSerializable
  • JUcm
  • JView
  • SimplePie_Cache_Base

Exceptions

  • Error
  • JAccessExceptionNotallowed
  • JCacheExceptionConnecting
  • JCacheExceptionUnsupported
  • JComponentExceptionMissing
  • JDatabaseException
  • JDatabaseExceptionConnecting
  • JDatabaseExceptionExecuting
  • JDatabaseExceptionUnsupported
  • JException
  • JSessionExceptionUnsupported
  • LogException
  • phpmailerException
  • SimplePie_Exception

Constants

  • JERROR_CALLBACK_NOT_CALLABLE
  • JERROR_ILLEGAL_MODE
  • JERROR_ILLEGAL_OPTIONS
  • JREQUEST_ALLOWHTML
  • JREQUEST_ALLOWRAW
  • JREQUEST_NOTRIM
  • JROUTER_MODE_RAW
  • JROUTER_MODE_SEF

Functions

  • __autoload
  • array_column
  • boolval
  • composerRequire205c915b9c7d3e718e7c95793ee67ffe
  • gzopen
  • gzseek
  • gztell
  • hash_equals
  • hash_pbkdf2
  • HTMLFilter
  • jexit
  • jimport
  • json_last_error_msg
  • ldap_escape
  • password_get_info
  • password_hash
  • password_needs_rehash
  • password_verify
  • PHPMailerAutoload
  • random_bytes
  • random_int
  • RandomCompat_intval
  • RandomCompat_strlen
  • RandomCompat_substr
  • tln_body2div
  • tln_casenormalize
  • tln_deent
  • tln_defang
  • tln_findnxreg
  • tln_findnxstr
  • tln_fixatts
  • tln_fixstyle
  • tln_fixurl
  • tln_getnxtag
  • tln_sanitize
  • tln_skipspace
  • tln_tagprint
  • tln_unspace
  • utf8_accents_to_ascii
  • utf8_bad_explain
  • utf8_bad_find
  • utf8_bad_findall
  • utf8_bad_identify
  • utf8_bad_replace
  • utf8_bad_strip
  • utf8_byte_position
  • utf8_compliant
  • utf8_from_unicode
  • utf8_ireplace
  • utf8_is_ascii
  • utf8_is_ascii_ctrl
  • utf8_is_valid
  • utf8_is_word_chars
  • utf8_locate_current_chr
  • utf8_locate_next_chr
  • utf8_ltrim
  • utf8_ord
  • utf8_rtrim
  • utf8_specials_pattern
  • utf8_str_pad
  • utf8_str_split
  • utf8_strcasecmp
  • utf8_strcspn
  • utf8_strip_ascii_ctrl
  • utf8_strip_non_ascii
  • utf8_strip_non_ascii_ctrl
  • utf8_strip_specials
  • utf8_stristr
  • utf8_strlen
  • utf8_strpos
  • utf8_strrev
  • utf8_strrpos
  • utf8_strspn
  • utf8_strtolower
  • utf8_strtoupper
  • utf8_substr
  • utf8_substr_replace
  • utf8_to_unicode
  • utf8_trim
  • utf8_ucfirst
  • utf8_ucwords
  • utf8_ucwords_callback
   1 <?php
   2 /**
   3  * @package     Joomla.Libraries
   4  * @subpackage  Installer
   5  *
   6  * @copyright   Copyright (C) 2005 - 2017 Open Source Matters, Inc. All rights reserved.
   7  * @license     GNU General Public License version 2 or later; see LICENSE.txt
   8  */
   9 
  10 defined('JPATH_PLATFORM') or die;
  11 
  12 jimport('joomla.filesystem.file');
  13 jimport('joomla.filesystem.folder');
  14 jimport('joomla.filesystem.path');
  15 jimport('joomla.base.adapter');
  16 
  17 /**
  18  * Joomla base installer class
  19  *
  20  * @since  3.1
  21  */
  22 class JInstaller extends JAdapter
  23 {
  24     /**
  25      * Array of paths needed by the installer
  26      *
  27      * @var    array
  28      * @since  3.1
  29      */
  30     protected $paths = array();
  31 
  32     /**
  33      * True if package is an upgrade
  34      *
  35      * @var    boolean
  36      * @since  3.1
  37      */
  38     protected $upgrade = null;
  39 
  40     /**
  41      * The manifest trigger class
  42      *
  43      * @var    object
  44      * @since  3.1
  45      */
  46     public $manifestClass = null;
  47 
  48     /**
  49      * True if existing files can be overwritten
  50      *
  51      * @var    boolean
  52      * @since  12.1
  53      */
  54     protected $overwrite = false;
  55 
  56     /**
  57      * Stack of installation steps
  58      * - Used for installation rollback
  59      *
  60      * @var    array
  61      * @since  3.1
  62      */
  63     protected $stepStack = array();
  64 
  65     /**
  66      * Extension Table Entry
  67      *
  68      * @var    JTableExtension
  69      * @since  3.1
  70      */
  71     public $extension = null;
  72 
  73     /**
  74      * The output from the install/uninstall scripts
  75      *
  76      * @var    string
  77      * @since  3.1
  78      * */
  79     public $message = null;
  80 
  81     /**
  82      * The installation manifest XML object
  83      *
  84      * @var    object
  85      * @since  3.1
  86      */
  87     public $manifest = null;
  88 
  89     /**
  90      * The extension message that appears
  91      *
  92      * @var    string
  93      * @since  3.1
  94      */
  95     protected $extension_message = null;
  96 
  97     /**
  98      * The redirect URL if this extension (can be null if no redirect)
  99      *
 100      * @var    string
 101      * @since  3.1
 102      */
 103     protected $redirect_url = null;
 104 
 105     /**
 106      * Flag if the uninstall process was triggered by uninstalling a package
 107      *
 108      * @var    boolean
 109      * @since  3.7.0
 110      */
 111     protected $packageUninstall = false;
 112 
 113     /**
 114      * JInstaller instance container.
 115      *
 116      * @var    JInstaller
 117      * @since  3.1
 118      * @deprecated  4.0
 119      */
 120     protected static $instance;
 121 
 122     /**
 123      * JInstaller instances container.
 124      *
 125      * @var    JInstaller[]
 126      * @since  3.4
 127      */
 128     protected static $instances;
 129 
 130     /**
 131      * Constructor
 132      *
 133      * @param   string  $basepath       Base Path of the adapters
 134      * @param   string  $classprefix    Class prefix of adapters
 135      * @param   string  $adapterfolder  Name of folder to append to base path
 136      *
 137      * @since   3.1
 138      */
 139     public function __construct($basepath = __DIR__, $classprefix = 'JInstallerAdapter', $adapterfolder = 'adapter')
 140     {
 141         parent::__construct($basepath, $classprefix, $adapterfolder);
 142 
 143         $this->extension = JTable::getInstance('extension');
 144     }
 145 
 146     /**
 147      * Returns the global Installer object, only creating it if it doesn't already exist.
 148      *
 149      * @param   string  $basepath       Base Path of the adapters
 150      * @param   string  $classprefix    Class prefix of adapters
 151      * @param   string  $adapterfolder  Name of folder to append to base path
 152      *
 153      * @return  JInstaller  An installer object
 154      *
 155      * @since   3.1
 156      */
 157     public static function getInstance($basepath = __DIR__, $classprefix = 'JInstallerAdapter', $adapterfolder = 'adapter')
 158     {
 159         if (!isset(self::$instances[$basepath]))
 160         {
 161             self::$instances[$basepath] = new JInstaller($basepath, $classprefix, $adapterfolder);
 162 
 163             // For B/C, we load the first instance into the static $instance container, remove at 4.0
 164             if (!isset(self::$instance))
 165             {
 166                 self::$instance = self::$instances[$basepath];
 167             }
 168         }
 169 
 170         return self::$instances[$basepath];
 171     }
 172 
 173     /**
 174      * Get the allow overwrite switch
 175      *
 176      * @return  boolean  Allow overwrite switch
 177      *
 178      * @since   3.1
 179      */
 180     public function isOverwrite()
 181     {
 182         return $this->overwrite;
 183     }
 184 
 185     /**
 186      * Set the allow overwrite switch
 187      *
 188      * @param   boolean  $state  Overwrite switch state
 189      *
 190      * @return  boolean  True it state is set, false if it is not
 191      *
 192      * @since   3.1
 193      */
 194     public function setOverwrite($state = false)
 195     {
 196         $tmp = $this->overwrite;
 197 
 198         if ($state)
 199         {
 200             $this->overwrite = true;
 201         }
 202         else
 203         {
 204             $this->overwrite = false;
 205         }
 206 
 207         return $tmp;
 208     }
 209 
 210     /**
 211      * Get the redirect location
 212      *
 213      * @return  string  Redirect location (or null)
 214      *
 215      * @since   3.1
 216      */
 217     public function getRedirectUrl()
 218     {
 219         return $this->redirect_url;
 220     }
 221 
 222     /**
 223      * Set the redirect location
 224      *
 225      * @param   string  $newurl  New redirect location
 226      *
 227      * @return  void
 228      *
 229      * @since   3.1
 230      */
 231     public function setRedirectUrl($newurl)
 232     {
 233         $this->redirect_url = $newurl;
 234     }
 235 
 236     /**
 237      * Get whether this installer is uninstalling extensions which are part of a package
 238      *
 239      * @return  boolean
 240      *
 241      * @since   3.7.0
 242      */
 243     public function isPackageUninstall()
 244     {
 245         return $this->packageUninstall;
 246     }
 247 
 248     /**
 249      * Set whether this installer is uninstalling extensions which are part of a package
 250      *
 251      * @param   boolean  $uninstall  True if a package triggered the uninstall, false otherwise
 252      *
 253      * @return  void
 254      *
 255      * @since   3.7.0
 256      */
 257     public function setPackageUninstall($uninstall)
 258     {
 259         $this->packageUninstall = $uninstall;
 260     }
 261 
 262     /**
 263      * Get the upgrade switch
 264      *
 265      * @return  boolean
 266      *
 267      * @since   3.1
 268      */
 269     public function isUpgrade()
 270     {
 271         return $this->upgrade;
 272     }
 273 
 274     /**
 275      * Set the upgrade switch
 276      *
 277      * @param   boolean  $state  Upgrade switch state
 278      *
 279      * @return  boolean  True if upgrade, false otherwise
 280      *
 281      * @since   3.1
 282      */
 283     public function setUpgrade($state = false)
 284     {
 285         $tmp = $this->upgrade;
 286 
 287         if ($state)
 288         {
 289             $this->upgrade = true;
 290         }
 291         else
 292         {
 293             $this->upgrade = false;
 294         }
 295 
 296         return $tmp;
 297     }
 298 
 299     /**
 300      * Get the installation manifest object
 301      *
 302      * @return  SimpleXMLElement  Manifest object
 303      *
 304      * @since   3.1
 305      */
 306     public function getManifest()
 307     {
 308         if (!is_object($this->manifest))
 309         {
 310             $this->findManifest();
 311         }
 312 
 313         return $this->manifest;
 314     }
 315 
 316     /**
 317      * Get an installer path by name
 318      *
 319      * @param   string  $name     Path name
 320      * @param   string  $default  Default value
 321      *
 322      * @return  string  Path
 323      *
 324      * @since   3.1
 325      */
 326     public function getPath($name, $default = null)
 327     {
 328         return (!empty($this->paths[$name])) ? $this->paths[$name] : $default;
 329     }
 330 
 331     /**
 332      * Sets an installer path by name
 333      *
 334      * @param   string  $name   Path name
 335      * @param   string  $value  Path
 336      *
 337      * @return  void
 338      *
 339      * @since   3.1
 340      */
 341     public function setPath($name, $value)
 342     {
 343         $this->paths[$name] = $value;
 344     }
 345 
 346     /**
 347      * Pushes a step onto the installer stack for rolling back steps
 348      *
 349      * @param   array  $step  Installer step
 350      *
 351      * @return  void
 352      *
 353      * @since   3.1
 354      */
 355     public function pushStep($step)
 356     {
 357         $this->stepStack[] = $step;
 358     }
 359 
 360     /**
 361      * Installation abort method
 362      *
 363      * @param   string  $msg   Abort message from the installer
 364      * @param   string  $type  Package type if defined
 365      *
 366      * @return  boolean  True if successful
 367      *
 368      * @since   3.1
 369      */
 370     public function abort($msg = null, $type = null)
 371     {
 372         $retval = true;
 373         $step = array_pop($this->stepStack);
 374 
 375         // Raise abort warning
 376         if ($msg)
 377         {
 378             JLog::add($msg, JLog::WARNING, 'jerror');
 379         }
 380 
 381         while ($step != null)
 382         {
 383             switch ($step['type'])
 384             {
 385                 case 'file':
 386                     // Remove the file
 387                     $stepval = JFile::delete($step['path']);
 388                     break;
 389 
 390                 case 'folder':
 391                     // Remove the folder
 392                     $stepval = JFolder::delete($step['path']);
 393                     break;
 394 
 395                 case 'query':
 396                     // Execute the query.
 397                     $stepval = $this->parseSQLFiles($step['script']);
 398                     break;
 399 
 400                 case 'extension':
 401                     // Get database connector object
 402                     $db = $this->getDbo();
 403                     $query = $db->getQuery(true);
 404 
 405                     // Remove the entry from the #__extensions table
 406                     $query->delete($db->quoteName('#__extensions'))
 407                         ->where($db->quoteName('extension_id') . ' = ' . (int) $step['id']);
 408                     $db->setQuery($query);
 409 
 410                     try
 411                     {
 412                         $db->execute();
 413 
 414                         $stepval = true;
 415                     }
 416                     catch (JDatabaseExceptionExecuting $e)
 417                     {
 418                         // The database API will have already logged the error it caught, we just need to alert the user to the issue
 419                         JLog::add(JText::_('JLIB_INSTALLER_ABORT_ERROR_DELETING_EXTENSIONS_RECORD'), JLog::WARNING, 'jerror');
 420 
 421                         $stepval = false;
 422                     }
 423 
 424                     break;
 425 
 426                 default:
 427                     if ($type && is_object($this->_adapters[$type]))
 428                     {
 429                         // Build the name of the custom rollback method for the type
 430                         $method = '_rollback_' . $step['type'];
 431 
 432                         // Custom rollback method handler
 433                         if (method_exists($this->_adapters[$type], $method))
 434                         {
 435                             $stepval = $this->_adapters[$type]->$method($step);
 436                         }
 437                     }
 438                     else
 439                     {
 440                         // Set it to false
 441                         $stepval = false;
 442                     }
 443                     break;
 444             }
 445 
 446             // Only set the return value if it is false
 447             if ($stepval === false)
 448             {
 449                 $retval = false;
 450             }
 451 
 452             // Get the next step and continue
 453             $step = array_pop($this->stepStack);
 454         }
 455 
 456         return $retval;
 457     }
 458 
 459     // Adapter functions
 460 
 461     /**
 462      * Package installation method
 463      *
 464      * @param   string  $path  Path to package source folder
 465      *
 466      * @return  boolean  True if successful
 467      *
 468      * @since   3.1
 469      */
 470     public function install($path = null)
 471     {
 472         if ($path && JFolder::exists($path))
 473         {
 474             $this->setPath('source', $path);
 475         }
 476         else
 477         {
 478             $this->abort(JText::_('JLIB_INSTALLER_ABORT_NOINSTALLPATH'));
 479 
 480             return false;
 481         }
 482 
 483         if (!$adapter = $this->setupInstall('install', true))
 484         {
 485             $this->abort(JText::_('JLIB_INSTALLER_ABORT_DETECTMANIFEST'));
 486 
 487             return false;
 488         }
 489 
 490         if (!is_object($adapter))
 491         {
 492             return false;
 493         }
 494 
 495         // Add the languages from the package itself
 496         if (method_exists($adapter, 'loadLanguage'))
 497         {
 498             $adapter->loadLanguage($path);
 499         }
 500 
 501         // Fire the onExtensionBeforeInstall event.
 502         JPluginHelper::importPlugin('extension');
 503         $dispatcher = JEventDispatcher::getInstance();
 504         $dispatcher->trigger(
 505             'onExtensionBeforeInstall',
 506             array(
 507                 'method' => 'install',
 508                 'type' => $this->manifest->attributes()->type,
 509                 'manifest' => $this->manifest,
 510                 'extension' => 0,
 511             )
 512         );
 513 
 514         // Run the install
 515         $result = $adapter->install();
 516 
 517         // Fire the onExtensionAfterInstall
 518         $dispatcher->trigger(
 519             'onExtensionAfterInstall',
 520             array('installer' => clone $this, 'eid' => $result)
 521         );
 522 
 523         if ($result !== false)
 524         {
 525             // Refresh versionable assets cache
 526             JFactory::getApplication()->flushAssets();
 527 
 528             return true;
 529         }
 530 
 531         return false;
 532     }
 533 
 534     /**
 535      * Discovered package installation method
 536      *
 537      * @param   integer  $eid  Extension ID
 538      *
 539      * @return  boolean  True if successful
 540      *
 541      * @since   3.1
 542      */
 543     public function discover_install($eid = null)
 544     {
 545         if (!$eid)
 546         {
 547             $this->abort(JText::_('JLIB_INSTALLER_ABORT_EXTENSIONNOTVALID'));
 548 
 549             return false;
 550         }
 551 
 552         if (!$this->extension->load($eid))
 553         {
 554             $this->abort(JText::_('JLIB_INSTALLER_ABORT_LOAD_DETAILS'));
 555 
 556             return false;
 557         }
 558 
 559         if ($this->extension->state != -1)
 560         {
 561             $this->abort(JText::_('JLIB_INSTALLER_ABORT_ALREADYINSTALLED'));
 562 
 563             return false;
 564         }
 565 
 566         // Load the adapter(s) for the install manifest
 567         $type   = $this->extension->type;
 568         $params = array('extension' => $this->extension, 'route' => 'discover_install');
 569 
 570         $adapter = $this->getAdapter($type, $params);
 571 
 572         if (!is_object($adapter))
 573         {
 574             return false;
 575         }
 576 
 577         if (!method_exists($adapter, 'discover_install') || !$adapter->getDiscoverInstallSupported())
 578         {
 579             $this->abort(JText::sprintf('JLIB_INSTALLER_ERROR_DISCOVER_INSTALL_UNSUPPORTED', $type));
 580 
 581             return false;
 582         }
 583 
 584         // The adapter needs to prepare itself
 585         if (method_exists($adapter, 'prepareDiscoverInstall'))
 586         {
 587             try
 588             {
 589                 $adapter->prepareDiscoverInstall();
 590             }
 591             catch (RuntimeException $e)
 592             {
 593                 $this->abort($e->getMessage());
 594 
 595                 return false;
 596             }
 597         }
 598 
 599         // Add the languages from the package itself
 600         if (method_exists($adapter, 'loadLanguage'))
 601         {
 602             $adapter->loadLanguage();
 603         }
 604 
 605         // Fire the onExtensionBeforeInstall event.
 606         JPluginHelper::importPlugin('extension');
 607         $dispatcher = JEventDispatcher::getInstance();
 608         $dispatcher->trigger(
 609             'onExtensionBeforeInstall',
 610             array(
 611                 'method' => 'discover_install',
 612                 'type' => $this->extension->get('type'),
 613                 'manifest' => null,
 614                 'extension' => $this->extension->get('extension_id'),
 615             )
 616         );
 617 
 618         // Run the install
 619         $result = $adapter->discover_install();
 620 
 621         // Fire the onExtensionAfterInstall
 622         $dispatcher->trigger(
 623             'onExtensionAfterInstall',
 624             array('installer' => clone $this, 'eid' => $result)
 625         );
 626 
 627         if ($result !== false)
 628         {
 629             // Refresh versionable assets cache
 630             JFactory::getApplication()->flushAssets();
 631 
 632             return true;
 633         }
 634 
 635         return false;
 636     }
 637 
 638     /**
 639      * Extension discover method
 640      *
 641      * Asks each adapter to find extensions
 642      *
 643      * @return  JInstallerExtension[]
 644      *
 645      * @since   3.1
 646      */
 647     public function discover()
 648     {
 649         $this->loadAllAdapters();
 650         $results = array();
 651 
 652         foreach ($this->_adapters as $adapter)
 653         {
 654             // Joomla! 1.5 installation adapter legacy support
 655             if (method_exists($adapter, 'discover'))
 656             {
 657                 $tmp = $adapter->discover();
 658 
 659                 // If its an array and has entries
 660                 if (is_array($tmp) && count($tmp))
 661                 {
 662                     // Merge it into the system
 663                     $results = array_merge($results, $tmp);
 664                 }
 665             }
 666         }
 667 
 668         return $results;
 669     }
 670 
 671     /**
 672      * Package update method
 673      *
 674      * @param   string  $path  Path to package source folder
 675      *
 676      * @return  boolean  True if successful
 677      *
 678      * @since   3.1
 679      */
 680     public function update($path = null)
 681     {
 682         if ($path && JFolder::exists($path))
 683         {
 684             $this->setPath('source', $path);
 685         }
 686         else
 687         {
 688             $this->abort(JText::_('JLIB_INSTALLER_ABORT_NOUPDATEPATH'));
 689 
 690             return false;
 691         }
 692 
 693         if (!$adapter = $this->setupInstall('update', true))
 694         {
 695             $this->abort(JText::_('JLIB_INSTALLER_ABORT_DETECTMANIFEST'));
 696 
 697             return false;
 698         }
 699 
 700         if (!is_object($adapter))
 701         {
 702             return false;
 703         }
 704 
 705         // Add the languages from the package itself
 706         if (method_exists($adapter, 'loadLanguage'))
 707         {
 708             $adapter->loadLanguage($path);
 709         }
 710 
 711         // Fire the onExtensionBeforeUpdate event.
 712         JPluginHelper::importPlugin('extension');
 713         $dispatcher = JEventDispatcher::getInstance();
 714         $dispatcher->trigger('onExtensionBeforeUpdate', array('type' => $this->manifest->attributes()->type, 'manifest' => $this->manifest));
 715 
 716         // Run the update
 717         $result = $adapter->update();
 718 
 719         // Fire the onExtensionAfterUpdate
 720         $dispatcher->trigger(
 721             'onExtensionAfterUpdate',
 722             array('installer' => clone $this, 'eid' => $result)
 723         );
 724 
 725         if ($result !== false)
 726         {
 727             return true;
 728         }
 729 
 730         return false;
 731     }
 732 
 733     /**
 734      * Package uninstallation method
 735      *
 736      * @param   string   $type        Package type
 737      * @param   mixed    $identifier  Package identifier for adapter
 738      * @param   integer  $cid         Application ID; deprecated in 1.6
 739      *
 740      * @return  boolean  True if successful
 741      *
 742      * @since   3.1
 743      */
 744     public function uninstall($type, $identifier, $cid = 0)
 745     {
 746         $params = array('extension' => $this->extension, 'route' => 'uninstall');
 747 
 748         $adapter = $this->getAdapter($type, $params);
 749 
 750         if (!is_object($adapter))
 751         {
 752             return false;
 753         }
 754 
 755         // We don't load languages here, we get the extension adapter to work it out
 756         // Fire the onExtensionBeforeUninstall event.
 757         JPluginHelper::importPlugin('extension');
 758         $dispatcher = JEventDispatcher::getInstance();
 759         $dispatcher->trigger('onExtensionBeforeUninstall', array('eid' => $identifier));
 760 
 761         // Run the uninstall
 762         $result = $adapter->uninstall($identifier);
 763 
 764         // Fire the onExtensionAfterInstall
 765         $dispatcher->trigger(
 766             'onExtensionAfterUninstall',
 767             array('installer' => clone $this, 'eid' => $identifier, 'result' => $result)
 768         );
 769 
 770         // Refresh versionable assets cache
 771         JFactory::getApplication()->flushAssets();
 772 
 773         return $result;
 774     }
 775 
 776     /**
 777      * Refreshes the manifest cache stored in #__extensions
 778      *
 779      * @param   integer  $eid  Extension ID
 780      *
 781      * @return  boolean
 782      *
 783      * @since   3.1
 784      */
 785     public function refreshManifestCache($eid)
 786     {
 787         if ($eid)
 788         {
 789             if (!$this->extension->load($eid))
 790             {
 791                 $this->abort(JText::_('JLIB_INSTALLER_ABORT_LOAD_DETAILS'));
 792 
 793                 return false;
 794             }
 795 
 796             if ($this->extension->state == -1)
 797             {
 798                 $this->abort(JText::_('JLIB_INSTALLER_ABORT_REFRESH_MANIFEST_CACHE'));
 799 
 800                 return false;
 801             }
 802 
 803             // Fetch the adapter
 804             $adapter = $this->getAdapter($this->extension->type);
 805 
 806             if (!is_object($adapter))
 807             {
 808                 return false;
 809             }
 810 
 811             if (!method_exists($adapter, 'refreshManifestCache'))
 812             {
 813                 $this->abort(JText::sprintf('JLIB_INSTALLER_ABORT_METHODNOTSUPPORTED_TYPE', $this->extension->type));
 814 
 815                 return false;
 816             }
 817 
 818             $result = $adapter->refreshManifestCache();
 819 
 820             if ($result !== false)
 821             {
 822                 return true;
 823             }
 824             else
 825             {
 826                 return false;
 827             }
 828         }
 829 
 830         $this->abort(JText::_('JLIB_INSTALLER_ABORT_REFRESH_MANIFEST_CACHE_VALID'));
 831 
 832         return false;
 833     }
 834 
 835     // Utility functions
 836 
 837     /**
 838      * Prepare for installation: this method sets the installation directory, finds
 839      * and checks the installation file and verifies the installation type.
 840      *
 841      * @param   string   $route          The install route being followed
 842      * @param   boolean  $returnAdapter  Flag to return the instantiated adapter
 843      *
 844      * @return  boolean|JInstallerAdapter  JInstallerAdapter object if explicitly requested otherwise boolean
 845      *
 846      * @since   3.1
 847      */
 848     public function setupInstall($route = 'install', $returnAdapter = false)
 849     {
 850         // We need to find the installation manifest file
 851         if (!$this->findManifest())
 852         {
 853             return false;
 854         }
 855 
 856         // Load the adapter(s) for the install manifest
 857         $type   = (string) $this->manifest->attributes()->type;
 858         $params = array('route' => $route, 'manifest' => $this->getManifest());
 859 
 860         // Load the adapter
 861         $adapter = $this->getAdapter($type, $params);
 862 
 863         if ($returnAdapter)
 864         {
 865             return $adapter;
 866         }
 867 
 868         return true;
 869     }
 870 
 871     /**
 872      * Backward compatible method to parse through a queries element of the
 873      * installation manifest file and take appropriate action.
 874      *
 875      * @param   SimpleXMLElement  $element  The XML node to process
 876      *
 877      * @return  mixed  Number of queries processed or False on error
 878      *
 879      * @since   3.1
 880      */
 881     public function parseQueries(SimpleXMLElement $element)
 882     {
 883         // Get the database connector object
 884         $db = & $this->_db;
 885 
 886         if (!$element || !count($element->children()))
 887         {
 888             // Either the tag does not exist or has no children therefore we return zero files processed.
 889             return 0;
 890         }
 891 
 892         // Get the array of query nodes to process
 893         $queries = $element->children();
 894 
 895         if (count($queries) === 0)
 896         {
 897             // No queries to process
 898             return 0;
 899         }
 900 
 901         $update_count = 0;
 902 
 903         // Process each query in the $queries array (children of $tagName).
 904         foreach ($queries as $query)
 905         {
 906             $db->setQuery($db->convertUtf8mb4QueryToUtf8($query));
 907 
 908             try
 909             {
 910                 $db->execute();
 911             }
 912             catch (JDatabaseExceptionExecuting $e)
 913             {
 914                 JLog::add(JText::sprintf('JLIB_INSTALLER_ERROR_SQL_ERROR', $e->getMessage()), JLog::WARNING, 'jerror');
 915 
 916                 return false;
 917             }
 918 
 919             $update_count++;
 920         }
 921 
 922         return $update_count;
 923     }
 924 
 925     /**
 926      * Method to extract the name of a discreet installation sql file from the installation manifest file.
 927      *
 928      * @param   object  $element  The XML node to process
 929      *
 930      * @return  mixed  Number of queries processed or False on error
 931      *
 932      * @since   3.1
 933      */
 934     public function parseSQLFiles($element)
 935     {
 936         if (!$element || !count($element->children()))
 937         {
 938             // The tag does not exist.
 939             return 0;
 940         }
 941 
 942         $db = & $this->_db;
 943 
 944         // TODO - At 4.0 we can change this to use `getServerType()` since SQL Server will not be supported
 945         $dbDriver = strtolower($db->name);
 946 
 947         if ($db->getServerType() === 'mysql')
 948         {
 949             $dbDriver = 'mysql';
 950         }
 951 
 952         $update_count = 0;
 953 
 954         // Get the name of the sql file to process
 955         foreach ($element->children() as $file)
 956         {
 957             $fCharset = strtolower($file->attributes()->charset) === 'utf8' ? 'utf8' : '';
 958             $fDriver  = strtolower($file->attributes()->driver);
 959 
 960             if ($fDriver === 'mysqli' || $fDriver === 'pdomysql')
 961             {
 962                 $fDriver = 'mysql';
 963             }
 964 
 965             if ($fCharset === 'utf8' && $fDriver == $dbDriver)
 966             {
 967                 $sqlfile = $this->getPath('extension_root') . '/' . trim($file);
 968 
 969                 // Check that sql files exists before reading. Otherwise raise error for rollback
 970                 if (!file_exists($sqlfile))
 971                 {
 972                     JLog::add(JText::sprintf('JLIB_INSTALLER_ERROR_SQL_FILENOTFOUND', $sqlfile), JLog::WARNING, 'jerror');
 973 
 974                     return false;
 975                 }
 976 
 977                 $buffer = file_get_contents($sqlfile);
 978 
 979                 // Graceful exit and rollback if read not successful
 980                 if ($buffer === false)
 981                 {
 982                     JLog::add(JText::_('JLIB_INSTALLER_ERROR_SQL_READBUFFER'), JLog::WARNING, 'jerror');
 983 
 984                     return false;
 985                 }
 986 
 987                 // Create an array of queries from the sql file
 988                 $queries = JDatabaseDriver::splitSql($buffer);
 989 
 990                 if (count($queries) === 0)
 991                 {
 992                     // No queries to process
 993                     return 0;
 994                 }
 995 
 996                 // Process each query in the $queries array (split out of sql file).
 997                 foreach ($queries as $query)
 998                 {
 999                     $db->setQuery($db->convertUtf8mb4QueryToUtf8($query));
1000 
1001                     try
1002                     {
1003                         $db->execute();
1004                     }
1005                     catch (JDatabaseExceptionExecuting $e)
1006                     {
1007                         JLog::add(JText::sprintf('JLIB_INSTALLER_ERROR_SQL_ERROR', $e->getMessage()), JLog::WARNING, 'jerror');
1008 
1009                         return false;
1010                     }
1011 
1012                     $update_count++;
1013                 }
1014             }
1015         }
1016 
1017         return $update_count;
1018     }
1019 
1020     /**
1021      * Set the schema version for an extension by looking at its latest update
1022      *
1023      * @param   SimpleXMLElement  $schema  Schema Tag
1024      * @param   integer           $eid     Extension ID
1025      *
1026      * @return  void
1027      *
1028      * @since   3.1
1029      */
1030     public function setSchemaVersion(SimpleXMLElement $schema, $eid)
1031     {
1032         if ($eid && $schema)
1033         {
1034             $db = JFactory::getDbo();
1035             $schemapaths = $schema->children();
1036 
1037             if (!$schemapaths)
1038             {
1039                 return;
1040             }
1041 
1042             if (count($schemapaths))
1043             {
1044                 $dbDriver = strtolower($db->name);
1045 
1046                 if ($db->getServerType() === 'mysql')
1047                 {
1048                     $dbDriver = 'mysql';
1049                 }
1050 
1051                 $schemapath = '';
1052 
1053                 foreach ($schemapaths as $entry)
1054                 {
1055                     $attrs = $entry->attributes();
1056 
1057                     if ($attrs['type'] == $dbDriver)
1058                     {
1059                         $schemapath = $entry;
1060                         break;
1061                     }
1062                 }
1063 
1064                 if ($schemapath !== '')
1065                 {
1066                     $files = str_replace('.sql', '', JFolder::files($this->getPath('extension_root') . '/' . $schemapath, '\.sql$'));
1067                     usort($files, 'version_compare');
1068 
1069                     // Update the database
1070                     $query = $db->getQuery(true)
1071                         ->delete('#__schemas')
1072                         ->where('extension_id = ' . $eid);
1073                     $db->setQuery($query);
1074 
1075                     if ($db->execute())
1076                     {
1077                         $query->clear()
1078                             ->insert($db->quoteName('#__schemas'))
1079                             ->columns(array($db->quoteName('extension_id'), $db->quoteName('version_id')))
1080                             ->values($eid . ', ' . $db->quote(end($files)));
1081                         $db->setQuery($query);
1082                         $db->execute();
1083                     }
1084                 }
1085             }
1086         }
1087     }
1088 
1089     /**
1090      * Method to process the updates for an item
1091      *
1092      * @param   SimpleXMLElement  $schema  The XML node to process
1093      * @param   integer           $eid     Extension Identifier
1094      *
1095      * @return  boolean           Result of the operations
1096      *
1097      * @since   3.1
1098      */
1099     public function parseSchemaUpdates(SimpleXMLElement $schema, $eid)
1100     {
1101         $update_count = 0;
1102 
1103         // Ensure we have an XML element and a valid extension id
1104         if ($eid && $schema)
1105         {
1106             $db = JFactory::getDbo();
1107             $schemapaths = $schema->children();
1108 
1109             if (count($schemapaths))
1110             {
1111                 // TODO - At 4.0 we can change this to use `getServerType()` since SQL Server will not be supported
1112                 $dbDriver = strtolower($db->name);
1113 
1114                 if ($db->getServerType() === 'mysql')
1115                 {
1116                     $dbDriver = 'mysql';
1117                 }
1118 
1119                 $schemapath = '';
1120 
1121                 foreach ($schemapaths as $entry)
1122                 {
1123                     $attrs = $entry->attributes();
1124 
1125                     // Assuming that the type is a mandatory attribute but if it is not mandatory then there should be a discussion for it.
1126                     $uDriver = strtolower($attrs['type']);
1127 
1128                     if ($uDriver === 'mysqli' || $uDriver === 'pdomysql')
1129                     {
1130                         $uDriver = 'mysql';
1131                     }
1132 
1133                     if ($uDriver == $dbDriver)
1134                     {
1135                         $schemapath = $entry;
1136                         break;
1137                     }
1138                 }
1139 
1140                 if ($schemapath !== '')
1141                 {
1142                     $files = str_replace('.sql', '', JFolder::files($this->getPath('extension_root') . '/' . $schemapath, '\.sql$'));
1143                     usort($files, 'version_compare');
1144 
1145                     if (!count($files))
1146                     {
1147                         return $update_count;
1148                     }
1149 
1150                     $query = $db->getQuery(true)
1151                         ->select('version_id')
1152                         ->from('#__schemas')
1153                         ->where('extension_id = ' . $eid);
1154                     $db->setQuery($query);
1155                     $version = $db->loadResult();
1156 
1157                     // No version - use initial version.
1158                     if (!$version)
1159                     {
1160                         $version = '0.0.0';
1161                     }
1162 
1163                     foreach ($files as $file)
1164                     {
1165                         if (version_compare($file, $version) > 0)
1166                         {
1167                             $buffer = file_get_contents($this->getPath('extension_root') . '/' . $schemapath . '/' . $file . '.sql');
1168 
1169                             // Graceful exit and rollback if read not successful
1170                             if ($buffer === false)
1171                             {
1172                                 JLog::add(JText::sprintf('JLIB_INSTALLER_ERROR_SQL_READBUFFER'), JLog::WARNING, 'jerror');
1173 
1174                                 return false;
1175                             }
1176 
1177                             // Create an array of queries from the sql file
1178                             $queries = JDatabaseDriver::splitSql($buffer);
1179 
1180                             if (count($queries) === 0)
1181                             {
1182                                 // No queries to process
1183                                 continue;
1184                             }
1185 
1186                             // Process each query in the $queries array (split out of sql file).
1187                             foreach ($queries as $query)
1188                             {
1189                                 $db->setQuery($db->convertUtf8mb4QueryToUtf8($query));
1190 
1191                                 try
1192                                 {
1193                                     $db->execute();
1194                                 }
1195                                 catch (JDatabaseExceptionExecuting $e)
1196                                 {
1197                                     JLog::add(JText::sprintf('JLIB_INSTALLER_ERROR_SQL_ERROR', $e->getMessage()), JLog::WARNING, 'jerror');
1198 
1199                                     return false;
1200                                 }
1201 
1202                                 $queryString = (string) $query;
1203                                 $queryString = str_replace(array("\r", "\n"), array('', ' '), substr($queryString, 0, 80));
1204                                 JLog::add(JText::sprintf('JLIB_INSTALLER_UPDATE_LOG_QUERY', $file, $queryString), JLog::INFO, 'Update');
1205 
1206                                 $update_count++;
1207                             }
1208                         }
1209                     }
1210 
1211                     // Update the database
1212                     $query = $db->getQuery(true)
1213                         ->delete('#__schemas')
1214                         ->where('extension_id = ' . $eid);
1215                     $db->setQuery($query);
1216 
1217                     if ($db->execute())
1218                     {
1219                         $query->clear()
1220                             ->insert($db->quoteName('#__schemas'))
1221                             ->columns(array($db->quoteName('extension_id'), $db->quoteName('version_id')))
1222                             ->values($eid . ', ' . $db->quote(end($files)));
1223                         $db->setQuery($query);
1224                         $db->execute();
1225                     }
1226                 }
1227             }
1228         }
1229 
1230         return $update_count;
1231     }
1232 
1233     /**
1234      * Method to parse through a files element of the installation manifest and take appropriate
1235      * action.
1236      *
1237      * @param   SimpleXMLElement  $element   The XML node to process
1238      * @param   integer           $cid       Application ID of application to install to
1239      * @param   array             $oldFiles  List of old files (SimpleXMLElement's)
1240      * @param   array             $oldMD5    List of old MD5 sums (indexed by filename with value as MD5)
1241      *
1242      * @return  boolean      True on success
1243      *
1244      * @since   3.1
1245      */
1246     public function parseFiles(SimpleXMLElement $element, $cid = 0, $oldFiles = null, $oldMD5 = null)
1247     {
1248         // Get the array of file nodes to process; we checked whether this had children above.
1249         if (!$element || !count($element->children()))
1250         {
1251             // Either the tag does not exist or has no children (hence no files to process) therefore we return zero files processed.
1252             return 0;
1253         }
1254 
1255         $copyfiles = array();
1256 
1257         // Get the client info
1258         $client = JApplicationHelper::getClientInfo($cid);
1259 
1260         /*
1261          * Here we set the folder we are going to remove the files from.
1262          */
1263         if ($client)
1264         {
1265             $pathname = 'extension_' . $client->name;
1266             $destination = $this->getPath($pathname);
1267         }
1268         else
1269         {
1270             $pathname = 'extension_root';
1271             $destination = $this->getPath($pathname);
1272         }
1273 
1274         /*
1275          * Here we set the folder we are going to copy the files from.
1276          *
1277          * Does the element have a folder attribute?
1278          *
1279          * If so this indicates that the files are in a subdirectory of the source
1280          * folder and we should append the folder attribute to the source path when
1281          * copying files.
1282          */
1283 
1284         $folder = (string) $element->attributes()->folder;
1285 
1286         if ($folder && file_exists($this->getPath('source') . '/' . $folder))
1287         {
1288             $source = $this->getPath('source') . '/' . $folder;
1289         }
1290         else
1291         {
1292             $source = $this->getPath('source');
1293         }
1294 
1295         // Work out what files have been deleted
1296         if ($oldFiles && ($oldFiles instanceof SimpleXMLElement))
1297         {
1298             $oldEntries = $oldFiles->children();
1299 
1300             if (count($oldEntries))
1301             {
1302                 $deletions = $this->findDeletedFiles($oldEntries, $element->children());
1303 
1304                 foreach ($deletions['folders'] as $deleted_folder)
1305                 {
1306                     JFolder::delete($destination . '/' . $deleted_folder);
1307                 }
1308 
1309                 foreach ($deletions['files'] as $deleted_file)
1310                 {
1311                     JFile::delete($destination . '/' . $deleted_file);
1312                 }
1313             }
1314         }
1315 
1316         $path = array();
1317 
1318         // Copy the MD5SUMS file if it exists
1319         if (file_exists($source . '/MD5SUMS'))
1320         {
1321             $path['src'] = $source . '/MD5SUMS';
1322             $path['dest'] = $destination . '/MD5SUMS';
1323             $path['type'] = 'file';
1324             $copyfiles[] = $path;
1325         }
1326 
1327         // Process each file in the $files array (children of $tagName).
1328         foreach ($element->children() as $file)
1329         {
1330             $path['src'] = $source . '/' . $file;
1331             $path['dest'] = $destination . '/' . $file;
1332 
1333             // Is this path a file or folder?
1334             $path['type'] = $file->getName() === 'folder' ? 'folder' : 'file';
1335 
1336             /*
1337              * Before we can add a file to the copyfiles array we need to ensure
1338              * that the folder we are copying our file to exits and if it doesn't,
1339              * we need to create it.
1340              */
1341 
1342             if (basename($path['dest']) !== $path['dest'])
1343             {
1344                 $newdir = dirname($path['dest']);
1345 
1346                 if (!JFolder::create($newdir))
1347                 {
1348                     JLog::add(JText::sprintf('JLIB_INSTALLER_ERROR_CREATE_DIRECTORY', $newdir), JLog::WARNING, 'jerror');
1349 
1350                     return false;
1351                 }
1352             }
1353 
1354             // Add the file to the copyfiles array
1355             $copyfiles[] = $path;
1356         }
1357 
1358         return $this->copyFiles($copyfiles);
1359     }
1360 
1361     /**
1362      * Method to parse through a languages element of the installation manifest and take appropriate
1363      * action.
1364      *
1365      * @param   SimpleXMLElement  $element  The XML node to process
1366      * @param   integer           $cid      Application ID of application to install to
1367      *
1368      * @return  boolean  True on success
1369      *
1370      * @since   3.1
1371      */
1372     public function parseLanguages(SimpleXMLElement $element, $cid = 0)
1373     {
1374         // TODO: work out why the below line triggers 'node no longer exists' errors with files
1375         if (!$element || !count($element->children()))
1376         {
1377             // Either the tag does not exist or has no children therefore we return zero files processed.
1378             return 0;
1379         }
1380 
1381         $copyfiles = array();
1382 
1383         // Get the client info
1384         $client = JApplicationHelper::getClientInfo($cid);
1385 
1386         // Here we set the folder we are going to copy the files to.
1387         // 'languages' Files are copied to JPATH_BASE/language/ folder
1388 
1389         $destination = $client->path . '/language';
1390 
1391         /*
1392          * Here we set the folder we are going to copy the files from.
1393          *
1394          * Does the element have a folder attribute?
1395          *
1396          * If so this indicates that the files are in a subdirectory of the source
1397          * folder and we should append the folder attribute to the source path when
1398          * copying files.
1399          */
1400 
1401         $folder = (string) $element->attributes()->folder;
1402 
1403         if ($folder && file_exists($this->getPath('source') . '/' . $folder))
1404         {
1405             $source = $this->getPath('source') . '/' . $folder;
1406         }
1407         else
1408         {
1409             $source = $this->getPath('source');
1410         }
1411 
1412         // Process each file in the $files array (children of $tagName).
1413         foreach ($element->children() as $file)
1414         {
1415             /*
1416              * Language files go in a subfolder based on the language code, ie.
1417              * <language tag="en-US">en-US.mycomponent.ini</language>
1418              * would go in the en-US subdirectory of the language folder.
1419              */
1420 
1421             // We will only install language files where a core language pack
1422             // already exists.
1423 
1424             if ((string) $file->attributes()->tag !== '')
1425             {
1426                 $path['src'] = $source . '/' . $file;
1427 
1428                 if ((string) $file->attributes()->client !== '')
1429                 {
1430                     // Override the client
1431                     $langclient = JApplicationHelper::getClientInfo((string) $file->attributes()->client, true);
1432                     $path['dest'] = $langclient->path . '/language/' . $file->attributes()->tag . '/' . basename((string) $file);
1433                 }
1434                 else
1435                 {
1436                     // Use the default client
1437                     $path['dest'] = $destination . '/' . $file->attributes()->tag . '/' . basename((string) $file);
1438                 }
1439 
1440                 // If the language folder is not present, then the core pack hasn't been installed... ignore
1441                 if (!JFolder::exists(dirname($path['dest'])))
1442                 {
1443                     continue;
1444                 }
1445             }
1446             else
1447             {
1448                 $path['src'] = $source . '/' . $file;
1449                 $path['dest'] = $destination . '/' . $file;
1450             }
1451 
1452             /*
1453              * Before we can add a file to the copyfiles array we need to ensure
1454              * that the folder we are copying our file to exits and if it doesn't,
1455              * we need to create it.
1456              */
1457 
1458             if (basename($path['dest']) !== $path['dest'])
1459             {
1460                 $newdir = dirname($path['dest']);
1461 
1462                 if (!JFolder::create($newdir))
1463                 {
1464                     JLog::add(JText::sprintf('JLIB_INSTALLER_ERROR_CREATE_DIRECTORY', $newdir), JLog::WARNING, 'jerror');
1465 
1466                     return false;
1467                 }
1468             }
1469 
1470             // Add the file to the copyfiles array
1471             $copyfiles[] = $path;
1472         }
1473 
1474         return $this->copyFiles($copyfiles);
1475     }
1476 
1477     /**
1478      * Method to parse through a media element of the installation manifest and take appropriate
1479      * action.
1480      *
1481      * @param   SimpleXMLElement  $element  The XML node to process
1482      * @param   integer           $cid      Application ID of application to install to
1483      *
1484      * @return  boolean     True on success
1485      *
1486      * @since   3.1
1487      */
1488     public function parseMedia(SimpleXMLElement $element, $cid = 0)
1489     {
1490         if (!$element || !count($element->children()))
1491         {
1492             // Either the tag does not exist or has no children therefore we return zero files processed.
1493             return 0;
1494         }
1495 
1496         $copyfiles = array();
1497 
1498         // Here we set the folder we are going to copy the files to.
1499         // Default 'media' Files are copied to the JPATH_BASE/media folder
1500 
1501         $folder = ((string) $element->attributes()->destination) ? '/' . $element->attributes()->destination : null;
1502         $destination = JPath::clean(JPATH_ROOT . '/media' . $folder);
1503 
1504         // Here we set the folder we are going to copy the files from.
1505 
1506         /*
1507          * Does the element have a folder attribute?
1508          * If so this indicates that the files are in a subdirectory of the source
1509          * folder and we should append the folder attribute to the source path when
1510          * copying files.
1511          */
1512 
1513         $folder = (string) $element->attributes()->folder;
1514 
1515         if ($folder && file_exists($this->getPath('source') . '/' . $folder))
1516         {
1517             $source = $this->getPath('source') . '/' . $folder;
1518         }
1519         else
1520         {
1521             $source = $this->getPath('source');
1522         }
1523 
1524         // Process each file in the $files array (children of $tagName).
1525         foreach ($element->children() as $file)
1526         {
1527             $path['src'] = $source . '/' . $file;
1528             $path['dest'] = $destination . '/' . $file;
1529 
1530             // Is this path a file or folder?
1531             $path['type'] = $file->getName() === 'folder' ? 'folder' : 'file';
1532 
1533             /*
1534              * Before we can add a file to the copyfiles array we need to ensure
1535              * that the folder we are copying our file to exits and if it doesn't,
1536              * we need to create it.
1537              */
1538 
1539             if (basename($path['dest']) !== $path['dest'])
1540             {
1541                 $newdir = dirname($path['dest']);
1542 
1543                 if (!JFolder::create($newdir))
1544                 {
1545                     JLog::add(JText::sprintf('JLIB_INSTALLER_ERROR_CREATE_DIRECTORY', $newdir), JLog::WARNING, 'jerror');
1546 
1547                     return false;
1548                 }
1549             }
1550 
1551             // Add the file to the copyfiles array
1552             $copyfiles[] = $path;
1553         }
1554 
1555         return $this->copyFiles($copyfiles);
1556     }
1557 
1558     /**
1559      * Method to parse the parameters of an extension, build the JSON string for its default parameters, and return the JSON string.
1560      *
1561      * @return  string  JSON string of parameter values
1562      *
1563      * @since   3.1
1564      * @note    This method must always return a JSON compliant string
1565      */
1566     public function getParams()
1567     {
1568         // Validate that we have a fieldset to use
1569         if (!isset($this->manifest->config->fields->fieldset))
1570         {
1571             return '{}';
1572         }
1573 
1574         // Getting the fieldset tags
1575         $fieldsets = $this->manifest->config->fields->fieldset;
1576 
1577         // Creating the data collection variable:
1578         $ini = array();
1579 
1580         // Iterating through the fieldsets:
1581         foreach ($fieldsets as $fieldset)
1582         {
1583             if (!count($fieldset->children()))
1584             {
1585                 // Either the tag does not exist or has no children therefore we return zero files processed.
1586                 return '{}';
1587             }
1588 
1589             // Iterating through the fields and collecting the name/default values:
1590             foreach ($fieldset as $field)
1591             {
1592                 // Check against the null value since otherwise default values like "0"
1593                 // cause entire parameters to be skipped.
1594 
1595                 if (($name = $field->attributes()->name) === null)
1596                 {
1597                     continue;
1598                 }
1599 
1600                 if (($value = $field->attributes()->default) === null)
1601                 {
1602                     continue;
1603                 }
1604 
1605                 $ini[(string) $name] = (string) $value;
1606             }
1607         }
1608 
1609         return json_encode($ini);
1610     }
1611 
1612     /**
1613      * Copyfiles
1614      *
1615      * Copy files from source directory to the target directory
1616      *
1617      * @param   array    $files      Array with filenames
1618      * @param   boolean  $overwrite  True if existing files can be replaced
1619      *
1620      * @return  boolean  True on success
1621      *
1622      * @since   3.1
1623      */
1624     public function copyFiles($files, $overwrite = null)
1625     {
1626         /*
1627          * To allow for manual override on the overwriting flag, we check to see if
1628          * the $overwrite flag was set and is a boolean value.  If not, use the object
1629          * allowOverwrite flag.
1630          */
1631 
1632         if ($overwrite === null || !is_bool($overwrite))
1633         {
1634             $overwrite = $this->overwrite;
1635         }
1636 
1637         /*
1638          * $files must be an array of filenames.  Verify that it is an array with
1639          * at least one file to copy.
1640          */
1641         if (is_array($files) && count($files) > 0)
1642         {
1643             foreach ($files as $file)
1644             {
1645                 // Get the source and destination paths
1646                 $filesource = JPath::clean($file['src']);
1647                 $filedest = JPath::clean($file['dest']);
1648                 $filetype = array_key_exists('type', $file) ? $file['type'] : 'file';
1649 
1650                 if (!file_exists($filesource))
1651                 {
1652                     /*
1653                      * The source file does not exist.  Nothing to copy so set an error
1654                      * and return false.
1655                      */
1656                     JLog::add(JText::sprintf('JLIB_INSTALLER_ERROR_NO_FILE', $filesource), JLog::WARNING, 'jerror');
1657 
1658                     return false;
1659                 }
1660                 elseif (($exists = file_exists($filedest)) && !$overwrite)
1661                 {
1662                     // It's okay if the manifest already exists
1663                     if ($this->getPath('manifest') === $filesource)
1664                     {
1665                         continue;
1666                     }
1667 
1668                     // The destination file already exists and the overwrite flag is false.
1669                     // Set an error and return false.
1670                     JLog::add(JText::sprintf('JLIB_INSTALLER_ERROR_FILE_EXISTS', $filedest), JLog::WARNING, 'jerror');
1671 
1672                     return false;
1673                 }
1674                 else
1675                 {
1676                     // Copy the folder or file to the new location.
1677                     if ($filetype === 'folder')
1678                     {
1679                         if (!JFolder::copy($filesource, $filedest, null, $overwrite))
1680                         {
1681                             JLog::add(JText::sprintf('JLIB_INSTALLER_ERROR_FAIL_COPY_FOLDER', $filesource, $filedest), JLog::WARNING, 'jerror');
1682 
1683                             return false;
1684                         }
1685 
1686                         $step = array('type' => 'folder', 'path' => $filedest);
1687                     }
1688                     else
1689                     {
1690                         if (!JFile::copy($filesource, $filedest, null))
1691                         {
1692                             JLog::add(JText::sprintf('JLIB_INSTALLER_ERROR_FAIL_COPY_FILE', $filesource, $filedest), JLog::WARNING, 'jerror');
1693 
1694                             // In 3.2, TinyMCE language handling changed.  Display a special notice in case an older language pack is installed.
1695                             if (strpos($filedest, 'media/editors/tinymce/jscripts/tiny_mce/langs'))
1696                             {
1697                                 JLog::add(JText::_('JLIB_INSTALLER_NOT_ERROR'), JLog::WARNING, 'jerror');
1698                             }
1699 
1700                             return false;
1701                         }
1702 
1703                         $step = array('type' => 'file', 'path' => $filedest);
1704                     }
1705 
1706                     /*
1707                      * Since we copied a file/folder, we want to add it to the installation step stack so that
1708                      * in case we have to roll back the installation we can remove the files copied.
1709                      */
1710                     if (!$exists)
1711                     {
1712                         $this->stepStack[] = $step;
1713                     }
1714                 }
1715             }
1716         }
1717         else
1718         {
1719             // The $files variable was either not an array or an empty array
1720             return false;
1721         }
1722 
1723         return count($files);
1724     }
1725 
1726     /**
1727      * Method to parse through a files element of the installation manifest and remove
1728      * the files that were installed
1729      *
1730      * @param   object   $element  The XML node to process
1731      * @param   integer  $cid      Application ID of application to remove from
1732      *
1733      * @return  boolean  True on success
1734      *
1735      * @since   3.1
1736      */
1737     public function removeFiles($element, $cid = 0)
1738     {
1739         if (!$element || !count($element->children()))
1740         {
1741             // Either the tag does not exist or has no children therefore we return zero files processed.
1742             return true;
1743         }
1744 
1745         $retval = true;
1746 
1747         // Get the client info if we're using a specific client
1748         if ($cid > -1)
1749         {
1750             $client = JApplicationHelper::getClientInfo($cid);
1751         }
1752         else
1753         {
1754             $client = null;
1755         }
1756 
1757         // Get the array of file nodes to process
1758         $files = $element->children();
1759 
1760         if (count($files) === 0)
1761         {
1762             // No files to process
1763             return true;
1764         }
1765 
1766         $folder = '';
1767 
1768         /*
1769          * Here we set the folder we are going to remove the files from.  There are a few
1770          * special cases that need to be considered for certain reserved tags.
1771          */
1772         switch ($element->getName())
1773         {
1774             case 'media':
1775                 if ((string) $element->attributes()->destination)
1776                 {
1777                     $folder = (string) $element->attributes()->destination;
1778                 }
1779                 else
1780                 {
1781                     $folder = '';
1782                 }
1783 
1784                 $source = $client->path . '/media/' . $folder;
1785 
1786                 break;
1787 
1788             case 'languages':
1789                 $lang_client = (string) $element->attributes()->client;
1790 
1791                 if ($lang_client)
1792                 {
1793                     $client = JApplicationHelper::getClientInfo($lang_client, true);
1794                     $source = $client->path . '/language';
1795                 }
1796                 else
1797                 {
1798                     if ($client)
1799                     {
1800                         $source = $client->path . '/language';
1801                     }
1802                     else
1803                     {
1804                         $source = '';
1805                     }
1806                 }
1807 
1808                 break;
1809 
1810             default:
1811                 if ($client)
1812                 {
1813                     $pathname = 'extension_' . $client->name;
1814                     $source = $this->getPath($pathname);
1815                 }
1816                 else
1817                 {
1818                     $pathname = 'extension_root';
1819                     $source = $this->getPath($pathname);
1820                 }
1821 
1822                 break;
1823         }
1824 
1825         // Process each file in the $files array (children of $tagName).
1826         foreach ($files as $file)
1827         {
1828             /*
1829              * If the file is a language, we must handle it differently.  Language files
1830              * go in a subdirectory based on the language code, ie.
1831              * <language tag="en_US">en_US.mycomponent.ini</language>
1832              * would go in the en_US subdirectory of the languages directory.
1833              */
1834 
1835             if ($file->getName() === 'language' && (string) $file->attributes()->tag !== '')
1836             {
1837                 if ($source)
1838                 {
1839                     $path = $source . '/' . $file->attributes()->tag . '/' . basename((string) $file);
1840                 }
1841                 else
1842                 {
1843                     $target_client = JApplicationHelper::getClientInfo((string) $file->attributes()->client, true);
1844                     $path = $target_client->path . '/language/' . $file->attributes()->tag . '/' . basename((string) $file);
1845                 }
1846 
1847                 // If the language folder is not present, then the core pack hasn't been installed... ignore
1848                 if (!JFolder::exists(dirname($path)))
1849                 {
1850                     continue;
1851                 }
1852             }
1853             else
1854             {
1855                 $path = $source . '/' . $file;
1856             }
1857 
1858             // Actually delete the files/folders
1859 
1860             if (is_dir($path))
1861             {
1862                 $val = JFolder::delete($path);
1863             }
1864             else
1865             {
1866                 $val = JFile::delete($path);
1867             }
1868 
1869             if ($val === false)
1870             {
1871                 JLog::add('Failed to delete ' . $path, JLog::WARNING, 'jerror');
1872                 $retval = false;
1873             }
1874         }
1875 
1876         if (!empty($folder))
1877         {
1878             JFolder::delete($source);
1879         }
1880 
1881         return $retval;
1882     }
1883 
1884     /**
1885      * Copies the installation manifest file to the extension folder in the given client
1886      *
1887      * @param   integer  $cid  Where to copy the installfile [optional: defaults to 1 (admin)]
1888      *
1889      * @return  boolean  True on success, False on error
1890      *
1891      * @since   3.1
1892      */
1893     public function copyManifest($cid = 1)
1894     {
1895         // Get the client info
1896         $client = JApplicationHelper::getClientInfo($cid);
1897 
1898         $path['src'] = $this->getPath('manifest');
1899 
1900         if ($client)
1901         {
1902             $pathname = 'extension_' . $client->name;
1903             $path['dest'] = $this->getPath($pathname) . '/' . basename($this->getPath('manifest'));
1904         }
1905         else
1906         {
1907             $pathname = 'extension_root';
1908             $path['dest'] = $this->getPath($pathname) . '/' . basename($this->getPath('manifest'));
1909         }
1910 
1911         return $this->copyFiles(array($path), true);
1912     }
1913 
1914     /**
1915      * Tries to find the package manifest file
1916      *
1917      * @return  boolean  True on success, False on error
1918      *
1919      * @since   3.1
1920      */
1921     public function findManifest()
1922     {
1923         // Do nothing if folder does not exist for some reason
1924         if (!JFolder::exists($this->getPath('source')))
1925         {
1926             return false;
1927         }
1928 
1929         // Main folder manifests (higher priority)
1930         $parentXmlfiles = JFolder::files($this->getPath('source'), '.xml$', false, true);
1931 
1932         // Search for children manifests (lower priority)
1933         $allXmlFiles    = JFolder::files($this->getPath('source'), '.xml$', 1, true);
1934 
1935         // Create an unique array of files ordered by priority
1936         $xmlfiles = array_unique(array_merge($parentXmlfiles, $allXmlFiles));
1937 
1938         // If at least one XML file exists
1939         if (!empty($xmlfiles))
1940         {
1941             foreach ($xmlfiles as $file)
1942             {
1943                 // Is it a valid Joomla installation manifest file?
1944                 $manifest = $this->isManifest($file);
1945 
1946                 if ($manifest !== null)
1947                 {
1948                     // If the root method attribute is set to upgrade, allow file overwrite
1949                     if ((string) $manifest->attributes()->method === 'upgrade')
1950                     {
1951                         $this->upgrade = true;
1952                         $this->overwrite = true;
1953                     }
1954 
1955                     // If the overwrite option is set, allow file overwriting
1956                     if ((string) $manifest->attributes()->overwrite === 'true')
1957                     {
1958                         $this->overwrite = true;
1959                     }
1960 
1961                     // Set the manifest object and path
1962                     $this->manifest = $manifest;
1963                     $this->setPath('manifest', $file);
1964 
1965                     // Set the installation source path to that of the manifest file
1966                     $this->setPath('source', dirname($file));
1967 
1968                     return true;
1969                 }
1970             }
1971 
1972             // None of the XML files found were valid install files
1973             JLog::add(JText::_('JLIB_INSTALLER_ERROR_NOTFINDJOOMLAXMLSETUPFILE'), JLog::WARNING, 'jerror');
1974 
1975             return false;
1976         }
1977         else
1978         {
1979             // No XML files were found in the install folder
1980             JLog::add(JText::_('JLIB_INSTALLER_ERROR_NOTFINDXMLSETUPFILE'), JLog::WARNING, 'jerror');
1981 
1982             return false;
1983         }
1984     }
1985 
1986     /**
1987      * Is the XML file a valid Joomla installation manifest file.
1988      *
1989      * @param   string  $file  An xmlfile path to check
1990      *
1991      * @return  SimpleXMLElement|null  A SimpleXMLElement, or null if the file failed to parse
1992      *
1993      * @since   3.1
1994      */
1995     public function isManifest($file)
1996     {
1997         $xml = simplexml_load_file($file);
1998 
1999         // If we cannot load the XML file return null
2000         if (!$xml)
2001         {
2002             return;
2003         }
2004 
2005         // Check for a valid XML root tag.
2006         if ($xml->getName() !== 'extension')
2007         {
2008             return;
2009         }
2010 
2011         // Valid manifest file return the object
2012         return $xml;
2013     }
2014 
2015     /**
2016      * Generates a manifest cache
2017      *
2018      * @return string serialised manifest data
2019      *
2020      * @since   3.1
2021      */
2022     public function generateManifestCache()
2023     {
2024         return json_encode(self::parseXMLInstallFile($this->getPath('manifest')));
2025     }
2026 
2027     /**
2028      * Cleans up discovered extensions if they're being installed some other way
2029      *
2030      * @param   string   $type     The type of extension (component, etc)
2031      * @param   string   $element  Unique element identifier (e.g. com_content)
2032      * @param   string   $folder   The folder of the extension (plugins; e.g. system)
2033      * @param   integer  $client   The client application (administrator or site)
2034      *
2035      * @return  object    Result of query
2036      *
2037      * @since   3.1
2038      */
2039     public function cleanDiscoveredExtension($type, $element, $folder = '', $client = 0)
2040     {
2041         $db = JFactory::getDbo();
2042         $query = $db->getQuery(true)
2043             ->delete($db->quoteName('#__extensions'))
2044             ->where('type = ' . $db->quote($type))
2045             ->where('element = ' . $db->quote($element))
2046             ->where('folder = ' . $db->quote($folder))
2047             ->where('client_id = ' . (int) $client)
2048             ->where('state = -1');
2049         $db->setQuery($query);
2050 
2051         return $db->execute();
2052     }
2053 
2054     /**
2055      * Compares two "files" entries to find deleted files/folders
2056      *
2057      * @param   array  $old_files  An array of SimpleXMLElement objects that are the old files
2058      * @param   array  $new_files  An array of SimpleXMLElement objects that are the new files
2059      *
2060      * @return  array  An array with the delete files and folders in findDeletedFiles[files] and findDeletedFiles[folders] respectively
2061      *
2062      * @since   3.1
2063      */
2064     public function findDeletedFiles($old_files, $new_files)
2065     {
2066         // The magic find deleted files function!
2067         // The files that are new
2068         $files = array();
2069 
2070         // The folders that are new
2071         $folders = array();
2072 
2073         // The folders of the files that are new
2074         $containers = array();
2075 
2076         // A list of files to delete
2077         $files_deleted = array();
2078 
2079         // A list of folders to delete
2080         $folders_deleted = array();
2081 
2082         foreach ($new_files as $file)
2083         {
2084             switch ($file->getName())
2085             {
2086                 case 'folder':
2087                     // Add any folders to the list
2088                     $folders[] = (string) $file; // add any folders to the list
2089                     break;
2090 
2091                 case 'file':
2092                 default:
2093                     // Add any files to the list
2094                     $files[] = (string) $file;
2095 
2096                     // Now handle the folder part of the file to ensure we get any containers
2097                     // Break up the parts of the directory
2098                     $container_parts = explode('/', dirname((string) $file));
2099 
2100                     // Make sure this is clean and empty
2101                     $container = '';
2102 
2103                     foreach ($container_parts as $part)
2104                     {
2105                         // Iterate through each part
2106                         // Add a slash if its not empty
2107                         if (!empty($container))
2108                         {
2109                             $container .= '/';
2110                         }
2111 
2112                         // Aappend the folder part
2113                         $container .= $part;
2114 
2115                         if (!in_array($container, $containers))
2116                         {
2117                             // Add the container if it doesn't already exist
2118                             $containers[] = $container;
2119                         }
2120                     }
2121                     break;
2122             }
2123         }
2124 
2125         foreach ($old_files as $file)
2126         {
2127             switch ($file->getName())
2128             {
2129                 case 'folder':
2130                     if (!in_array((string) $file, $folders))
2131                     {
2132                         // See whether the folder exists in the new list
2133                         if (!in_array((string) $file, $containers))
2134                         {
2135                             // Check if the folder exists as a container in the new list
2136                             // If it's not in the new list or a container then delete it
2137                             $folders_deleted[] = (string) $file;
2138                         }
2139                     }
2140                     break;
2141 
2142                 case 'file':
2143                 default:
2144                     if (!in_array((string) $file, $files))
2145                     {
2146                         // Look if the file exists in the new list
2147                         if (!in_array(dirname((string) $file), $folders))
2148                         {
2149                             // Look if the file is now potentially in a folder
2150                             $files_deleted[] = (string) $file; // not in a folder, doesn't exist, wipe it out!
2151                         }
2152                     }
2153                     break;
2154             }
2155         }
2156 
2157         return array('files' => $files_deleted, 'folders' => $folders_deleted);
2158     }
2159 
2160     /**
2161      * Loads an MD5SUMS file into an associative array
2162      *
2163      * @param   string  $filename  Filename to load
2164      *
2165      * @return  array  Associative array with filenames as the index and the MD5 as the value
2166      *
2167      * @since   3.1
2168      */
2169     public function loadMD5Sum($filename)
2170     {
2171         if (!file_exists($filename))
2172         {
2173             // Bail if the file doesn't exist
2174             return false;
2175         }
2176 
2177         $data = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2178         $retval = array();
2179 
2180         foreach ($data as $row)
2181         {
2182             // Split up the data
2183             $results = explode('  ', $row);
2184 
2185             // Cull any potential prefix
2186             $results[1] = str_replace('./', '', $results[1]);
2187 
2188             // Throw into the array
2189             $retval[$results[1]] = $results[0];
2190         }
2191 
2192         return $retval;
2193     }
2194 
2195     /**
2196      * Parse a XML install manifest file.
2197      *
2198      * XML Root tag should be 'install' except for languages which use meta file.
2199      *
2200      * @param   string  $path  Full path to XML file.
2201      *
2202      * @return  array  XML metadata.
2203      *
2204      * @since   12.1
2205      */
2206     public static function parseXMLInstallFile($path)
2207     {
2208         // Check if xml file exists.
2209         if (!file_exists($path))
2210         {
2211             return false;
2212         }
2213 
2214         // Read the file to see if it's a valid component XML file
2215         $xml = simplexml_load_file($path);
2216 
2217         if (!$xml)
2218         {
2219             return false;
2220         }
2221 
2222         // Check for a valid XML root tag.
2223 
2224         // Extensions use 'extension' as the root tag.  Languages use 'metafile' instead
2225 
2226         $name = $xml->getName();
2227 
2228         if ($name !== 'extension' && $name !== 'metafile')
2229         {
2230             unset($xml);
2231 
2232             return false;
2233         }
2234 
2235         $data = array();
2236 
2237         $data['name'] = (string) $xml->name;
2238 
2239         // Check if we're a language. If so use metafile.
2240         $data['type'] = $xml->getName() === 'metafile' ? 'language' : (string) $xml->attributes()->type;
2241 
2242         $data['creationDate'] = ((string) $xml->creationDate) ?: JText::_('JLIB_UNKNOWN');
2243         $data['author'] = ((string) $xml->author) ?: JText::_('JLIB_UNKNOWN');
2244 
2245         $data['copyright'] = (string) $xml->copyright;
2246         $data['authorEmail'] = (string) $xml->authorEmail;
2247         $data['authorUrl'] = (string) $xml->authorUrl;
2248         $data['version'] = (string) $xml->version;
2249         $data['description'] = (string) $xml->description;
2250         $data['group'] = (string) $xml->group;
2251 
2252         if ($xml->files && count($xml->files->children()))
2253         {
2254             $filename = JFile::getName($path);
2255             $data['filename'] = JFile::stripExt($filename);
2256 
2257             foreach ($xml->files->children() as $oneFile)
2258             {
2259                 if ((string) $oneFile->attributes()->plugin)
2260                 {
2261                     $data['filename'] = (string) $oneFile->attributes()->plugin;
2262                     break;
2263                 }
2264             }
2265         }
2266 
2267         return $data;
2268     }
2269 
2270     /**
2271      * Fetches an adapter and adds it to the internal storage if an instance is not set
2272      * while also ensuring its a valid adapter name
2273      *
2274      * @param   string  $name     Name of adapter to return
2275      * @param   array   $options  Adapter options
2276      *
2277      * @return  JInstallerAdapter
2278      *
2279      * @since       3.4
2280      * @deprecated  4.0  The internal adapter cache will no longer be supported,
2281      *                   use loadAdapter() to fetch an adapter instance
2282      */
2283     public function getAdapter($name, $options = array())
2284     {
2285         $this->getAdapters($options);
2286 
2287         if (!$this->setAdapter($name, $this->_adapters[$name]))
2288         {
2289             return false;
2290         }
2291 
2292         return $this->_adapters[$name];
2293     }
2294 
2295     /**
2296      * Gets a list of available install adapters.
2297      *
2298      * @param   array  $options  An array of options to inject into the adapter
2299      * @param   array  $custom   Array of custom install adapters
2300      *
2301      * @return  array  An array of available install adapters.
2302      *
2303      * @since   3.4
2304      * @note    As of 4.0, this method will only return the names of available adapters and will not
2305      *          instantiate them and store to the $_adapters class var.
2306      */
2307     public function getAdapters($options = array(), array $custom = array())
2308     {
2309         $files = new DirectoryIterator($this->_basepath . '/' . $this->_adapterfolder);
2310 
2311         // Process the core adapters
2312         foreach ($files as $file)
2313         {
2314             $fileName = $file->getFilename();
2315 
2316             // Only load for php files.
2317             if (!$file->isFile() || $file->getExtension() !== 'php')
2318             {
2319                 continue;
2320             }
2321 
2322             // Derive the class name from the filename.
2323             $name  = str_ireplace('.php', '', trim($fileName));
2324             $class = $this->_classprefix . ucfirst($name);
2325 
2326             // Core adapters should autoload based on classname, keep this fallback just in case
2327             if (!class_exists($class))
2328             {
2329                 // Try to load the adapter object
2330                 JLoader::register($class, $this->_basepath . '/' . $this->_adapterfolder . '/' . $fileName);
2331 
2332                 if (!class_exists($class))
2333                 {
2334                     // Skip to next one
2335                     continue;
2336                 }
2337             }
2338 
2339             $this->_adapters[$name] = $this->loadAdapter($name, $options);
2340         }
2341 
2342         // Add any custom adapters if specified
2343         if (count($custom) >= 1)
2344         {
2345             foreach ($custom as $adapter)
2346             {
2347                 // Setup the class name
2348                 // TODO - Can we abstract this to not depend on the Joomla class namespace without PHP namespaces?
2349                 $class = $this->_classprefix . ucfirst(trim($adapter));
2350 
2351                 // If the class doesn't exist we have nothing left to do but look at the next type. We did our best.
2352                 if (!class_exists($class))
2353                 {
2354                     continue;
2355                 }
2356 
2357                 $this->_adapters[$name] = $this->loadAdapter($name, $options);
2358             }
2359         }
2360 
2361         return $this->_adapters;
2362     }
2363 
2364     /**
2365      * Method to load an adapter instance
2366      *
2367      * @param   string  $adapter  Adapter name
2368      * @param   array   $options  Adapter options
2369      *
2370      * @return  JInstallerAdapter
2371      *
2372      * @since   3.4
2373      * @throws  InvalidArgumentException
2374      */
2375     public function loadAdapter($adapter, $options = array())
2376     {
2377         $class = $this->_classprefix . ucfirst($adapter);
2378 
2379         if (!class_exists($class))
2380         {
2381             // @deprecated 4.0 - The adapter should be autoloaded or manually included by the caller
2382             $path = $this->_basepath . '/' . $this->_adapterfolder . '/' . $adapter . '.php';
2383 
2384             // Try to load the adapter object
2385             if (!file_exists($path))
2386             {
2387                 throw new InvalidArgumentException(sprintf('The %s install adapter does not exist.', $adapter));
2388             }
2389 
2390             // Try once more to find the class
2391             JLoader::register($class, $path);
2392 
2393             if (!class_exists($class))
2394             {
2395                 throw new InvalidArgumentException(sprintf('The %s install adapter does not exist.', $adapter));
2396             }
2397         }
2398 
2399         // Ensure the adapter type is part of the options array
2400         $options['type'] = $adapter;
2401 
2402         return new $class($this, $this->getDbo(), $options);
2403     }
2404 
2405     /**
2406      * Loads all adapters.
2407      *
2408      * @param   array  $options  Adapter options
2409      *
2410      * @return  void
2411      *
2412      * @since       3.4
2413      * @deprecated  4.0  Individual adapters should be instantiated as needed
2414      * @note        This method is serving as a proxy of the legacy JAdapter API into the preferred API
2415      */
2416     public function loadAllAdapters($options = array())
2417     {
2418         $this->getAdapters($options);
2419     }
2420 }
2421 
Joomla! Framework TM API documentation generated by ApiGen 2.8.0
Joomla!® and Joomla! Framework™ are trademarks of Open Source Matters, Inc. in the United States and other countries.