示例#1
0
			}

			CdiDumpDB::backup('manual');
			$result["status"] = 'success';
			$result["result"] = htmlspecialchars(CdiPreferences::appendRestore()->generate());
		} catch(Exception $e) {
			$result["status"] = "error";
			$result["message"] = $e->getMessage();
			Symphony::Log()->pushToLog('[CDI] ' . $e->getMessage(), E_ERROR, true);
		}
	} 

	// CDI Restore
	else if(isset($_POST["action"]["cdi_restore"])) {
		try {
			CdiDumpDB::restore();
			$result["status"] = 'success';
		} catch(Exception $e) {
			$result["status"] = "error";
			$result["message"] = $e->getMessage();
			Symphony::Log()->pushToLog('[CDI] ' . $e->getMessage(), E_NOTICE, true);
		}
	} 
	
	// No action? Error!
	else {
	   	$result["status"] = "error";
	   	$result["message"] = "You can only execute actions if you actually post one!";
		Symphony::Log()->pushToLog('[CDI] You can only execute actions if you actually post one!', E_NOTICE, true);
	}
示例#2
0
		public static function appendRestore() {
			$div = new XMLElement('div', NULL,array('style'=>'margin-bottom: 1.5em;','class' => 'cdiRestore'));
			if(CdiUtil::hasDumpDBInstalled()) {
				$div->appendChild(new XMLElement('h3','Restore Symphony database',array('style' => 'margin: 5px 0;')));
				$table = new XMLElement('table', NULL, array('cellpadding' => '0', 'cellspacing' => '0', 'border' => '0', 'style' => 'margin-bottom: 10px;'));
				$files = CdiDumpDB::getBackupFiles();
				if(count($files) > 0) {
					rsort($files);
					foreach($files as $file) {
						$filename = explode('-',$file);
						if($entryCount == 5) { break; }
						$tr = new XMLElement('tr',null);
						$linkbutton = new XMLElement('a',date('d-m-Y H:i:s', (int)$filename[0]),array('href' => URL . '/symphony/extension/cdi/download/?ref=' . $file));
						$tr->appendChild(new XMLElement('td',$linkbutton->generate(),array('width' => '150', 'style' => 'vertical-align:middle;')));
						$tr->appendChild(new XMLElement('td',$filename[1],array('style' => 'vertical-align:middle;')));
						$td = new XMLElement('td',null,array('width' => '75'));
						$button = new XMLElement('input',null, array('value' => 'Restore', 'name' => 'action[cdi_restore]', 'type' => 'button', 'class' => 'cdi_restore_action', 'ref' => $file));
						$td->appendChild($button);
						$tr->appendChild($td);
						$table->appendChild($tr);
						$entryCount++;
					}
				}
				$tr = new XMLElement('tr',null,array('class' => 'cdiNoLastBackupCell'));
				$tr->appendChild(new XMLElement('td','There is no recent Symphony database to restore'));
				if($entryCount != 0) { $tr->setAttribute('style','display: none'); }
				$table->appendChild($tr);
				$div->appendChild($table);

				$uploadContainer = new XMLElement('div',null,array('class' => 'cdiRestoreUpload'));
				if($entryCount != 0) { $uploadContainer->setAttribute('style','display: none'); }
				$span = new XMLElement('span',NULL,array('class' => 'frame'));
				$span->appendChild(new XMLElement('input',NULL,array('name' => 'dumpdb_restore_file', 'type' => 'file')));
				$uploadContainer->appendChild($span);
				
				$button = new XMLElement('div',NULL,array('style' => 'margin: 10px 0;'));
				$button->appendChild(new XMLElement('input',null,array('value' => 'Upload', 'name' => 'action[dumpdb_restore]', 'type' => 'submit', 'class' => 'cdi_import_action')));
				$button->appendChild(new XMLElement('span',' Press "Upload" to restore the Symphony Database.'));
				$uploadContainer->appendChild($button);
				$div->appendChild($uploadContainer);
				
				if($entryCount != 0) {
					$button = new XMLElement('div',NULL,array('style' => 'margin: 0 0 10px 10px;'));
					$button->appendChild(new XMLElement('input', null, array('value' => 'Clear', 'name' => 'action[cdi_clear_restore]', 'type' => 'button', 'class' => 'cdi_clear_restore_action')));
					$button->appendChild(new XMLElement('span',' Press "Clear" to remove all Symphony database backups'));
					$div->appendChild($button);
				}
				
				$div->appendChild(new XMLElement('p', 'Restoring a backup of your Symphony database will replace the entire structure and data of this instance. You can use this to synchronize instances, but be carefull to prevent data loss.', array('class' => 'help')));
			}
			return $div;
		}
示例#3
0
		public function appendPreferences($context){
			// Import the db_sync.sql file when the cdi_import action is called
			// The import action is the only left to require a post-back because AJAX file upload is cumbersome
			if(isset($_POST["action"]["cdi_import"])) {
				CdiDBSync::import();
			} else if(isset($_POST["action"]["dumpdb_restore"])) {
				CdiDumpDB::restore();
			}
			
			// Create the Preferences user-interface for the CDI extension
			$group = new XMLElement('fieldset');
			$group->setAttribute('class', 'cdi settings');
			$group->appendChild(new XMLElement('legend', 'Continuous Database Integration'));
			$group->appendChild(new XMLElement('div', '<span class="image">&#160;</span><span>Processing... please wait.</span>', array('class' => 'help cdiLoading cdiHidden')));
			Administration::instance()->Page->Form->setAttribute('enctype', 'multipart/form-data');
			
			$group->appendChild(CdiPreferences::appendCdiMode());
			if(CdiUtil::isCdi()) {
				$group->appendChild(CdiPreferences::appendCdiPreferences());
			} else if(CdiUtil::isCdiDBSync()) {
				$group->appendChild(CdiPreferences::appendDBSyncPreferences());
			}

			// Append preferences
			$context['wrapper']->appendChild($group);
		}
示例#4
0
		/**
		 * The executeQueries() function will try to execute all SQL statements that are available in the manifest folder.
		 * It will check the CDI log to see if the statement has already been executed based on the MD5 hash.
		 * This function can only be called by SLAVE instances
		 */
		public static function update() {
			// We should not be processing any queries when the extension is disabled or when we are the Master instance
			// Check also exists on content page, but just to be sure!
			if((!class_exists('Administration')) || !CdiUtil::isEnabled() || !CdiUtil::isCdiSlave()) {
				echo "WARNING: CDI is disabled or you are running the queryies on the Master instance. No queries have been executed.";
				return;
			}
	
			// Prevent the CdiLogQuery::log() from persisting queries that are executed by CDI itself
			// Technically this should not be possible because it will not log queries on a SLAVE instance
			// and you can only run the executeQueries when in SLAVE mode. This is just to be sure.
			CdiLogQuery::isUpdating(true);
			
			// Switch to maintenance mode
			if(Symphony::Configuration()->get('maintenance-enabled', 'cdi') == 'yes') {
				Symphony::Configuration()->set('enabled', 'yes', 'maintenance_mode');
				Symphony::Configuration()->write();			
			}
			
			// Implement automatic backup before processing structural changes
			if(Symphony::Configuration()->get('backup-enabled', 'cdi') == 'yes') {
				try {
					if(CdiUtil::hasDumpDBInstalled()) {
						require_once(EXTENSIONS . '/cdi/lib/class.cdidumpdb.php');
						$currentBackup = CdiDumpDB::backup("automatic");
					} else {
						throw new Exception('You can only enable automatic backup files when the "Dump DB" extension (version 1.10 or higher) is installed and enabled.');
					}
				}catch (Exception $e) {
					echo "ERROR: " . $e->getMessage() , ". Failed to backup database before update, aborting.";
					die();
				}
			}
			
			try {
				$skipped = 0;
				$executed = 0;
	
				$entries = CdiLogQuery::getCdiLogEntries();
				foreach($entries as $entry) {
					$ts = $entry[0];
					$order = $entry[1];
					$hash = $entry[2];
					$query = $entry[3];
					$date = date('Y-m-d H:i:s', $ts);
	
					// Replace the table prefix in the query
					// Rename the generic table prefix to the prefix used by this instance
					$tbl_prefix = Symphony::Configuration()->get('tbl_prefix', 'database');
					$query = str_replace('tbl_', $tbl_prefix, $query);
					
					try {
						// Look for available CDI log entries based on the provided MD5 hash
						$cdiLogEntry = Symphony::Database()->fetchRow(0,"SELECT * FROM tbl_cdi_log WHERE `query_hash` LIKE '" . $hash . "'");
						
						if(empty($cdiLogEntry)) {
							// The query has not been found in the log, thus it has not been executed
							// So let's execute the query and add it to the log!
							Symphony::Database()->query("INSERT INTO `tbl_cdi_log` (`query_hash`,`author`,`url`,`date`,`order`)
														 VALUES ('" . $hash . "','" . CdiUtil::getAuthor() . "','" . CdiUtil::getURL() . "','" . $date . "'," . $order . ")");
							Symphony::Database()->query($query);
							$executed++;
						} else {
							// The query has already been executed, let's do nothing;
							$skipped++;
						}
					} catch (Exception $e) {
						//TODO: think of some smart way of dealing with errors, perhaps through the preference screen or a CDI Status content page?
						//Due to the error we need to perform a rollback to allow this query to be executed at a later stage.
						CdiLogQuery::rollback($hash,$ts,$order);
						
						// Implement automatic restore on error
						if((Symphony::Configuration()->get('backup-enabled', 'cdi') == 'yes') &&
						   (Symphony::Configuration()->get('restore-enabled', 'cdi') == 'yes')) {
							try {
								CdiDumpDB::restore($currentBackup);
							}catch (Exception $r) {
								echo "ERROR: " . $r->getMessage() , ". Failed to restore latest database backup. This instance needs immediate attention!";
								die();
							}

							// Restore was succesful, at least we can jump out of maintenance mode
							if(Symphony::Configuration()->get('maintenance-enabled', 'cdi') == 'yes') {
								Symphony::Configuration()->set('enabled', 'no', 'maintenance_mode');
								Symphony::Configuration()->write();
							}
							
							echo "ERROR: " . $e->getMessage() , ". Rollback & Restore have been executed.";
						} else {
							if(Symphony::Configuration()->get('maintenance-enabled', 'cdi') == 'yes') {
								echo "ERROR: " . $e->getMessage() , ". Rollback has been executed. This instance is now in maintenance mode and needs immediate attention!";
							} else {
								echo "ERROR: " . $e->getMessage() , ". Rollback has been executed.";
							}
						}
						
						// Stop processing
						die();
					}
				}
				
				echo "OK: " . $executed . " queries executed, " . $skipped . " skipped.";
			} catch (Exception $e) {
				//TODO: think of some smart way of dealing with errors, perhaps through the preference screen or a CDI Status content page?
				echo "ERROR: " . $e->getMessage();
			}

			// Save the last update date to configuration
			Symphony::Configuration()->set('last-update', time(), 'cdi');
			// No more maintenance mode
			if(Symphony::Configuration()->get('maintenance-enabled', 'cdi') == 'yes') {
				Symphony::Configuration()->set('enabled', 'no', 'maintenance_mode');
			}
			
			Symphony::Configuration()->write();
			
			// Re-enable CdiLogQuery::log() to persist queries
			CdiLogQuery::isUpdating(false);
		}