Overview

Packages

  • Core
    • Authentication
    • Backend
    • Cache
    • CEC
    • Chain
    • ContentType
    • Database
    • Datatype
    • Debug
    • Exception
    • Frontend
      • Search
      • URI
      • Util
    • GenericDB
      • Model
    • GUI
      • HTML
    • I18N
    • LayoutHandler
    • Log
    • Security
    • Session
    • Util
    • Validation
    • Versioning
    • XML
  • Module
    • ContentSitemapHtml
    • ContentSitemapXml
    • ContentUserForum
    • NavigationTop
  • mpAutoloaderClassMap
  • None
  • Plugin
    • ContentAllocation
    • CronjobOverview
    • FormAssistant
    • FrontendLogic
    • FrontendUsers
    • Linkchecker
    • ModRewrite
    • Newsletter
    • Repository
      • FrontendNavigation
      • KeywordDensity
    • SearchSolr
    • SmartyWrapper
    • UrlShortener
    • UserForum
    • Workflow
  • PluginManager
  • Setup
    • Form
    • GUI
    • Helper
      • Environment
      • Filesystem
      • MySQL
      • PHP
    • UpgradeJob

Classes

  • cAjaxRequest
  • cAutoload
  • cBackend
  • cEffectiveSetting
  • cGuiScrollListAlltranslations
  • cHTMLValidator
  • cMailer
  • cModuleFileTranslation
  • cModuleHandler
  • cModuleSearch
  • cModuleSynchronizer
  • cModuleTemplateHandler
  • CodeMirror
  • cPasswordRequest
  • cPermission
  • cRegistry
  • cSystemPurge
  • cSystemtest
  • cTinyMCEEditor
  • cWYSIWYGEditor
  • FrontendList
  • HtmlParser
  • TreeItem
  • UploadList
  • UploadSearchResultList

Functions

  • _processCmsTags
  • addArtspec
  • addslashes_deep
  • addSortImages
  • backToMainArea
  • buildArticleSelect
  • buildCategorySelect
  • buildCategorySelectRights
  • buildHeapTable
  • buildStackString
  • buildTree
  • buildUserOrGroupPermsFromRequest
  • callPluginStore
  • cApiCatGetLevelNode
  • cApiImageCheckCachedImageValidity
  • cApiImageCheckImageEditingPosibility
  • cApiImageGetCacheFileName
  • cApiImageGetTargetDimensions
  • cApiImageIsAnimGif
  • cApiImgScale
  • cApiImgScaleGetMD5CacheFile
  • cApiImgScaleHQ
  • cApiImgScaleImageMagick
  • cApiImgScaleLQ
  • cApiIsImageMagickAvailable
  • cApiStrCleanURLCharacters
  • cApiStrNormalizeLineEndings
  • cApiStrRecodeString
  • cApiStrReplaceDiacritics
  • cApiStrTrimAfterWord
  • cApiStrTrimHard
  • cApiStrTrimSentence
  • cDeprecated
  • cDie
  • cError
  • checkLangInClients
  • checkPathInformation
  • cInclude
  • compareUrlStrings
  • conChangeTemplateForCat
  • conCopyArticle
  • conCopyArtLang
  • conCopyContainerConf
  • conCopyContent
  • conCopyMetaTags
  • conCopyTemplateConfiguration
  • conCreateLocationString
  • conDeeperCategoriesArray
  • conDeleteart
  • conEditArt
  • conEditFirstTime
  • conFetchCategoryTree
  • conFlagOnOffline
  • conGenerateCode
  • conGenerateCodeForAllArts
  • conGenerateCodeForAllArtsInCategory
  • conGenerateCodeForAllartsUsingLayout
  • conGenerateCodeForAllartsUsingMod
  • conGenerateCodeForAllArtsUsingTemplate
  • conGenerateCodeForArtInAllCategories
  • conGenerateCodeForClient
  • conGenerateKeywords
  • conGetAvailableMetaTagTypes
  • conGetCategoryArticleId
  • conGetCategoryAssignments
  • conGetContainerConfiguration
  • conGetContentFromArticle
  • conGetHtmlTranslationTable
  • conGetMetaValue
  • conGetTemplateConfigurationIdForArticle
  • conGetTemplateConfigurationIdForCategory
  • conGetTopmostCat
  • conGetUsedModules
  • conHtmlentities
  • conHtmlEntityDecode
  • conHtmlSpecialChars
  • conIsLocked
  • conLock
  • conLockBulkEditing
  • conMakeArticleIndex
  • conMakeCatOnline
  • conMakeOnline
  • conMakeOnlineBulkEditing
  • conMakePublic
  • conMakeStart
  • conMoveArticles
  • conPhp54Check
  • conRemoveOldCategoryArticle
  • conSaveContentEntry
  • conSetCodeFlag
  • conSetCodeFlagBulkEditing
  • conSetMetaValue
  • conSyncArticle
  • copyRightsForElement
  • createBulkEditingFunction
  • createRandomName
  • createRightsForElement
  • cWarning
  • dbGetColumns
  • dbGetIndexes
  • dbGetPrimaryKeyName
  • dbTableExists
  • dbUpgradeTable
  • defineIfNotDefined
  • deleteArtspec
  • deleteRightsForElement
  • deleteSystemProperty
  • displayDatetime
  • emptyLogFile
  • endAndLogTiming
  • endsWith
  • extractNumber
  • generateDisplayFilePath
  • generateJs
  • getAktuellType
  • getAllClientsAndLanguages
  • getArtLang
  • getArtspec
  • getAvailableContentTypes
  • getCanonicalDay
  • getCanonicalMonth
  • getDirectorySize
  • getEffectiveSetting
  • getEffectiveSettingsByType
  • getEncodingByLanguage
  • getFileContents
  • getFileInformation
  • getFileType
  • getGroupOrUserName
  • getIDForArea
  • getJsHelpContext
  • getLanguageNamesByClient
  • getLanguagesByClient
  • getmicrotime
  • getNamedFrame
  • getParam
  • getParentAreaId
  • getSearchResults
  • getStrExpandCollapseButton
  • getSystemProperties
  • getSystemPropertiesByType
  • getSystemProperty
  • getTemplateSelect
  • getUplExpandCollapseButton
  • htmldecode
  • htmlentities_iso88592
  • humanReadableSize
  • includePlugins
  • insertEmptyStrRow
  • ipMatch
  • isAlphanumeric
  • isArchive
  • isArtInMultipleUse
  • isFunctionDisabled
  • isGroup
  • isIPv4
  • isRunningFromWeb
  • isStartArticle
  • isUtf8
  • isValidMail
  • langActivateDeactivateLanguage
  • langDeleteLanguage
  • langEditLanguage
  • langGetTextDirection
  • langNewLanguage
  • langRenameLanguage
  • layDeleteLayout
  • layEditLayout
  • machineReadableSize
  • mailLogBulkEditingFunctions
  • mailLogDecodeAddresses
  • markSubMenuItem
  • mask
  • modDeleteModule
  • modEditModule
  • modTestModule
  • phpInfoToHtml
  • plugin_include
  • prCreateURLNameLocationString
  • prDeleteCacheFileContent
  • prGetCacheFileContent
  • prResolvePathViaCategoryNames
  • prResolvePathViaURLNames
  • prWriteCacheFileContent
  • putFileContents
  • recursiveCopy
  • removeFileInformation
  • renderBackendBreadcrumb
  • renderLabel
  • renderSelectProperty
  • renderTextProperty
  • saveGroupRights
  • saveRights
  • scanDirectory
  • scanPlugins
  • sendEncodingHeader
  • set_magic_quotes_gpc
  • setArtspecDefault
  • setArtspecOnline
  • setHelpContext
  • setSystemProperty
  • showTree
  • startTiming
  • statCreateLocationString
  • statDisplayTopChooser
  • statDisplayYearlyTopChooser
  • statGetAvailableMonths
  • statGetAvailableYears
  • statResetStatistic
  • statsArchive
  • statsDisplayInfo
  • statsOverviewAll
  • statsOverviewTop
  • statsOverviewTopYear
  • statsOverviewYear
  • strAssignTemplate
  • strBuildSqlValues
  • strCheckTreeForErrors
  • strCopyCategory
  • strCopyTree
  • strDeeperCategoriesArray
  • strDeleteCategory
  • strHasArticles
  • strHasStartArticle
  • stripslashes_deep
  • strMakePublic
  • strMakeVisible
  • strMoveCatTargetallowed
  • strMoveDownCategory
  • strMoveSubtree
  • strMoveUpCategory
  • strNewCategory
  • strNewTree
  • strNextBackwards
  • strNextDeeper
  • strNextDeeperAll
  • strNextPost
  • strOrderedPostTreeList
  • strRemakeTreeTable
  • strRenameCategory
  • strRenameCategoryAlias
  • strSortPrePost
  • strSyncCategory
  • systemHavePerm
  • tplAutoFillModules
  • tplBrowseLayoutForContainers
  • tplcfgDuplicate
  • tplDeleteTemplate
  • tplDuplicateTemplate
  • tplEditTemplate
  • tplGetContainerDefault
  • tplGetContainerMode
  • tplGetContainerName
  • tplGetContainerTypes
  • tplGetInUsedData
  • tplIsTemplateInUse
  • tplPreparseLayout
  • updateClientCache
  • updateFileInformation
  • uplCreateFriendlyName
  • uplDirectoryListRecursive
  • uplGetDirectoriesToExclude
  • uplGetFileExtension
  • uplGetFileIcon
  • uplGetFileTypeDescription
  • uplGetThumbnail
  • uplHasFiles
  • uplHasSubdirs
  • uplmkdir
  • uplRecursiveDBDirectoryList
  • uplRecursiveDirectoryList
  • uplRenameDirectory
  • uplSearch
  • uplSyncDirectory
  • uplSyncDirectoryDBFS
  • xmlFileToArray
  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
  • Todo
   1: <?php
   2: /**
   3:  * This file contains the the system test class.
   4:  *
   5:  * @package Core
   6:  * @subpackage Backend
   7:  * @version SVN Revision $Rev:$
   8:  *
   9:  * @author Mischa Holz
  10:  * @copyright four for business AG <www.4fb.de>
  11:  * @license http://www.contenido.org/license/LIZENZ.txt
  12:  * @link http://www.4fb.de
  13:  * @link http://www.contenido.org
  14:  */
  15: 
  16: defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
  17: 
  18: /**
  19:  * Provides functions to test the system integrity
  20:  *
  21:  * @package Core
  22:  * @subpackage Backend
  23:  */
  24: class cSystemtest {
  25: 
  26:     /**
  27:      * The minimal PHP version
  28:      *
  29:      * @var string
  30:      */
  31:     const CON_SETUP_MIN_PHP_VERSION = '5.2.0';
  32: 
  33:     /**
  34:      * Messages have no influence on the result of the system integrity
  35:      *
  36:      * @var int
  37:      */
  38:     const C_SEVERITY_NONE = 1;
  39: 
  40:     /**
  41:      * Messages are only to inform the user about something.
  42:      *
  43:      * @var int
  44:      */
  45:     const C_SEVERITY_INFO = 2;
  46: 
  47:     /**
  48:      * Messages about settings which aren't correct, but CONTENIDO might work
  49:      * anyway
  50:      *
  51:      * @var int
  52:      */
  53:     const C_SEVERITY_WARNING = 3;
  54: 
  55:     /**
  56:      * Messages about settings which aren't correct.
  57:      * CONTENIDO won't work
  58:      *
  59:      * @var int
  60:      */
  61:     const C_SEVERITY_ERROR = 4;
  62: 
  63:     /**
  64:      * Possible result of cSystemtest::predictCorrectFilePermissions()
  65:      * The filepermissions are okay
  66:      *
  67:      * @var int
  68:      */
  69:     const CON_PREDICT_SUFFICIENT = 1;
  70: 
  71:     /**
  72:      * Possible result of cSystemtest::predictCorrectFilePermissions()
  73:      * The filepermissions are not predictable (we can't figure the server UID)
  74:      *
  75:      * @var int
  76:      */
  77:     const CON_PREDICT_NOTPREDICTABLE = 2;
  78: 
  79:     /**
  80:      * Possible result of cSystemtest::predictCorrectFilePermissions()
  81:      * The filepermissions for the owner have to be changed
  82:      *
  83:      * @var int
  84:      */
  85:     const CON_PREDICT_CHANGEPERM_SAMEOWNER = 3;
  86: 
  87:     /**
  88:      * Possible result of cSystemtest::predictCorrectFilePermissions()
  89:      * The filepermissions for the group have to be changed
  90:      *
  91:      * @var int
  92:      */
  93:     const CON_PREDICT_CHANGEPERM_SAMEGROUP = 4;
  94: 
  95:     /**
  96:      * Possible result of cSystemtest::predictCorrectFilePermissions()
  97:      * The filepermissions for others should be changed
  98:      *
  99:      * @var int
 100:      */
 101:     const CON_PREDICT_CHANGEPERM_OTHERS = 5;
 102: 
 103:     /**
 104:      * Possible result of cSystemtest::predictCorrectFilePermissions()
 105:      * The owner of the file should be changed
 106:      *
 107:      * @var int
 108:      */
 109:     const CON_PREDICT_CHANGEUSER = 6;
 110: 
 111:     /**
 112:      * Possible result of cSystemtest::predictCorrectFilePermissions()
 113:      * The group of the file should be changed
 114:      *
 115:      * @var int
 116:      */
 117:     const CON_PREDICT_CHANGEGROUP = 7;
 118: 
 119:     /**
 120:      * Possible result of cSystemtest::predictCorrectFilePermissions()
 121:      * The filepermissions are unpredictable because Windows
 122:      *
 123:      * @var int
 124:      */
 125:     const CON_PREDICT_WINDOWS = 8;
 126: 
 127:     /**
 128:      * Possible result of cSystemtest::checkOpenBaseDir().
 129:      * No restrictions
 130:      *
 131:      * @var int
 132:      */
 133:     const CON_BASEDIR_NORESTRICTION = 1;
 134: 
 135:     /**
 136:      * Possible result of cSystemtest::checkOpenBaseDir().
 137:      * The Basedir is set to ".". CONTENIDO won't work
 138:      *
 139:      * @var int
 140:      */
 141:     const CON_BASEDIR_DOTRESTRICTION = 2;
 142: 
 143:     /**
 144:      * Possible result of cSystemtest::checkOpenBaseDir().
 145:      * Open basedir is in effect but CONTENIDO works anyway
 146:      *
 147:      * @var int
 148:      */
 149:     const CON_BASEDIR_RESTRICTIONSUFFICIENT = 3;
 150: 
 151:     /**
 152:      * Possible result of cSystemtest::checkOpenBaseDir().
 153:      * Open basedir is in effect and CONTENIDO doesn't work with it
 154:      *
 155:      * @var int
 156:      */
 157:     const CON_BASEDIR_INCOMPATIBLE = 4;
 158: 
 159:     /**
 160:      * Possible result of cSystemtest::isPHPExtensionLoaded()
 161:      * The extension is loaded
 162:      *
 163:      * @var int
 164:      */
 165:     const CON_EXTENSION_AVAILABLE = 1;
 166: 
 167:     /**
 168:      * Possible result of cSystemtest::isPHPExtensionLoaded()
 169:      * The extension is not loaded
 170:      *
 171:      * @var int
 172:      */
 173:     const CON_EXTENSION_UNAVAILABLE = 2;
 174: 
 175:     /**
 176:      * Possible result of cSystemtest::isPHPExtensionLoaded()
 177:      * It was unable to check wether the extension is loaded or not
 178:      *
 179:      * @var int
 180:      */
 181:     const CON_EXTENSION_CANTCHECK = 3;
 182: 
 183:     /**
 184:      * Possible result of cSystemtest::checkImageResizer()
 185:      * GD is available for image resizing
 186:      *
 187:      * @var int
 188:      */
 189:     const CON_IMAGERESIZE_GD = 1;
 190: 
 191:     /**
 192:      * Possible result of cSystemtest::checkImageResizer()
 193:      * ImageMagick is available for image resizing
 194:      *
 195:      * @var int
 196:      */
 197:     const CON_IMAGERESIZE_IMAGEMAGICK = 2;
 198: 
 199:     /**
 200:      * Possible result of cSystemtest::checkImageResizer()
 201:      * It was unable to check which extension is available for image resizing
 202:      *
 203:      * @var int
 204:      */
 205:     const CON_IMAGERESIZE_CANTCHECK = 3;
 206: 
 207:     /**
 208:      * Possible result of cSystemtest::checkImageResizer()
 209:      * No fitting extension is available
 210:      *
 211:      * @var int
 212:      */
 213:     const CON_IMAGERESIZE_NOTHINGAVAILABLE = 4;
 214: 
 215:     /**
 216:      * Possible result of cSystemtest::testMySQL()
 217:      * Everything works fine with the given settings
 218:      *
 219:      * @var int
 220:      */
 221:     const CON_MYSQL_OK = 1;
 222: 
 223:     /**
 224:      * Possible result of cSystemtest::testMySQL()
 225:      * Strict mode is activated.
 226:      * CONTENIDO won't work
 227:      *
 228:      * @var int
 229:      */
 230:     const CON_MYSQL_STRICT_MODE = 2;
 231: 
 232:     /**
 233:      * Possible result of cSystemtest::testMySQL()
 234:      * Strict mode is activated.
 235:      * CONTENIDO won't work
 236:      *
 237:      * @var int
 238:      */
 239:     const CON_MYSQL_CANT_CONNECT = 3;
 240: 
 241:     /**
 242:      * The test results which are stored for display.
 243:      * Every array element is an assoicative array like this:
 244:      * $_messages[$i] = array(
 245:      * "result" => $result, //true or false, success or no success
 246:      * "severity" => $severity, //one of the C_SEVERITY constants
 247:      * "headline" => $headline, //the headline of the message
 248:      * "message" => $message //the message
 249:      * );
 250:      *
 251:      * @var array
 252:      */
 253:     protected $_messages;
 254: 
 255:     /**
 256:      * The stored config array
 257:      *
 258:      * @var array
 259:      */
 260:     protected $_config;
 261: 
 262:     /**
 263:      * Caches the given config array for later use.
 264:      *
 265:      * @param array $config A config array which should be similar to
 266:      *        CONTENIDO's $cfg
 267:      */
 268:     public function __construct($config) {
 269:         $this->_config = $config;
 270:     }
 271: 
 272:     /**
 273:      * Runs all available tests and stores the resuls in the messages array
 274:      *
 275:      * @param bool $testFileSystem If this is true the file system checks will
 276:      *        be performed too with standard settings.
 277:      */
 278:     public function runTests($testFileSystem = true) {
 279:         $this->storeResult($this->testPHPVersion(), self::C_SEVERITY_ERROR, sprintf(i18n("PHP Version lower than %s"), self::CON_SETUP_MIN_PHP_VERSION), sprintf(i18n("CONTENIDO requires PHP %s or higher as it uses functionality first introduced with this version. Please update your PHP version."), self::CON_SETUP_MIN_PHP_VERSION), i18n("The PHP version is higher than ") . self::CON_SETUP_MIN_PHP_VERSION);
 280:         $this->storeResult($this->testFileUploadSetting(), self::C_SEVERITY_WARNING, i18n("File uploads disabled"), sprintf(i18n("Your PHP version is not configured for file uploads. You can't upload files using CONTENIDO's file manager unless you configure PHP for file uploads. See %s for more information"), '<a target="_blank" href="http://www.php.net/manual/en/ini.core.php#ini.file-uploads">http://www.php.net/manual/en/ini.core.php#ini.file-uploads</a>'), i18n("PHP file upload is enabled"));
 281:         $this->storeResult($this->testMagicQuotesRuntimeSetting(), self::C_SEVERITY_ERROR, i18n("PHP setting 'magic_quotes_runtime' is turned on"), i18n("The PHP setting 'magic_quotes_runtime' is turned on. CONTENIDO has been developed to comply with magic_quotes_runtime=Off as this is the PHP default setting. You have to change this directive to make CONTENIDO work."), i18n("'magic_quotes_runtime' is turned off"));
 282:         $this->storeResult($this->testMagicQuotesSybaseSetting(), self::C_SEVERITY_ERROR, i18n("PHP Setting 'magic_quotes_sybase' is turned on"), i18n("The PHP Setting 'magic_quotes_sybase' is turned on. CONTENIDO has been developed to comply with magic_quotes_sybase=Off as this is the PHP default setting. You have to change this directive to make CONTENIDO work."), i18n("'magic_quotes_sybase' is turned off"));
 283:         $this->storeResult($this->testMaxExecutionTime(), self::C_SEVERITY_WARNING, i18n("PHP maximum execution time is less than 30 seconds"), i18n("PHP is configured for a maximum execution time of less than 30 seconds. This could cause problems with slow web servers and/or long operations in the backend. Our recommended execution time is 120 seconds on slow web servers, 60 seconds for medium ones and 30 seconds for fast web servers."), i18n("PHP allows execution times longer than 30 seconds"));
 284:         $this->storeResult($this->testZIPArchive(), self::C_SEVERITY_WARNING, i18n("The class ZipArchive could not be found"), i18n("This could cause some problems, but CONTENIDO is able to run without it. You should check your PHP installation."), i18n("The ZipArchive class is enabled"));
 285: 
 286:         $test = $this->checkOpenBasedirCompatibility();
 287:         switch ($test) {
 288:             case self::CON_BASEDIR_NORESTRICTION:
 289:                 $this->storeResult(true, self::C_SEVERITY_ERROR, "", "", i18n("open_basedir directive doesn't enforce any restrictions"));
 290:                 break;
 291:             case self::CON_BASEDIR_DOTRESTRICTION:
 292:                 $this->storeResult(false, self::C_SEVERITY_ERROR, i18n("open_basedir directive set to '.'"), i18n("The directive open_basedir is set to '.' (e.g. current directory). This means that CONTENIDO is unable to access files in a logical upper level in the filesystem. This will cause problems managing the CONTENIDO frontends. Either add the full path of this CONTENIDO installation to the open_basedir directive, or turn it off completely."));
 293:                 break;
 294:             case self::CON_BASEDIR_RESTRICTIONSUFFICIENT:
 295:                 $this->storeResult(false, self::C_SEVERITY_INFO, i18n("open_basedir setting might be insufficient"), i18n("Setup believes that the PHP directive open_basedir is configured sufficient, however, if you encounter errors like 'open_basedir restriction in effect. File <filename> is not within the allowed path(s): <path>', you have to adjust the open_basedir directive"));
 296:                 break;
 297:             case self::CON_BASEDIR_INCOMPATIBLE:
 298:                 $this->storeResult(false, self::C_SEVERITY_ERROR, i18n("open_basedir directive incompatible"), i18n("Setup has checked your PHP open_basedir directive and reckons that it is not sufficient. Please change the directive to include the CONTENIDO installation or turn it off completely."));
 299:                 break;
 300:         }
 301: 
 302:         $this->storeResult($this->testMemoryLimit(), self::C_SEVERITY_WARNING, i18n("PHP memory_limit directive too small"), i18n("The memory_limit directive is set to 32 MB or lower. This might be not enough for CONTENIDO to operate correctly. We recommend to disable this setting completely, as this can cause problems with large CONTENIDO projects."), i18n("Memory limit is either high enough or deactivated"));
 303:         $this->storeResult($this->testPHPSQLSafeMode(), self::C_SEVERITY_ERROR, i18n("PHP sql.safe_mode turned on"), i18n("The PHP directive sql.safe_mode is turned on. This causes problems with the SQL queries issued by CONTENIDO. Please turn that directive off."), i18n("sql.safe_mode is deactivated"));
 304:         $this->storeResult($this->isPHPExtensionLoaded("gd") == self::CON_EXTENSION_AVAILABLE, self::C_SEVERITY_WARNING, i18n("PHP GD-Extension is not loaded"), i18n("The PHP GD-Extension is not loaded. Some third-party modules rely on the GD functionality. If you don't enable the GD extension, you will encounter problems with modules like galleries."), i18n("GD extension loaded"));
 305:         if ($this->isPHPExtensionLoaded("gd") == self::CON_EXTENSION_AVAILABLE) {
 306:             $this->storeResult($this->testGDGIFRead(), self::C_SEVERITY_INFO, i18n("GD-Library GIF read support missing"), i18n("Your GD version doesn't support reading GIF files. This might cause problems with some modules."), i18n("GD is able to read GIFs"));
 307:             $this->storeResult($this->testGDGIFWrite(), self::C_SEVERITY_INFO, i18n("GD-Library GIF write support missing"), i18n("Your GD version doesn't support writing GIF files. This might cause problems with some modules."), i18n("GD is able to write GIFs"));
 308:             $this->storeResult($this->testGDJPEGRead(), self::C_SEVERITY_INFO, i18n("GD-Library JPEG read support missing"), i18n("Your GD version doesn't support reading JPEG files. This might cause problems with some modules."), i18n("GD is able to read JPEGs"));
 309:             $this->storeResult($this->testGDJPEGWrite(), self::C_SEVERITY_INFO, i18n("GD-Library JPEG write support missing"), i18n("Your GD version doesn't support writing JPEG files. This might cause problems with some modules."), i18n("GD is able to write JPEGs"));
 310:             $this->storeResult($this->testGDPNGRead(), self::C_SEVERITY_INFO, i18n("GD-Library PNG read support missing"), i18n("Your GD version doesn't support reading PNG files. This might cause problems with some modules."), i18n("GD is able to read PNGs"));
 311:             $this->storeResult($this->testGDPNGWrite(), self::C_SEVERITY_INFO, i18n("GD-Library PNG write support missing"), i18n("Your GD version doesn't support writing PNG files. This might cause problems with some modules."), i18n("GD is able to write PNGs"));
 312:         }
 313:         $this->storeResult($this->isPHPExtensionLoaded("pcre") == self::CON_EXTENSION_AVAILABLE, self::C_SEVERITY_ERROR, i18n("PHP PCRE Extension is not loaded"), i18n("The PHP PCRE Extension is not loaded. CONTENIDO uses PCRE-functions like preg_repace and preg_match and won't work without the PCRE Extension."), i18n("PCRE extension loaded"));
 314:         $this->storeResult($this->isPHPExtensionLoaded("xml") == self::CON_EXTENSION_AVAILABLE, self::C_SEVERITY_ERROR, i18n("PHP XML Extension is not loaded"), i18n("The PHP XML Extension is not loaded. CONTENIDO won't work without the XML Extension."), i18n("XML extension loaded"));
 315:         $this->storeResult($this->testDOMDocument(), self::C_SEVERITY_ERROR, i18n("Class 'DOMDocument' is not available"), i18n("The class DOMDocument could not be found. Please check your PHP installation and enable the XML extension if necessary. CONTENIDO won't work without it."), i18n("DOMDocument is available"));
 316:         $this->storeResult($this->testXMLParserCreate(), self::C_SEVERITY_ERROR, i18n("Function 'xml_parser_create' is not available"), i18n("The function xml_parser_create could not be found. Please check your PHP installation and enable the XML extension if necessary. CONTENIDO won't work without it."), i18n("xml_parser_create is available"));
 317: 
 318:         $result = $this->checkImageResizer();
 319:         switch ($result) {
 320:             case self::CON_IMAGERESIZE_CANTCHECK:
 321:                 $this->storeResult(false, self::C_SEVERITY_WARNING, i18n("Unable to check for a suitable image resizer"), i18n("Setup has tried to check for a suitable image resizer (which is, for exampl, required for thumbnail creation), but was not able to clearly identify one. If thumbnails won't work, make sure you've got either the GD-extension or ImageMagick available."));
 322:                 break;
 323:             case self::CON_IMAGERESIZE_NOTHINGAVAILABLE:
 324:                 $this->storeResult(false, self::C_SEVERITY_ERROR, i18n("No suitable image resizer available"), i18n("Setup checked your image resizing support, however, it was unable to find a suitable image resizer. Thumbnails won't work correctly or won't be looking good. Install the GD-Extension or ImageMagick"));
 325:                 break;
 326:             case self::CON_IMAGERESIZE_GD:
 327:                 $this->storeResult(true, self::C_SEVERITY_WARNING, "", "", i18n("GD extension is available and usable to handle images"));
 328:                 break;
 329:             case self::CON_IMAGERESIZE_IMAGEMAGICK:
 330:                 $this->storeResult(true, self::C_SEVERITY_WARNING, "", "", i18n("ImageMagick extension is available and usable to handle images"));
 331:                 break;
 332:         }
 333: 
 334:         $this->storeResult($this->testIconv(), self::C_SEVERITY_ERROR, i18n("PHP iconv functions are not available."), i18n("PHP has been compiled with the --without-iconv directive. CONTENIDO won't work without the iconv functions."), i18n("iconv is available"));
 335: 
 336:         $result = $this->testMySQL($this->_config['db']['connection']['host'], $this->_config['db']['connection']['user'], $this->_config['db']['connection']['password']);
 337:         switch ($result) {
 338:             case self::CON_MYSQL_OK:
 339:                 $this->storeResult(true, self::C_SEVERITY_ERROR, "", "", i18n("Database connection works"));
 340:                 break;
 341:             case self::CON_MYSQL_STRICT_MODE:
 342:                 $this->storeResult(false, self::C_SEVERITY_ERROR, i18n('MySQL is running in strict mode'), i18n('MySQL is running in strict mode, CONTENIDO will not work with this mode. Please change your sql_mode!'));
 343:                 break;
 344:             default:
 345:                 $this->storeResult(false, self::C_SEVERITY_ERROR, i18n("MySQL database connect failed"), sprintf(i18n("Setup was unable to connect to the MySQL Server (Server %s, Username %s). Please correct the MySQL data and try again.<br><br>The error message given was: %s"), $this->_config['db']['connection']['host'], $this->_config['db']['connection']['user'], $result));
 346:         }
 347: 
 348:         if ($testFileSystem) {
 349:             $this->storeResult($this->testFilesystem(), self::C_SEVERITY_WARNING, i18n("Permission error"), i18n("CONTENIDO doesn't have the necessary permissions to write all the files it needs. Please check your filesystem permissions."), i18n("Filesystem checks"), i18n("CONTENIDO has all the necessary permissions to read and write files"));
 350:         }
 351:     }
 352: 
 353:     /**
 354:      * Stores a result in the messages array for later display
 355:      *
 356:      * @param bool $result true for success, false otherwise
 357:      * @param int $severity One one of the C_SEVERITY constants
 358:      * @param string $errorHeadline The headline which will be stored in the
 359:      *        case that $result is false
 360:      * @param string $errorMessage The message which will be stored in the case
 361:      *        that $result is false
 362:      * @param string $successHeadline The headline which will be stored in the
 363:      *        case that $result is true
 364:      * @param string $successMessage The message which will be stored in the
 365:      *        case that $result is true
 366:      */
 367:     public function storeResult($result, $severity, $errorHeadline = "", $errorMessage = "", $successHeadline = "", $successMessage = "") {
 368:         if ($result) {
 369:             $this->_messages[] = array(
 370:                 "result" => $result,
 371:                 "severity" => $severity,
 372:                 "headline" => $successHeadline,
 373:                 "message" => $successMessage
 374:             );
 375:         } else {
 376:             $this->_messages[] = array(
 377:                 "result" => $result,
 378:                 "severity" => $severity,
 379:                 "headline" => $errorHeadline,
 380:                 "message" => $errorMessage
 381:             );
 382:         }
 383:     }
 384: 
 385:     /**
 386:      * Returns the message array
 387:      *
 388:      * @see cSystemtest::$_messages
 389:      * @return array
 390:      */
 391:     public function getResults() {
 392:         return $this->_messages;
 393:     }
 394: 
 395:     /**
 396:      * Returns an array with information about the file, especially the file
 397:      * owner
 398:      *
 399:      * The return array looks like this:
 400:      * array(
 401:      * "info" => $info, //'s' for a socket, 'l' for a symbolic link, '-' for a
 402:      * regular file, 'b' "block special", 'd' for a directory, 'c' "character
 403:      * special", 'p' FIFO pipe, 'u' for unkown
 404:      * "type" => $type, //A more descriptive version of $info
 405:      * "owner" => array(
 406:      * "id" => $id, //the owner id
 407:      * "read" => $read, //true if the owner is allowed to read the file
 408:      * "write" => $write //true if the owner is allowed to write the file
 409:      * )
 410:      * "group" => array(
 411:      * "id" => $id, //the owner group
 412:      * "read" => $read, //true if the owner group is allowed to read the file
 413:      * "write" => $write //true if the owner group is allowed to write the file
 414:      * )
 415:      * "others" => array(
 416:      * "read" => $read, //true if others are allowed to read the file
 417:      * "write" => $write //true if others are allowed to write the file
 418:      * )
 419:      * )
 420:      *
 421:      * @param string $sFilename The path to the file
 422:      * @return boolean array if the file can't be accessed
 423:      */
 424:     protected function getFileInfo($sFilename) {
 425:         if (!cFileHandler::exists($sFilename)) {
 426:             return false;
 427:         }
 428: 
 429:         $oiFilePermissions = fileperms($sFilename);
 430:         if ($oiFilePermissions === false) {
 431:             return false;
 432:         }
 433: 
 434:         switch (true) {
 435:             case (($oiFilePermissions & 0xC000) == 0xC000):
 436:                 $info = 's';
 437:                 $type = "socket";
 438:                 break;
 439:             case (($oiFilePermissions & 0xA000) == 0xA000):
 440:                 $info = 'l';
 441:                 $type = "symbolic link";
 442:                 break;
 443:             case (($oiFilePermissions & 0x8000) == 0x8000):
 444:                 $info = '-';
 445:                 $type = "regular file";
 446:                 break;
 447:             case (($oiFilePermissions & 0x6000) == 0x6000):
 448:                 $info = 'b';
 449:                 $type = "block special";
 450:                 break;
 451:             case (($oiFilePermissions & 0x4000) == 0x4000):
 452:                 $info = 'd';
 453:                 $type = "directory";
 454:                 break;
 455:             case (($oiFilePermissions & 0x2000) == 0x2000):
 456:                 $info = 'c';
 457:                 $type = "character special";
 458:                 break;
 459:             case (($oiFilePermissions & 0x1000) == 0x1000):
 460:                 $info = 'p';
 461:                 $type = "FIFO pipe";
 462:                 break;
 463:             default:
 464:                 $info = "u";
 465:                 $type = "Unknown";
 466:                 break;
 467:         }
 468: 
 469:         $aFileinfo = array();
 470:         $aFileinfo["info"] = $info;
 471:         $aFileinfo["type"] = $type;
 472:         $aFileinfo["owner"]["read"] = ($oiFilePermissions & 0x0100) ? true : false;
 473:         $aFileinfo["owner"]["write"] = ($oiFilePermissions & 0x0080) ? true : false;
 474:         $aFileinfo["group"]["read"] = ($oiFilePermissions & 0x0020) ? true : false;
 475:         $aFileinfo["group"]["write"] = ($oiFilePermissions & 0x0010) ? true : false;
 476:         $aFileinfo["others"]["read"] = ($oiFilePermissions & 0x0004) ? true : false;
 477:         $aFileinfo["others"]["write"] = ($oiFilePermissions & 0x0002) ? true : false;
 478:         $aFileinfo["owner"]["id"] = fileowner($sFilename);
 479:         $aFileinfo["group"]["id"] = filegroup($sFilename);
 480:         return ($aFileinfo);
 481:     }
 482: 
 483:     /**
 484:      * Returns true if the file is writeable
 485:      *
 486:      * @param string $filename The path to the file
 487:      * @return boolean
 488:      */
 489:     protected function canWriteFile($filename) {
 490:         clearstatcache();
 491:         if (is_file($filename)) {
 492:             return is_writable($filename);
 493:         } else {
 494:             return is_writable(dirname($filename));
 495:         }
 496:     }
 497: 
 498:     /**
 499:      * Returns true if the given file is a directory and if it is writeable
 500:      *
 501:      * @param string $dirname The path to the directory
 502:      * @return boolean
 503:      */
 504:     protected function canWriteDir($dirname) {
 505:         clearstatcache();
 506:         return is_dir($dirname) && is_writable($dirname);
 507:     }
 508: 
 509:     /**
 510:      * Returns the current user which runs the PHP interpreter
 511:      *
 512:      * @return number boolean ID or false if unable to determine the user
 513:      */
 514:     protected function getServerUID() {
 515:         if (function_exists("posix_getuid")) {
 516:             return posix_getuid();
 517:         }
 518: 
 519:         $sFilename = md5(mt_rand()) . ".txt";
 520: 
 521:         if (is_writeable(".")) {
 522:             cFileHandler::create($sFilename, "test");
 523:             $iUserId = fileowner($sFilename);
 524:             cFileHandler::remove($sFilename);
 525: 
 526:             return ($iUserId);
 527:         } else {
 528:             if (is_writeable("/tmp/")) {
 529:                 cFileHandler::create("/tmp/" . $sFilename, "w");
 530:                 $iUserId = fileowner("/tmp/" . $sFilename);
 531:                 cFileHandler::remove("/tmp/" . $sFilename);
 532: 
 533:                 return ($iUserId);
 534:             }
 535:             return false;
 536:         }
 537:     }
 538: 
 539:     /**
 540:      * Returns the current group which runs the PHP interpreter
 541:      *
 542:      * @return number boolean ID or false if unable to determine the group
 543:      */
 544:     protected function getServerGID() {
 545:         if (function_exists("posix_getgid")) {
 546:             return posix_getgid();
 547:         }
 548: 
 549:         $sFilename = md5(mt_rand()) . ".txt";
 550: 
 551:         if (is_writeable(".")) {
 552:             cFileHandler::create($sFilename, "test");
 553:             $iUserId = filegroup($sFilename);
 554:             cFileHandler::remove($sFilename);
 555: 
 556:             return ($iUserId);
 557:         } else {
 558:             return false;
 559:         }
 560:     }
 561: 
 562:     /**
 563:      * Returns one of the CON_PREDICT suggestions depending on the permissions
 564:      * of the given file
 565:      *
 566:      * @param string $file The path to the file
 567:      * @return int CON_PREDICT_*
 568:      */
 569:     protected function predictCorrectFilepermissions($file) {
 570:         // Check if the system is a windows system. If yes, we can't predict
 571:         // anything.
 572:         if ($this->isWindows()) {
 573:             return self::CON_PREDICT_WINDOWS;
 574:         }
 575: 
 576:         // Check if the file is read- and writeable. If yes, we don't need to do
 577:         // any
 578:         // further checks.
 579:         if (is_writable($file) && is_readable($file)) {
 580:             return self::CON_PREDICT_SUFFICIENT;
 581:         }
 582: 
 583:         // If we can't find out the web server UID, we cannot predict the
 584:         // correct
 585:         // mask.
 586:         $iServerUID = $this->getServerUID();
 587:         if ($iServerUID === false) {
 588:             return self::CON_PREDICT_NOTPREDICTABLE;
 589:         }
 590: 
 591:         // If we can't find out the web server GID, we cannot predict the
 592:         // correct
 593:         // mask.
 594:         $iServerGID = $this->getServerGID();
 595:         if ($iServerGID === false) {
 596:             return self::CON_PREDICT_NOTPREDICTABLE;
 597:         }
 598: 
 599:         $aFilePermissions = $this->getFileInfo($file);
 600: 
 601:         if ($this->getSafeModeStatus()) {
 602:             // SAFE-Mode related checks
 603:             if ($iServerUID == $aFilePermissions["owner"]["id"]) {
 604:                 return self::CON_PREDICT_CHANGEPERM_SAMEOWNER;
 605:             }
 606: 
 607:             if ($this->getSafeModeGidStatus()) {
 608:                 // SAFE-Mode GID related checks
 609:                 if ($iServerGID == $aFilePermissions["group"]["id"]) {
 610:                     return self::CON_PREDICT_CHANGEPERM_SAMEGROUP;
 611:                 }
 612: 
 613:                 return self::CON_PREDICT_CHANGEGROUP;
 614:             }
 615:         } else {
 616:             // Regular checks
 617:             if ($iServerUID == $aFilePermissions["owner"]["id"]) {
 618:                 return self::CON_PREDICT_CHANGEPERM_SAMEOWNER;
 619:             }
 620: 
 621:             if ($iServerGID == $aFilePermissions["group"]["id"]) {
 622:                 return self::CON_PREDICT_CHANGEPERM_SAMEGROUP;
 623:             }
 624: 
 625:             return self::CON_PREDICT_CHANGEPERM_OTHERS;
 626:         }
 627:     }
 628: 
 629:     /**
 630:      * Gets a PHP setting with ini_get
 631:      *
 632:      * @param string $setting A PHP setting
 633:      * @return mixed The value of the PHP setting or NULL if ini_get is disabled
 634:      */
 635:     protected function getPHPIniSetting($setting) {
 636:         // Avoid errors if ini_get is in the disable_functions directive
 637:         $value = @ini_get($setting);
 638: 
 639:         return $value;
 640:     }
 641: 
 642:     /**
 643:      * Converts a string like "12M" to the correct number of bytes
 644:      *
 645:      * @param string $val A string in the form of "12K", "12M" or "12G"
 646:      * @return number
 647:      */
 648:     protected function getAsBytes($val) {
 649:         if (strlen($val) == 0) {
 650:             return 0;
 651:         }
 652:         $val = trim($val);
 653:         $last = $val{strlen($val) - 1};
 654:         switch ($last) {
 655:             case 'k':
 656:             case 'K':
 657:                 return (int) $val * 1024;
 658:                 break;
 659:             case 'm':
 660:             case 'M':
 661:                 return (int) $val * 1048576;
 662:                 break;
 663:             case 'g':
 664:             case 'G':
 665:                 return (int) $val * 1048576 * 1024;
 666:                 break;
 667:             default:
 668:                 return $val;
 669:         }
 670:     }
 671: 
 672:     /**
 673:      * Connects to the database with the given settings
 674:      *
 675:      * @param string $host The database host
 676:      * @param string $username The database user
 677:      * @param string $password The database user password
 678:      * @return boolean cDb an array with the cDB object on the first place and a
 679:      *         boolean on the second
 680:      */
 681:     protected function doMySQLConnect($host, $username, $password) {
 682:         $aOptions = array(
 683:             'connection' => array(
 684:                 'host' => $host,
 685:                 'user' => $username,
 686:                 'password' => $password
 687:             )
 688:         );
 689:         try {
 690:             $db = new cDb($aOptions);
 691:         } catch (cDbException $e) {
 692:             return array(
 693:                 $db,
 694:                 false
 695:             );
 696:         }
 697: 
 698:         if ($db->connect() == 0) {
 699:             return array(
 700:                 $db,
 701:                 false
 702:             );
 703:         } else {
 704:             return array(
 705:                 $db,
 706:                 true
 707:             );
 708:         }
 709:     }
 710: 
 711:     /**
 712:      * Checks if a given extension is loaded.
 713:      *
 714:      * @param string $extension A PHP extension
 715:      * @return int Returns one of the CON_EXTENSION constants
 716:      */
 717:     public function isPHPExtensionLoaded($extension) {
 718:         $value = extension_loaded($extension);
 719: 
 720:         if ($value === NULL) {
 721:             return self::CON_EXTENSION_CANTCHECK;
 722:         }
 723: 
 724:         if ($value === true) {
 725:             return self::CON_EXTENSION_AVAILABLE;
 726:         }
 727: 
 728:         if ($value === false) {
 729:             return self::CON_EXTENSION_UNAVAILABLE;
 730:         }
 731:     }
 732: 
 733:     /**
 734:      * Returns true if the interpreter is run on Windows
 735:      *
 736:      * @return boolean
 737:      */
 738:     public function isWindows() {
 739:         if (strtolower(substr(PHP_OS, 0, 3)) == "win") {
 740:             return true;
 741:         } else {
 742:             return false;
 743:         }
 744:     }
 745: 
 746:     /**
 747:      * Test PHP function
 748:      *
 749:      * @return boolean true if the test passed and false if not
 750:      */
 751:     public function testPHPVersion() {
 752:         if (version_compare(phpversion(), CON_SETUP_MIN_PHP_VERSION, '>=') == true) {
 753:             return true;
 754:         } else {
 755:             return false;
 756:         }
 757:     }
 758: 
 759:     /**
 760:      *
 761:      * @return boolean true if the test passed and false if not
 762:      */
 763:     public function getSafeModeStatus() {
 764:         if ($this->getPHPIniSetting("safe_mode") == "1") {
 765:             return true;
 766:         } else {
 767:             return false;
 768:         }
 769:     }
 770: 
 771:     /**
 772:      *
 773:      * @return boolean true if the test passed and false if not
 774:      */
 775:     public function getSafeModeGidStatus() {
 776:         if ($this->getPHPIniSetting("safe_mode_gid") == "1") {
 777:             return true;
 778:         } else {
 779:             return false;
 780:         }
 781:     }
 782: 
 783:     /**
 784:      *
 785:      * @return boolean true if the test passed and false if not
 786:      */
 787:     public function testXMLParserCreate() {
 788:         return function_exists("xml_parser_create");
 789:     }
 790: 
 791:     /**
 792:      *
 793:      * @return boolean true if the test passed and false if not
 794:      */
 795:     public function testFileUploadSetting() {
 796:         return $this->getPHPIniSetting('file_uploads');
 797:     }
 798: 
 799:     /**
 800:      *
 801:      * @return boolean true if the test passed and false if not
 802:      */
 803:     public function testMagicQuotesRuntimeSetting() {
 804:         return !$this->getPHPIniSetting('magic_quotes_runtime');
 805:     }
 806: 
 807:     /**
 808:      *
 809:      * @return boolean true if the test passed and false if not
 810:      */
 811:     public function testMagicQuotesSybaseSetting() {
 812:         return !$this->getPHPIniSetting('magic_quotes_sybase');
 813:     }
 814: 
 815:     /**
 816:      *
 817:      * @return boolean true if the test passed and false if not
 818:      */
 819:     public function testMaxExecutionTime() {
 820:         return intval($this->getPHPIniSetting('max_execution_time')) >= 30;
 821:     }
 822: 
 823:     /**
 824:      *
 825:      * @return boolean true if the test passed and false if not
 826:      */
 827:     public function testZIPArchive() {
 828:         return class_exists("ZipArchive");
 829:     }
 830: 
 831:     /**
 832:      *
 833:      * @return boolean true if the test passed and false if not
 834:      */
 835:     public function testMemoryLimit() {
 836:         $memoryLimit = $this->getAsBytes($this->getPHPIniSetting("memory_limit"));
 837:         return ($memoryLimit > 1024 * 1024 * 32) || ($memoryLimit == 0);
 838:     }
 839: 
 840:     /**
 841:      *
 842:      * @return boolean true if the test passed and false if not
 843:      */
 844:     public function testPHPSQLSafeMode() {
 845:         return !$this->getPHPIniSetting('sql.safe_mode');
 846:     }
 847: 
 848:     /**
 849:      *
 850:      * @return boolean true if the test passed and false if not
 851:      */
 852:     public function testDOMDocument() {
 853:         return class_exists("DOMDocument");
 854:     }
 855: 
 856:     /**
 857:      *
 858:      * @param string $ext
 859:      * @return bool true if the test passed and false if not
 860:      */
 861:     public function testPHPExtension($ext) {
 862:         return $this->isPHPExtensionLoaded($ext) == CON_EXTENSION_AVAILABLE;
 863:     }
 864: 
 865:     /**
 866:      *
 867:      * @return boolean true if the test passed and false if not
 868:      */
 869:     public function testIconv() {
 870:         return function_exists("iconv");
 871:     }
 872: 
 873:     /**
 874:      *
 875:      * @return boolean true if the test passed and false if not
 876:      */
 877:     public function testGDGIFRead() {
 878:         if (($this->isPHPExtensionLoaded('gd') != self::CON_EXTENSION_AVAILABLE) && ($this->isPHPExtensionLoaded('gd') != self::CON_EXTENSION_CANTCHECK)) {
 879:             return false;
 880:         }
 881:         return function_exists("imagecreatefromgif");
 882:     }
 883: 
 884:     /**
 885:      *
 886:      * @return boolean true if the test passed and false if not
 887:      */
 888:     public function testGDGIFWrite() {
 889:         if (($this->isPHPExtensionLoaded('gd') != self::CON_EXTENSION_AVAILABLE) && ($this->isPHPExtensionLoaded('gd') != self::CON_EXTENSION_CANTCHECK)) {
 890:             return false;
 891:         }
 892:         return function_exists("imagegif");
 893:     }
 894: 
 895:     /**
 896:      *
 897:      * @return boolean true if the test passed and false if not
 898:      */
 899:     public function testGDJPEGRead() {
 900:         if (($this->isPHPExtensionLoaded('gd') != self::CON_EXTENSION_AVAILABLE) && ($this->isPHPExtensionLoaded('gd') != self::CON_EXTENSION_CANTCHECK)) {
 901:             return false;
 902:         }
 903:         return function_exists("imagecreatefromjpeg");
 904:     }
 905: 
 906:     /**
 907:      *
 908:      * @return boolean true if the test passed and false if not
 909:      */
 910:     public function testGDJPEGWrite() {
 911:         if (($this->isPHPExtensionLoaded('gd') != self::CON_EXTENSION_AVAILABLE) && ($this->isPHPExtensionLoaded('gd') != self::CON_EXTENSION_CANTCHECK)) {
 912:             return false;
 913:         }
 914:         return function_exists("imagejpeg");
 915:     }
 916: 
 917:     /**
 918:      *
 919:      * @return boolean true if the test passed and false if not
 920:      */
 921:     public function testGDPNGRead() {
 922:         if (($this->isPHPExtensionLoaded('gd') != self::CON_EXTENSION_AVAILABLE) && ($this->isPHPExtensionLoaded('gd') != self::CON_EXTENSION_CANTCHECK)) {
 923:             return false;
 924:         }
 925:         return function_exists("imagecreatefrompng");
 926:     }
 927: 
 928:     /**
 929:      *
 930:      * @return boolean true if the test passed and false if not
 931:      */
 932:     public function testGDPNGWrite() {
 933:         if (($this->isPHPExtensionLoaded('gd') != self::CON_EXTENSION_AVAILABLE) && ($this->isPHPExtensionLoaded('gd') != self::CON_EXTENSION_CANTCHECK)) {
 934:             return false;
 935:         }
 936:         return function_exists("imagepng");
 937:     }
 938: 
 939:     /**
 940:      *
 941:      * @return boolean true if the test passed and false if not
 942:      */
 943:     public function testMySQLExtension() {
 944:         if ($this->isPHPExtensionLoaded("mysql") == self::CON_EXTENSION_AVAILABLE) {
 945:             return true;
 946:         } else {
 947:             return false;
 948:         }
 949:     }
 950: 
 951:     /**
 952:      *
 953:      * @return boolean true if the test passed and false if not
 954:      */
 955:     public function testMySQLiExtension() {
 956:         if ($this->isPHPExtensionLoaded("mysqli") == self::CON_EXTENSION_AVAILABLE) {
 957:             return true;
 958:         } else {
 959:             return false;
 960:         }
 961:     }
 962: 
 963:     /**
 964:      *
 965:      * @param string $host
 966:      * @param string $username
 967:      * @param string $password
 968:      * @return boolean true if the test passed and false if not
 969:      */
 970:     public function testMySQLModeStrict($host, $username, $password) {
 971:         // host, user and password
 972:         $dbCfg = array(
 973:             'connection' => array(
 974:                 'host' => $host,
 975:                 'user' => $username,
 976:                 'password' => $password
 977:             )
 978:         );
 979: 
 980:         $db = new cDb($dbCfg);
 981:         $db->query('SELECT LOWER(@@GLOBAL.sql_mode) AS sql_mode');
 982:         if ($db->nextRecord()) {
 983:             if (strpos($db->f('sql_mode'), 'strict_trans_tables') !== false || strpos($db->f('sql_mode'), 'strict_all_tables') !== false) {
 984:                 return false;
 985:             }
 986:         }
 987:         return true;
 988:     }
 989: 
 990:     /**
 991:      *
 992:      * @param string $host
 993:      * @param string $username
 994:      * @param string $password
 995:      * @return int 1 if the test passed and > 1 if not
 996:      */
 997:     public function testMySQL($host, $username, $password) {
 998:         list($handle, $status) = $this->doMySQLConnect($host, $username, $password);
 999: 
1000:         $errorMessage = "";
1001:         if ($this->testMySQLiExtension() && !$this->testMySQLExtension()) {
1002:             $errorMessage = mysqli_error($handle->getLinkId());
1003:         } else {
1004:             $errorMessage = mysql_error();
1005:         }
1006:         if ($errorMessage != "") {
1007:             return $errorMessage;
1008:         }
1009: 
1010:         if ($handle->getLinkId()->errno == 1045) {
1011:             return self::CON_MYSQL_CANT_CONNECT;
1012:         }
1013: 
1014:         if (!$this->testMySQLModeStrict($host, $username, $password)) {
1015:             return self::CON_MYSQL_STRICT_MODE;
1016:         }
1017: 
1018:         return self::CON_MYSQL_OK;
1019:     }
1020: 
1021:     /**
1022:      *
1023:      * @param bool $testConfig
1024:      * @param bool $testFrontend
1025:      * @return bool true if the test passed and false if not
1026:      */
1027:     public function testFilesystem($testConfig = true, $testFrontend = true) {
1028:         global $cfgClient;
1029: 
1030:         $status = true;
1031: 
1032:         $files = array(
1033:             // check files
1034:             array(
1035:                 'filename' => $this->_config['path']['contenido_logs'] . "errorlog.txt",
1036:                 'severity' => self::C_SEVERITY_WARNING
1037:             ),
1038:             array(
1039:                 'filename' => $this->_config['path']['contenido_logs'] . "setuplog.txt",
1040:                 'severity' => self::C_SEVERITY_WARNING
1041:             ),
1042:             array(
1043:                 'filename' => $this->_config['path']['contenido_cronlog'] . "pseudo-cron.log",
1044:                 'severity' => self::C_SEVERITY_WARNING
1045:             ),
1046:             array(
1047:                 'filename' => $this->_config['path']['contenido_cronlog'] . "session_cleanup.php.job",
1048:                 'severity' => self::C_SEVERITY_WARNING
1049:             ),
1050:             array(
1051:                 'filename' => $this->_config['path']['contenido_cronlog'] . "send_reminder.php.job",
1052:                 'severity' => self::C_SEVERITY_WARNING
1053:             ),
1054:             array(
1055:                 'filename' => $this->_config['path']['contenido_cronlog'] . "optimize_database.php.job",
1056:                 'severity' => self::C_SEVERITY_WARNING
1057:             ),
1058:             array(
1059:                 'filename' => $this->_config['path']['contenido_cronlog'] . "move_old_stats.php.job",
1060:                 'severity' => self::C_SEVERITY_WARNING
1061:             ),
1062:             array(
1063:                 'filename' => $this->_config['path']['contenido_cronlog'] . "move_articles.php.job",
1064:                 'severity' => self::C_SEVERITY_WARNING
1065:             ),
1066:             array(
1067:                 'filename' => $this->_config['path']['contenido_cronlog'] . "linkchecker.php.job",
1068:                 'severity' => self::C_SEVERITY_WARNING
1069:             ),
1070:             array(
1071:                 'filename' => $this->_config['path']['contenido_cronlog'] . "run_newsletter_job.php.job",
1072:                 'severity' => self::C_SEVERITY_WARNING
1073:             ),
1074:             array(
1075:                 'filename' => $this->_config['path']['contenido_cronlog'] . "setfrontenduserstate.php.job",
1076:                 'severity' => self::C_SEVERITY_WARNING
1077:             ),
1078:             array(
1079:                 'filename' => $this->_config['path']['contenido_cronlog'] . "advance_workflow.php.job",
1080:                 'severity' => self::C_SEVERITY_WARNING
1081:             ),
1082:             array(
1083:                 'filename' => $this->_config['path']['contenido_cache'],
1084:                 'severity' => self::C_SEVERITY_WARNING,
1085:                 'dir' => true
1086:             ),
1087:             array(
1088:                 'filename' => $this->_config['path']['contenido_temp'],
1089:                 'severity' => self::C_SEVERITY_WARNING,
1090:                 'dir' => true
1091:             ),
1092:             array(
1093:                 'filename' => $this->_config['path']['contenido_config'] . "config.php",
1094:                 'severity' => self::C_SEVERITY_ERROR,
1095:                 'config' => $testConfig
1096:             )
1097:         );
1098: 
1099:         $frontendFiles = array(
1100:             "cache",
1101:             "cache/code",
1102:             "css",
1103:             "data",
1104:             "data/layouts",
1105:             "data/logs",
1106:             "data/modules",
1107:             "data/version",
1108:             "data/version/css",
1109:             "data/version/js",
1110:             "data/version/layout",
1111:             "data/version/module",
1112:             "data/version/templates",
1113:             "js",
1114:             "templates",
1115:             "upload"
1116:         );
1117: 
1118:         $ret = true;
1119:         foreach ($files as $key => $file) {
1120: 
1121:             $name = $file['filename'];
1122:             $severity = $file['severity'];
1123:             $dir = $file['dir'];
1124:             $frontend = $file['frontend'];
1125:             $config = $file['config'];
1126: 
1127:             if (array_key_exists('frontend', $file) && $frontend != false) {
1128:                 $ret = $this->testSingleFile($name, $severity, $frontend);
1129:             } else if (array_key_exists('config', $file) && $config != false) {
1130:                 $ret = $this->testSingleFile($name, $severity);
1131:             } else if (!array_key_exists('frontend', $file) && !array_key_exists('config', $file)) {
1132:                 $ret = $this->testSingleFile($name, $severity, $config);
1133:             }
1134:             if ($ret == false) {
1135:                 $status = false;
1136:             }
1137:         }
1138: 
1139:         if ($testFrontend) {
1140:             foreach ($cfgClient as $oneClient) {
1141:                 if (!is_array($oneClient)) {
1142:                     continue;
1143:                 }
1144:                 foreach ($frontendFiles as $file) {
1145:                     $ret = $this->testSingleFile($oneClient["path"]["frontend"] . $file, self::C_SEVERITY_WARNING, true);
1146:                     if ($ret == false) {
1147:                         $status = false;
1148:                     }
1149:                 }
1150:             }
1151:         }
1152: 
1153:         return $status;
1154:     }
1155: 
1156:     /**
1157:      * Checks a single file or directory wether it is writeable or not
1158:      *
1159:      * @param string $filename The file
1160:      * @param int $severity The resulting C_SEVERITY constant should the test
1161:      *        fail
1162:      * @param bool $dir True if the $filename is a directory
1163:      * @throws Exception Throws a generic Exception in the event that the
1164:      *         permissions are wrong
1165:      * @return boolean Returns true if everything is fine
1166:      */
1167:     protected function testSingleFile($filename, $severity, $dir = false) {
1168:         if (strpos($filename, $this->_config["path"]["frontend"]) === 0) {
1169:             $length = strlen($this->_config["path"]["frontend"]) + 1;
1170:             $shortFilename = substr($filename, $length);
1171:         } else { // for dirs
1172:             $shortFilename = $filename;
1173:         }
1174: 
1175:         if (!$dir) {
1176:             $status = $this->canWriteFile($filename);
1177:         } else {
1178:             $status = $this->canWriteDir($filename);
1179:         }
1180: 
1181:         $title = sprintf(i18n("Can't write %s"), $shortFilename);
1182:         $message = sprintf(i18n("Setup or CONTENIDO can't write to the file %s. Please change the file permissions to correct this problem."), $shortFilename);
1183: 
1184:         if ($status == false) {
1185:             if (cFileHandler::exists($filename)) {
1186:                 $perm = $this->predictCorrectFilepermissions($filename);
1187: 
1188:                 switch ($perm) {
1189:                     case self::CON_PREDICT_WINDOWS:
1190:                         $predictMessage = i18n("Your Server runs Windows. Due to that, Setup can't recommend any file permissions.");
1191:                         break;
1192:                     case self::CON_PREDICT_NOTPREDICTABLE:
1193:                         $predictMessage = sprintf(i18n("Due to a very restrictive environment, an advise is not possible. Ask your system administrator to enable write access to the file %s, especially in environments where ACL (Access Control Lists) are used."), $shortFilename);
1194:                         break;
1195:                     case self::CON_PREDICT_CHANGEPERM_SAMEOWNER:
1196:                         $mfileperms = substr(sprintf("%o", fileperms($filename)), -3);
1197:                         $mfileperms{0} = intval($mfileperms{0}) | 0x6;
1198:                         $predictMessage = sprintf(i18n("Your web server and the owner of your files are identical. You need to enable write access for the owner, e.g. using chmod u+rw %s, setting the file mask to %s or set the owner to allow writing the file."), $shortFilename, $mfileperms);
1199:                         break;
1200:                     case self::CON_PREDICT_CHANGEPERM_SAMEGROUP:
1201:                         $mfileperms = substr(sprintf("%o", fileperms($filename)), -3);
1202:                         $mfileperms{1} = intval($mfileperms{1}) | 0x6;
1203:                         $predictMessage = sprintf(i18n("Your web server's group and the group of your files are identical. You need to enable write access for the group, e.g. using chmod g+rw %s, setting the file mask to %s or set the group to allow writing the file."), $shortFilename, $mfileperms);
1204:                         break;
1205:                     case self::CON_PREDICT_CHANGEPERM_OTHERS:
1206:                         $mfileperms = substr(sprintf("%o", fileperms($filename)), -3);
1207:                         $mfileperms{2} = intval($mfileperms{2}) | 0x6;
1208:                         $predictMessage = sprintf(i18n("Your web server is not equal to the file owner, and is not in the webserver's group. It would be highly insecure to allow world write acess to the files. If you want to install anyways, enable write access for all others, e.g. using chmod o+rw %s, setting the file mask to %s or set the others to allow writing the file."), $shortFilename, $mfileperms);
1209:                         break;
1210:                 }
1211:             } else {
1212:                 $target = dirname($filename);
1213: 
1214:                 $perm = $this->predictCorrectFilepermissions($target);
1215: 
1216:                 switch ($perm) {
1217:                     case self::CON_PREDICT_WINDOWS:
1218:                         $predictMessage = i18n("Your Server runs Windows. Due to that, Setup can't recommend any directory permissions.");
1219:                         break;
1220:                     case self::CON_PREDICT_NOTPREDICTABLE:
1221:                         $predictMessage = sprintf(i18n("Due to a very restrictive environment, an advise is not possible. Ask your system administrator to enable write access to the file or directory %s, especially in environments where ACL (Access Control Lists) are used."), dirname($shortFilename));
1222:                         break;
1223:                     case self::CON_PREDICT_CHANGEPERM_SAMEOWNER:
1224:                         $mfileperms = substr(sprintf("%o", @fileperms($target)), -3);
1225:                         $mfileperms{0} = intval($mfileperms{0}) | 0x6;
1226:                         $predictMessage = sprintf(i18n("Your web server and the owner of your directory are identical. You need to enable write access for the owner, e.g. using chmod u+rw %s, setting the directory mask to %s or set the owner to allow writing the directory."), dirname($shortFilename), $mfileperms);
1227:                         break;
1228:                     case self::CON_PREDICT_CHANGEPERM_SAMEGROUP:
1229:                         $mfileperms = substr(sprintf("%o", @fileperms($target)), -3);
1230:                         $mfileperms{1} = intval($mfileperms{1}) | 0x6;
1231:                         $predictMessage = sprintf(i18n("Your web server's group and the group of your directory are identical. You need to enable write access for the group, e.g. using chmod g+rw %s, setting the directory mask to %s or set the group to allow writing the directory."), dirname($shortFilename), $mfileperms);
1232:                         break;
1233:                     case self::CON_PREDICT_CHANGEPERM_OTHERS:
1234:                         $mfileperms = substr(sprintf("%o", @fileperms($target)), -3);
1235:                         $mfileperms{2} = intval($mfileperms{2}) | 0x6;
1236:                         $predictMessage = sprintf(i18n("Your web server is not equal to the directory owner, and is not in the webserver's group. It would be highly insecure to allow world write acess to the directory. If you want to install anyways, enable write access for all others, e.g. using chmod o+rw %s, setting the directory mask to %s or set the others to allow writing the directory."), dirname($shortFilename), $mfileperms);
1237:                         break;
1238:                 }
1239:             }
1240: 
1241:             $this->storeResult(false, $severity, $title, $message . "<br><br>" . $predictMessage);
1242:             if ($title && $message) {
1243:                 $status = false;
1244:             }
1245:         }
1246: 
1247:         return $status;
1248:     }
1249: 
1250:     /**
1251:      *
1252:      * @return boolean true if the test passed and false if not
1253:      */
1254:     public function testFrontendFolderCreation() {
1255:         $directories = array(
1256:             "cms/cache",
1257:             "cms/cache/code",
1258:             "cms/css",
1259:             "cms/data",
1260:             "cms/data/layouts",
1261:             "cms/data/modules",
1262:             "cms/data/version",
1263:             "cms/data/version/css",
1264:             "cms/data/version/js",
1265:             "cms/data/version/layout",
1266:             "cms/data/version/module",
1267:             "cms/data/version/templates",
1268:             "cms/js",
1269:             "cms/templates",
1270:             "cms/upload"
1271:         );
1272: 
1273:         $ret = true;
1274: 
1275:         foreach ($directories as $dir) {
1276:             if (!cFileHandler::exists("../" . $dir)) {
1277:                 if (!mkdir("../" . $dir)) {
1278:                     $ret = false;
1279:                     $this->storeResult(false, self::C_SEVERITY_WARNING, sprintf(i18n("Could not find or create directory %s"), $dir), i18n("The frontend expects certain directories to exist and it needs to be able to write to these directories."));
1280:                 } else {
1281:                     if (!cFileHandler::chmod("../" . $dir, "777")) {
1282:                         $ret = false;
1283:                         $this->storeResult(false, self::C_SEVERITY_WARNING, sprintf(i18n("Could not find or create directory %s"), $dir), i18n("The frontend expects certain directories to exist and it needs to be able to write to these directories."));
1284:                     }
1285:                 }
1286:             }
1287:         }
1288: 
1289:         return $ret;
1290:     }
1291: 
1292:     /**
1293:      * Checks for the open_basedir directive and returns one of the CON_BASEDIR
1294:      * constants
1295:      *
1296:      * @return int
1297:      */
1298:     public function checkOpenBasedirCompatibility() {
1299:         $value = $this->getPHPIniSetting("open_basedir");
1300: 
1301:         if ($this->isWindows()) {
1302:             $aBasedirEntries = explode(";", $value);
1303:         } else {
1304:             $aBasedirEntries = explode(":", $value);
1305:         }
1306: 
1307:         if (count($aBasedirEntries) == 1 && $aBasedirEntries[0] == $value) {
1308:             return self::CON_BASEDIR_NORESTRICTION;
1309:         }
1310: 
1311:         if (in_array(".", $aBasedirEntries) && count($aBasedirEntries) == 1) {
1312:             return self::CON_BASEDIR_DOTRESTRICTION;
1313:         }
1314: 
1315:         $sCurrentDirectory = getcwd();
1316: 
1317:         foreach ($aBasedirEntries as $entry) {
1318:             if (stristr($sCurrentDirectory, $entry)) {
1319:                 return self::CON_BASEDIR_RESTRICTIONSUFFICIENT;
1320:             }
1321:         }
1322: 
1323:         return self::CON_BASEDIR_INCOMPATIBLE;
1324:     }
1325: 
1326:     /**
1327:      * Checks the available image resizer classes and functions
1328:      *
1329:      * @return int Returns one of the CON_IMAGERESIZE constants
1330:      */
1331:     public function checkImageResizer() {
1332:         $iGDStatus = $this->isPHPExtensionLoaded('gd');
1333: 
1334:         if ($iGDStatus == self::CON_EXTENSION_AVAILABLE) {
1335:             return self::CON_IMAGERESIZE_GD;
1336:         }
1337: 
1338:         if (function_exists('imagecreate')) {
1339:             return self::CON_IMAGERESIZE_GD;
1340:         }
1341: 
1342:         checkAndInclude($this->_config['path']['contenido'] . 'includes/functions.api.images.php');
1343:         if (capiIsImageMagickAvailable()) {
1344:             return self::CON_IMAGERESIZE_IMAGEMAGICK;
1345:         }
1346: 
1347:         if ($iGDStatus === self::CON_EXTENSION_CANTCHECK) {
1348:             return self::CON_IMAGERESIZE_CANTCHECK;
1349:         } else {
1350:             return self::CON_IMAGERESIZE_NOTHINGAVAILABLE;
1351:         }
1352:     }
1353: 
1354:     /**
1355:      *
1356:      * @param string $setupType
1357:      * @param string $databaseName
1358:      * @param string $databasePrefix
1359:      */
1360:     public function checkSetupMysql($setupType, $databaseName, $databasePrefix) {
1361:         switch ($setupType) {
1362:             case "setup":
1363: 
1364:                 $db = getSetupMySQLDBConnection(false);
1365: 
1366:                 // Check if the database exists
1367:                 $status = checkMySQLDatabaseExists($db, $databaseName);
1368: 
1369:                 if ($status) {
1370:                     // Yes, database exists
1371:                     $db = getSetupMySQLDBConnection();
1372:                     $db->connect();
1373: 
1374:                     // Check if data already exists
1375:                     $db->query('SHOW TABLES LIKE "%s_actions"', $databasePrefix);
1376: 
1377:                     if ($db->nextRecord()) {
1378:                         $this->storeResult(false, cSystemtest::C_SEVERITY_ERROR, i18n("MySQL database already exists and seems to be filled", "setup"), sprintf(i18n("Setup checked the database %s and found the table %s. It seems that you already have a CONTENIDO installation in this database. If you want to install anyways, change the database prefix. If you want to upgrade from a previous version, choose 'upgrade' as setup type.", "setup"), $databaseName, sprintf("%s_actions", $databasePrefix)));
1379:                         return;
1380:                     }
1381: 
1382:                     // Check if data already exists
1383:                     $db->query('SHOW TABLES LIKE "%s_test"', $databasePrefix);
1384:                     if ($db->nextRecord()) {
1385:                         $this->storeResult(false, cSystemtest::C_SEVERITY_ERROR, i18n("MySQL test table already exists in the database", "setup"), sprintf(i18n("Setup checked the database %s and found the test table %s. Please remove it before continuing.", "setup"), $databaseName, sprintf("%s_test", $databasePrefix)));
1386:                         return;
1387:                     }
1388: 
1389:                     // Good, table doesn't exist. Check for database permisions
1390:                     $status = checkMySQLTableCreation($db, $databaseName, sprintf("%s_test", $databasePrefix));
1391:                     if (!$status) {
1392:                         $this->storeResult(false, cSystemtest::C_SEVERITY_ERROR, i18n("Unable to create tables in the selected MySQL database", "setup"), sprintf(i18n("Setup tried to create a test table in the database %s and failed. Please assign table creation permissions to the database user you entered, or ask an administrator to do so.", "setup"), $databaseName));
1393:                         return;
1394:                     }
1395: 
1396:                     // Good, we could create a table. Now remove it again
1397:                     $status = checkMySQLDropTable($db, $databaseName, sprintf("%s_test", $databasePrefix));
1398:                     if (!$status) {
1399:                         $this->storeResult(false, cSystemtest::C_SEVERITY_WARNING, i18n("Unable to remove the test table", "setup"), sprintf(i18n("Setup tried to remove the test table %s in the database %s and failed due to insufficient permissions. Please remove the table %s manually.", "setup"), sprintf("%s_test", $databasePrefix), $databaseName, sprintf("%s_test", $databasePrefix)));
1400:                     }
1401:                 } else {
1402:                     $db->connect();
1403:                     // Check if database can be created
1404:                     $status = checkMySQLDatabaseCreation($db, $databaseName);
1405:                     if (!$status) {
1406:                         $this->storeResult(false, cSystemtest::C_SEVERITY_ERROR, i18n("Unable to create the database in the MySQL server", "setup"), sprintf(i18n("Setup tried to create a test database and failed. Please assign database creation permissions to the database user you entered, ask an administrator to do so, or create the database manually.", "setup")));
1407:                         return;
1408:                     }
1409: 
1410:                     // Check for database permisions
1411:                     $status = checkMySQLTableCreation($db, $databaseName, sprintf("%s_test", $databasePrefix));
1412:                     if (!$status) {
1413:                         $this->storeResult(false, cSystemtest::C_SEVERITY_ERROR, i18n("Unable to create tables in the selected MySQL database", "setup"), sprintf(i18n("Setup tried to create a test table in the database %s and failed. Please assign table creation permissions to the database user you entered, or ask an administrator to do so.", "setup"), $databaseName));
1414:                         return;
1415:                     }
1416: 
1417:                     // Good, we could create a table. Now remove it again
1418:                     $status = checkMySQLDropTable($db, $databaseName, sprintf("%s_test", $databasePrefix));
1419:                     if (!$status) {
1420:                         $this->storeResult(false, cSystemtest::C_SEVERITY_WARNING, i18n("Unable to remove the test table", "setup"), sprintf(i18n("Setup tried to remove the test table %s in the database %s and failed due to insufficient permissions. Please remove the table %s manually.", "setup"), sprintf("%s_test", $databasePrefix), $databaseName, sprintf("%s_test", $databasePrefix)));
1421:                     }
1422:                 }
1423:                 break;
1424:             case "upgrade":
1425:                 $db = getSetupMySQLDBConnection(false);
1426: 
1427:                 // Check if the database exists
1428:                 $status = checkMySQLDatabaseExists($db, $databaseName);
1429:                 if (!$status) {
1430:                     $this->storeResult(false, cSystemtest::C_SEVERITY_ERROR, i18n("No data found for the upgrade", "setup"), sprintf(i18n("Setup tried to locate the data for the upgrade, however, the database %s doesn't exist. You need to copy your database first before running setup.", "setup"), $databaseName));
1431:                     return;
1432:                 }
1433: 
1434:                 $db = getSetupMySQLDBConnection();
1435: 
1436:                 // Check if data already exists
1437:                 $sql = 'SHOW TABLES LIKE "%s_actions"';
1438:                 $db->query(sprintf($sql, $databasePrefix));
1439:                 if (!$db->nextRecord()) {
1440:                     $this->storeResult(false, cSystemtest::C_SEVERITY_ERROR, i18n("No data found for the upgrade", "setup"), sprintf(i18n("Setup tried to locate the data for the upgrade, however, the database %s contains no tables. You need to copy your database first before running setup.", "setup"), $databaseName));
1441:                     return;
1442:                 }
1443: 
1444:                 break;
1445:         }
1446:     }
1447: }
1448: 
CMS CONTENIDO 4.9.2 API documentation generated by ApiGen 2.8.0