| 1 | <?php
 | 
  
    | 2 | 
 | 
  
    | 3 | /**
 | 
  
    | 4 |  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 | 
  
    | 5 |  *
 | 
  
    | 6 |  * This program is free software: you can redistribute it and/or modify
 | 
  
    | 7 |  * it under the terms of the GNU General Public License as published by
 | 
  
    | 8 |  * the Free Software Foundation, either version 3 of the License, or
 | 
  
    | 9 |  * (at your option) any later version.
 | 
  
    | 10 |  *
 | 
  
    | 11 |  * This program is distributed in the hope that it will be useful,
 | 
  
    | 12 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
  
    | 13 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
  
    | 14 |  * GNU General Public License for more details.
 | 
  
    | 15 |  *
 | 
  
    | 16 |  * You should have received a copy of the GNU General Public License
 | 
  
    | 17 |  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
  
    | 18 |  */
 | 
  
    | 19 | 
 | 
  
    | 20 | /**
 | 
  
    | 21 |  * UpgradeHelper.php
 | 
  
    | 22 |  *
 | 
  
    | 23 |  * @category     Core
 | 
  
    | 24 |  * @package      Core_Upgrade
 | 
  
    | 25 |  * @copyright    Werner v.d.Decken <wkl@isteam.de>
 | 
  
    | 26 |  * @author       Werner v.d.Decken <wkl@isteam.de>
 | 
  
    | 27 |  * @license      http://www.gnu.org/licenses/gpl.html   GPL License
 | 
  
    | 28 |  * @version      0.0.1
 | 
  
    | 29 |  * @revision     $Revision: $
 | 
  
    | 30 |  * @link         $HeadURL: $
 | 
  
    | 31 |  * @lastmodified $Date: $
 | 
  
    | 32 |  * @since        File available since 17.03.2013
 | 
  
    | 33 |  * @description  some helper function for upgrade-script.php
 | 
  
    | 34 |  */
 | 
  
    | 35 | class UpgradeHelper {
 | 
  
    | 36 | 
 | 
  
    | 37 | /**
 | 
  
    | 38 |  * Compare available tables against a list of tables
 | 
  
    | 39 |  * @param  array list of needed table names without TablePrefix
 | 
  
    | 40 |  * @return array list of missing tables
 | 
  
    | 41 |  * @description this method is the replaement for self::existsAllTables()
 | 
  
    | 42 |  */
 | 
  
    | 43 | 	public static function getMissingTables(array $aTablesList)
 | 
  
    | 44 | 	{
 | 
  
    | 45 | 		$aTablesList = array_flip($aTablesList);
 | 
  
    | 46 | 		$oDb = WbDatabase::getInstance();
 | 
  
    | 47 | 		$sPattern = addcslashes ( $oDb->TablePrefix, '%_' );
 | 
  
    | 48 | 		if (($oTables = $oDb->query( 'SHOW TABLES LIKE "'.$sPattern.'%"'))) {
 | 
  
    | 49 | 			while ($aTable = $oTables->fetchRow(MYSQL_NUM)) {
 | 
  
    | 50 | 				$sTable =  preg_replace('/^'.preg_quote($oDb->TablePrefix, '/').'/s', '', $aTable[0]);
 | 
  
    | 51 | 				if (isset($aTablesList[$sTable])) {
 | 
  
    | 52 | 					unset($aTablesList[$sTable]);
 | 
  
    | 53 | 				}
 | 
  
    | 54 | 			}
 | 
  
    | 55 | 		}
 | 
  
    | 56 | 		return array_flip($aTablesList);
 | 
  
    | 57 | 	}
 | 
  
    | 58 | /**
 | 
  
    | 59 |  * Alias for self::getMissingTables()
 | 
  
    | 60 |  * @param array list of needed table names without TablePrefix
 | 
  
    | 61 |  * @return array list of missing tables
 | 
  
    | 62 |  */
 | 
  
    | 63 | 	public static function existsAllTables(array $aTablesList)
 | 
  
    | 64 | 	{
 | 
  
    | 65 | 		return self::getMissingTables($aTablesList);
 | 
  
    | 66 | 	}
 | 
  
    | 67 | /**
 | 
  
    | 68 |  * Sanitize and repair Pagetree links
 | 
  
    | 69 |  * @return boolean|int number of updated records or false on error
 | 
  
    | 70 |  */
 | 
  
    | 71 | 	public static function sanitizePagesTreeLinkStructure()
 | 
  
    | 72 | 	{
 | 
  
    | 73 | 		$oDb = WbDatabase::getInstance();
 | 
  
    | 74 | 		$iCounter = 0;
 | 
  
    | 75 | 		$aPages = array();
 | 
  
    | 76 | 		try {
 | 
  
    | 77 | 			$sql = 'SELECT `page_id`, `link`, `page_trail` '
 | 
  
    | 78 | 				 . 'FROM `'.$oDb->TablePrefix.'pages` '
 | 
  
    | 79 | 				 . 'ORDER BY `page_id`';
 | 
  
    | 80 | 			$oPages = $oDb->doQuery($sql);
 | 
  
    | 81 | 			// read 'page_id', 'link' and 'page_trail' from all pages
 | 
  
    | 82 | 			while ($aPage = $oPages->fetchRow(MYSQL_ASSOC)) {
 | 
  
    | 83 | 				// extact filename only from complete link
 | 
  
    | 84 | 				$aPages[$aPage['page_id']]['filename'] = preg_replace('/.*?\/([^\/]*$)/', '\1', $aPage['link']);
 | 
  
    | 85 | 				$aPages[$aPage['page_id']]['page_trail'] = $aPage['page_trail'];
 | 
  
    | 86 | 				$aPages[$aPage['page_id']]['link'] = $aPage['link'];
 | 
  
    | 87 | 			}
 | 
  
    | 88 | 			foreach ($aPages as $iKey=>$aRecord) {
 | 
  
    | 89 | 			// iterate all pages
 | 
  
    | 90 | 				$aTmp = array();
 | 
  
    | 91 | 				$aIds = explode(',', $aRecord['page_trail']);
 | 
  
    | 92 | 				// rebuild link from filenames using page_trail
 | 
  
    | 93 | 				foreach($aIds as $iId) {
 | 
  
    | 94 | 					$aTmp[] = $aPages[$iId]['filename'];
 | 
  
    | 95 | 				}
 | 
  
    | 96 | 				$sLink = '/'.implode('/', $aTmp);
 | 
  
    | 97 | 				if ($sLink != $aPages[$iKey]['link']) {
 | 
  
    | 98 | 				// update page if old link is different to new generated link
 | 
  
    | 99 | 					$sql = 'UPDATE `'.$oDb->TablePrefix.'pages` '
 | 
  
    | 100 | 						 . 'SET `link`=\''.$sLink.'\' '
 | 
  
    | 101 | 						 . 'WHERE `page_id`='.$iKey;
 | 
  
    | 102 | 					$oDb->doQuery($sql);
 | 
  
    | 103 | 					$iCounter++;
 | 
  
    | 104 | 				}
 | 
  
    | 105 | 			}
 | 
  
    | 106 | 		} catch(WbDatabaseException $e) {
 | 
  
    | 107 | 			return false;
 | 
  
    | 108 | 		}
 | 
  
    | 109 | 		return $iCounter;
 | 
  
    | 110 | 	}
 | 
  
    | 111 | /**
 | 
  
    | 112 |  *
 | 
  
    | 113 |  * @param string $sMsg Message to show
 | 
  
    | 114 |  */
 | 
  
    | 115 | 	public static function dieWithMessage($sMsg)
 | 
  
    | 116 | 	{
 | 
  
    | 117 | 		$sMsg = 'Fatal error occured during initial startup.<br /><br />'.PHP_EOL.$sMsg
 | 
  
    | 118 | 			  . '<br />'.PHP_EOL.'Please correct these errors and then '
 | 
  
    | 119 | 			  . '<a href="http://'.$_SERVER["HTTP_HOST"].$_SERVER["SCRIPT_NAME"].'" '
 | 
  
    | 120 | 			  . 'title="restart">klick here to restart the upgrade-script</a>.<br />'.PHP_EOL;
 | 
  
    | 121 | 		die($sMsg);
 | 
  
    | 122 | 	}
 | 
  
    | 123 | /**
 | 
  
    | 124 |  *
 | 
  
    | 125 |  * @param string $sAppPath path to the current installation
 | 
  
    | 126 |  * @return boolean
 | 
  
    | 127 |  */
 | 
  
    | 128 | 	public static function checkSetupFiles($sAppPath)
 | 
  
    | 129 | 	{
 | 
  
    | 130 | 		if (defined('DB_PASSWORD')) {
 | 
  
    | 131 | 		// old config.php is active
 | 
  
    | 132 | 			if (!is_writable($sAppPath.'config.php') || !is_writable($sAppPath.'config.php.new') || !is_writable($sAppPath.'setup.ini.php.new'))
 | 
  
    | 133 | 			{
 | 
  
    | 134 | 			// stop script if there's an error occured
 | 
  
    | 135 | 				$sMsg = 'Following files must exist and be writable to run upgrade:<br />'
 | 
  
    | 136 | 				      . '<ul><li>config.php</li>'.(file_exists($sAppPath.'config.php.new') ? '<li>config.php.new</li>' : '')
 | 
  
    | 137 | 				      . '<li>setup.ini.php.new</li></ul>';
 | 
  
    | 138 | 				self::dieWithMessage($sMsg);
 | 
  
    | 139 | 			} else { // ok, let's change the files now!
 | 
  
    | 140 | 				if (file_exists($aAppPath.'setup.ini.php')) {
 | 
  
    | 141 | 				// if 'setup.ini.php' exists
 | 
  
    | 142 | 					if (!is_writeable($aAppPath.'setup.ini.php')) {
 | 
  
    | 143 | 					// but it's not writable
 | 
  
    | 144 | 						$sMsg = 'The file \'setup.ini.php\' already exists but is not writeable!';
 | 
  
    | 145 | 						self::dieWithMessage($sMsg);
 | 
  
    | 146 | 					}
 | 
  
    | 147 | 				} else {
 | 
  
    | 148 | 				// try to rename 'setup.ini.php.new' into 'setup.ini.php'
 | 
  
    | 149 | 					if (!rename($aAppPath.'setup.ini.php.new', $aAppPath.'setup.ini.php')) {
 | 
  
    | 150 | 						$sMsg = 'Can not rename \''.$aAppPath.'setup.ini.php.new\' into \''.$aAppPath.'setup.ini.php\' !!<br />'
 | 
  
    | 151 | 						      . 'Create an empty file \''.$aAppPath.'setup.ini.php\' and make it writeable for the server!';
 | 
  
    | 152 | 						self::dieWithMessage($sMsg);
 | 
  
    | 153 | 					}
 | 
  
    | 154 | 				}
 | 
  
    | 155 | 			// now first read constants from old config.php
 | 
  
    | 156 | 				$sContent = file_get_contents($sAppPath.'config.php');
 | 
  
    | 157 | 				$sPattern = '/^\s*define\s*\(\s*([\'\"])(.*?)\1\s*,.*;\s*$/m';
 | 
  
    | 158 | 				if (preg_match_all($sPattern, $sContent, $aMatches)) {
 | 
  
    | 159 | 				// get all already defined consts
 | 
  
    | 160 | 					$aAllConsts = get_defined_constants(true);
 | 
  
    | 161 | 					$aSetupConsts = array();
 | 
  
    | 162 | 				// collect the needed values from defined consts
 | 
  
    | 163 | 					foreach($aMatches[2] as $sConstName) {
 | 
  
    | 164 | 						$aSetupConsts[$sConstName] = (isset($aAllConsts['user'][$sConstName]) ? $aAllConsts['user'][$sConstName] : '');
 | 
  
    | 165 | 					}
 | 
  
    | 166 | 				// try to sanitize available values
 | 
  
    | 167 | 					$aSetupConsts['DB_TYPE'] = ((isset($aSetupConsts['DB_TYPE']) && $aSetupConsts['DB_TYPE'] != '') ? $aSetupConsts['DB_TYPE'] : 'mysql');
 | 
  
    | 168 | 					$aSetupConsts['DB_PORT'] = ((isset($aSetupConsts['DB_PORT']) && $aSetupConsts['DB_PORT'] != '') ? $aSetupConsts['DB_PORT'] : '3306');
 | 
  
    | 169 | 					$aSetupConsts['DB_CHARSET'] = (isset($aSetupConsts['DB_CHARSET']) ? $aSetupConsts['DB_CHARSET'] : '');
 | 
  
    | 170 | 					$aSetupConsts['DB_CHARSET'] = preg_replace('/[^0-9a-z]*/i', '', $aSetupConsts['DB_CHARSET']);
 | 
  
    | 171 | 					$aSetupConsts['TABLE_PREFIX'] = (isset($aSetupConsts['TABLE_PREFIX']) ? $aSetupConsts['TABLE_PREFIX'] : '');
 | 
  
    | 172 | 					$aSetupConsts['ADMIN_DIRECTORY'] = trim(str_replace('\\', '/', preg_replace('/^'.preg_quote(WB_PATH, '/').'/', '', ADMIN_PATH)), '/').'/';
 | 
  
    | 173 | 					$aSetupConsts['WB_URL'] = rtrim(str_replace('\\', '/', WB_URL), '/').'/';
 | 
  
    | 174 | 				// Try and write settings to config file
 | 
  
    | 175 | 					if (writeSetupIni($sAppPath, $aSetupConsts)) {
 | 
  
    | 176 | 						if (writeConfig($sAppPath)) {
 | 
  
    | 177 | 							return true;
 | 
  
    | 178 | 						} else {
 | 
  
    | 179 | 							$sMsg ='Error writing \''.$sAppPath.'config.php\'!';
 | 
  
    | 180 | 						}
 | 
  
    | 181 | 					} else {
 | 
  
    | 182 | 						$sMsg ='Error writing \''.$sAppPath.'setup.ini.php\'!';
 | 
  
    | 183 | 					}
 | 
  
    | 184 | 				} else {
 | 
  
    | 185 | 					$sMsg = 'No valid content found in \''.$sAppPath.'config.php\'!';
 | 
  
    | 186 | 				}
 | 
  
    | 187 | 				self::dieWithMessage($sMsg);
 | 
  
    | 188 | 			}
 | 
  
    | 189 | 		} else {
 | 
  
    | 190 | 			$sFileContent = file_get_contents($sAppPath.'config.php');
 | 
  
    | 191 | 			if (preg_match('/\s*define\s*\(.*\)\s*;/i', $sFileContent)) {
 | 
  
    | 192 | 			// if config.php does not contain any defines
 | 
  
    | 193 | 				if (is_writable($sAppPath.'config.php')) {
 | 
  
    | 194 | 				// overwrite config.php with default content for compatibility
 | 
  
    | 195 | 					if (self::writeConfig($sAppPath.'config.php')) {
 | 
  
    | 196 | 						return true;
 | 
  
    | 197 | 					} else  {
 | 
  
    | 198 | 						$sMsg ='Error writing \''.$sAppPath.'config.php\'!';
 | 
  
    | 199 | 					}
 | 
  
    | 200 | 				} else {
 | 
  
    | 201 | 					$sMsg ='File is not writable \''.$sAppPath.'config.php\'!';
 | 
  
    | 202 | 				}
 | 
  
    | 203 | 				self::dieWithMessage($sMsg);
 | 
  
    | 204 | 			}
 | 
  
    | 205 | 		}
 | 
  
    | 206 | 	}
 | 
  
    | 207 | /**
 | 
  
    | 208 |  *
 | 
  
    | 209 |  * @param string $sAppPath the path where setup.ini.php is located
 | 
  
    | 210 |  * @param array  $aSetupValues
 | 
  
    | 211 |  * @return boolean
 | 
  
    | 212 |  */
 | 
  
    | 213 | 	public static function writeSetupIni($sAppPath, array $aSetupValues)
 | 
  
    | 214 | 	{
 | 
  
    | 215 | 		$sSetupContent =
 | 
  
    | 216 | 			";<?php die('sorry, illegal file access'); ?>#####\n"
 | 
  
    | 217 | 		   .";################################################\n"
 | 
  
    | 218 | 		   ."; WebsiteBaker configuration file\n"
 | 
  
    | 219 | 		   ."; auto generated ".date('Y-m-d h:i:s A e ')."\n"
 | 
  
    | 220 | 		   .";################################################\n"
 | 
  
    | 221 | 		   ."[Constants]\n"
 | 
  
    | 222 | 		   ."DEBUG   = false\n"
 | 
  
    | 223 | 		   ."AppUrl  = \"".$aSetupValues['WB_URL']."\"\n"
 | 
  
    | 224 | 		   ."AcpDir  = \"".$aSetupValues['ADMIN_DIRECTORY']."\"\n"
 | 
  
    | 225 | 		   .";##########\n"
 | 
  
    | 226 | 		   ."[DataBase]\n"
 | 
  
    | 227 | 		   ."type    = \"".$aSetupValues['DB_TYPE']."\"\n"
 | 
  
    | 228 | 		   ."user    = \"".$aSetupValues['DB_USERNAME']."\"\n"
 | 
  
    | 229 | 		   ."pass    = \"".$aSetupValues['DB_PASSWORD']."\"\n"
 | 
  
    | 230 | 		   ."host    = \"".$aSetupValues['DB_HOST']."\"\n"
 | 
  
    | 231 | 		   ."port    = \"".$aSetupValues['DB_PORT']."3306\"\n"
 | 
  
    | 232 | 		   ."name    = \"".$aSetupValues['DB_NAME']."\"\n"
 | 
  
    | 233 | 		   ."charset = \"".$aSetupValues['DB_CHARSET']."\"\n"
 | 
  
    | 234 | 		   ."table_prefix = \"".$aSetupValues['TABLE_PREFIX']."\"\n"
 | 
  
    | 235 | 		   .";\n"
 | 
  
    | 236 | 		   .";################################################\n";
 | 
  
    | 237 | 		$sSetupFile = $sAppPath.'setup.ini.php';
 | 
  
    | 238 | 		if (file_put_contents($sSetupFile, $sSetupContent)) {
 | 
  
    | 239 | 			return true;
 | 
  
    | 240 | 		}
 | 
  
    | 241 | 		return false;
 | 
  
    | 242 | 	}
 | 
  
    | 243 | /**
 | 
  
    | 244 |  * 
 | 
  
    | 245 |  * @param string $sAppPath the path where config.php is located
 | 
  
    | 246 |  * @return boolean
 | 
  
    | 247 |  */
 | 
  
    | 248 | 	public static function writeConfig($sAppPath)
 | 
  
    | 249 | 	{
 | 
  
    | 250 | 		$sConfigContent = "<?php\n"
 | 
  
    | 251 | 			."/* this file is for backward compatibility only */\n"
 | 
  
    | 252 | 			."/* never put any code in this file! */\n"
 | 
  
    | 253 | 			."include_once(dirname(__FILE__).'/framework/initialize.php');\n";
 | 
  
    | 254 | 		$sConfigFile = $sAppPath.'config.php';
 | 
  
    | 255 | 		if (file_put_contents($sConfigFile, $sConfigContent)) {
 | 
  
    | 256 | 			return true;
 | 
  
    | 257 | 		}
 | 
  
    | 258 | 		return false;
 | 
  
    | 259 | 	}
 | 
  
    | 260 | 
 | 
  
    | 261 | } // end of class UpgradeHelper
 | 
  
    | 262 | 
 |