1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
15:
16: defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
17:
18: 19: 20: 21: 22: 23:
24: class cSystemtest {
25:
26: 27: 28: 29: 30:
31: const CON_SETUP_MIN_PHP_VERSION = '5.2.0';
32:
33: 34: 35: 36: 37:
38: const C_SEVERITY_NONE = 1;
39:
40: 41: 42: 43: 44:
45: const C_SEVERITY_INFO = 2;
46:
47: 48: 49: 50: 51: 52:
53: const C_SEVERITY_WARNING = 3;
54:
55: 56: 57: 58: 59: 60:
61: const C_SEVERITY_ERROR = 4;
62:
63: 64: 65: 66: 67: 68:
69: const CON_PREDICT_SUFFICIENT = 1;
70:
71: 72: 73: 74: 75: 76:
77: const CON_PREDICT_NOTPREDICTABLE = 2;
78:
79: 80: 81: 82: 83: 84:
85: const CON_PREDICT_CHANGEPERM_SAMEOWNER = 3;
86:
87: 88: 89: 90: 91: 92:
93: const CON_PREDICT_CHANGEPERM_SAMEGROUP = 4;
94:
95: 96: 97: 98: 99: 100:
101: const CON_PREDICT_CHANGEPERM_OTHERS = 5;
102:
103: 104: 105: 106: 107: 108:
109: const CON_PREDICT_CHANGEUSER = 6;
110:
111: 112: 113: 114: 115: 116:
117: const CON_PREDICT_CHANGEGROUP = 7;
118:
119: 120: 121: 122: 123: 124:
125: const CON_PREDICT_WINDOWS = 8;
126:
127: 128: 129: 130: 131: 132:
133: const CON_BASEDIR_NORESTRICTION = 1;
134:
135: 136: 137: 138: 139: 140:
141: const CON_BASEDIR_DOTRESTRICTION = 2;
142:
143: 144: 145: 146: 147: 148:
149: const CON_BASEDIR_RESTRICTIONSUFFICIENT = 3;
150:
151: 152: 153: 154: 155: 156:
157: const CON_BASEDIR_INCOMPATIBLE = 4;
158:
159: 160: 161: 162: 163: 164:
165: const CON_EXTENSION_AVAILABLE = 1;
166:
167: 168: 169: 170: 171: 172:
173: const CON_EXTENSION_UNAVAILABLE = 2;
174:
175: 176: 177: 178: 179: 180:
181: const CON_EXTENSION_CANTCHECK = 3;
182:
183: 184: 185: 186: 187: 188:
189: const CON_IMAGERESIZE_GD = 1;
190:
191: 192: 193: 194: 195: 196:
197: const CON_IMAGERESIZE_IMAGEMAGICK = 2;
198:
199: 200: 201: 202: 203: 204:
205: const CON_IMAGERESIZE_CANTCHECK = 3;
206:
207: 208: 209: 210: 211: 212:
213: const CON_IMAGERESIZE_NOTHINGAVAILABLE = 4;
214:
215: 216: 217: 218: 219: 220:
221: const CON_MYSQL_OK = 1;
222:
223: 224: 225: 226: 227: 228: 229:
230: const CON_MYSQL_STRICT_MODE = 2;
231:
232: 233: 234: 235: 236: 237: 238:
239: const CON_MYSQL_CANT_CONNECT = 3;
240:
241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252:
253: protected $_messages;
254:
255: 256: 257: 258: 259:
260: protected $_config;
261:
262: 263: 264: 265: 266: 267:
268: public function __construct($config) {
269: $this->_config = $config;
270: }
271:
272: 273: 274: 275: 276: 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: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 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: 387: 388: 389: 390:
391: public function getResults() {
392: return $this->_messages;
393: }
394:
395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 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: 485: 486: 487: 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: 500: 501: 502: 503:
504: protected function canWriteDir($dirname) {
505: clearstatcache();
506: return is_dir($dirname) && is_writable($dirname);
507: }
508:
509: 510: 511: 512: 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: 541: 542: 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: 564: 565: 566: 567: 568:
569: protected function predictCorrectFilepermissions($file) {
570:
571:
572: if ($this->isWindows()) {
573: return self::CON_PREDICT_WINDOWS;
574: }
575:
576:
577:
578:
579: if (is_writable($file) && is_readable($file)) {
580: return self::CON_PREDICT_SUFFICIENT;
581: }
582:
583:
584:
585:
586: $iServerUID = $this->getServerUID();
587: if ($iServerUID === false) {
588: return self::CON_PREDICT_NOTPREDICTABLE;
589: }
590:
591:
592:
593:
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:
603: if ($iServerUID == $aFilePermissions["owner"]["id"]) {
604: return self::CON_PREDICT_CHANGEPERM_SAMEOWNER;
605: }
606:
607: if ($this->getSafeModeGidStatus()) {
608:
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:
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: 631: 632: 633: 634:
635: protected function getPHPIniSetting($setting) {
636:
637: $value = @ini_get($setting);
638:
639: return $value;
640: }
641:
642: 643: 644: 645: 646: 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: 674: 675: 676: 677: 678: 679: 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: 713: 714: 715: 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: 735: 736: 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: 748: 749: 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: 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: 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: 786:
787: public function testXMLParserCreate() {
788: return function_exists("xml_parser_create");
789: }
790:
791: 792: 793: 794:
795: public function testFileUploadSetting() {
796: return $this->getPHPIniSetting('file_uploads');
797: }
798:
799: 800: 801: 802:
803: public function testMagicQuotesRuntimeSetting() {
804: return !$this->getPHPIniSetting('magic_quotes_runtime');
805: }
806:
807: 808: 809: 810:
811: public function testMagicQuotesSybaseSetting() {
812: return !$this->getPHPIniSetting('magic_quotes_sybase');
813: }
814:
815: 816: 817: 818:
819: public function testMaxExecutionTime() {
820: return intval($this->getPHPIniSetting('max_execution_time')) >= 30;
821: }
822:
823: 824: 825: 826:
827: public function testZIPArchive() {
828: return class_exists("ZipArchive");
829: }
830:
831: 832: 833: 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: 843:
844: public function testPHPSQLSafeMode() {
845: return !$this->getPHPIniSetting('sql.safe_mode');
846: }
847:
848: 849: 850: 851:
852: public function testDOMDocument() {
853: return class_exists("DOMDocument");
854: }
855:
856: 857: 858: 859: 860:
861: public function testPHPExtension($ext) {
862: return $this->isPHPExtensionLoaded($ext) == CON_EXTENSION_AVAILABLE;
863: }
864:
865: 866: 867: 868:
869: public function testIconv() {
870: return function_exists("iconv");
871: }
872:
873: 874: 875: 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: 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: 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: 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: 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: 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: 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: 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: 966: 967: 968: 969:
970: public function testMySQLModeStrict($host, $username, $password) {
971:
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: 993: 994: 995: 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: 1024: 1025: 1026:
1027: public function testFilesystem($testConfig = true, $testFrontend = true) {
1028: global $cfgClient;
1029:
1030: $status = true;
1031:
1032: $files = array(
1033:
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: 1158: 1159: 1160: 1161: 1162: 1163: 1164: 1165: 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 {
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: 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: 1294: 1295: 1296: 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: 1328: 1329: 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: 1357: 1358: 1359:
1360: public function checkSetupMysql($setupType, $databaseName, $databasePrefix) {
1361: switch ($setupType) {
1362: case "setup":
1363:
1364: $db = getSetupMySQLDBConnection(false);
1365:
1366:
1367: $status = checkMySQLDatabaseExists($db, $databaseName);
1368:
1369: if ($status) {
1370:
1371: $db = getSetupMySQLDBConnection();
1372: $db->connect();
1373:
1374:
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:
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:
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:
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:
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:
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:
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:
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:
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: