/** * If it is proven to be a valid SQL Statement worthy of logging, the persistQuery() function will * write the statement to file and log it * @param string $query The SQL Statement that will be saved to file and CDI log */ public static function persistQuery($query) { try { $ts = time(); if(self::$lastEntryTS != $ts) { self::$lastEntryTS = $ts; self::$lastEntryOrder = 0; } else { self::$lastEntryOrder++; } $id = $ts . '-' . self::$lastEntryOrder; $hash = md5($id . $query); $date = date('Y-m-d H:i:s', $ts); try{ //We are only logging this to file because we do not execute CDI queries on the MASTER instance //The database table `tbl_cdi_log` is removed from the database on the MASTER instance. //It is the repsonsibility of the user to ensure that they only have a single MASTER instance //and that they protect the integrity of the Symphony database $entries = CdiLogQuery::getCdiLogEntries(); $entries[$id] = array(0 => $ts, 1 => self::$lastEntryOrder, 2 => $hash, 3 => $query); file_put_contents(CDI_FILE, json_encode($entries)); return true; } catch(Exception $e) { //TODO: think of some smart way of dealing with errors, perhaps through the preference screen or a CDI Status content page? CdiLogQuery::rollback($hash,$ts,$order); return false; } } catch(Exception $e) { //TODO: think of some smart way of dealing with errors, perhaps through the preference screen or a CDI Status content page? return false; } }
/** * The CdiQueryLog::log() function is called from the Database implementation responsible for executing Symphony SQL queries * If in MASTER mode, CDI will save the query to disk allowing it to be committed to the VCS. From there it will be available * for automatic query exection by CDI slave instances (see also CdiLogQuery::executeQueries()). * @param String $query */ public static function log($query) { // Prevent execution on the frontend and check configuration conditions // Do not log the query when CDI is disabled, in SLAVE mode or busy executing queries. // Additionally if the logger is not installed, you should not be able to call this function if((!class_exists('Administration')) || !CdiUtil::isEnabled() || self::$isUpdating) { return true; } $query = trim($query); $tbl_prefix = Symphony::Configuration()->get('tbl_prefix', 'database'); /* FILTERS */ // do not register changes to tbl_cdi_log if (preg_match("/{$tbl_prefix}cdi_log/i", $query)) return true; // only structural changes, no SELECT statements if (!preg_match('/^(insert|update|delete|create|drop|alter|rename)/i', $query)) return true; // un-tracked tables (sessions, cache, authors) if (preg_match("/{$tbl_prefix}(authors|cache|forgotpass|sessions)/i", $query)) return true; // content updates in tbl_entries (includes tbl_entries_fields_*) if (preg_match('/^(insert|delete|update)/i', $query) && preg_match("/({$config->tbl_prefix}entries)/i", $query)) return true; // append query delimeter if it doesn't exist if (!preg_match('/;$/', $query)) $query .= ";"; // Replace the table prefix in the query // This allows query execution on slave instances with different table prefix. $query = str_replace($tbl_prefix,'tbl_',$query); // We've come far enough... let's try to save it to disk! if(CdiUtil::isCdiMaster()) { return CdiMaster::persistQuery($query); } else if(CdiUtil::isCdiDBSyncMaster()) { return CdiDBSync::persistQuery($query); } else { //TODO: error handling for the unusual event that we are dealing with here. return true; } }
require_once(EXTENSIONS . '/cdi/lib/class.cdilogquery.php'); require_once(EXTENSIONS . '/cdi/lib/class.cdipreferences.php'); // We should not be processing any queries when the extension is disabled or when we are the Master instance if((!class_exists('Administration')) || !CdiUtil::isEnabled()) { $result["status"] = "error"; $result["message"] = "You can only execute actions from within Symphony and when the CDI extension is enabled"; Symphony::Log()->pushToLog('[CDI] You can only execute actions from within Symphony and when the CDI extension is enabled', E_NOTICE, true); } // Clean the database and log files when the cdi_clear action is called if(isset($_POST["action"]["cdi_clear"])) { try { if(CdiUtil::isCdiMaster()) { CdiMaster::uninstall(); CdiMaster::install(); } else if (CdiUtil::isCdiSlave()) { CdiSlave::uninstall(); CdiSlave::install(); } else if(CdiUtil::isCdiDBSync()) { CdiDBSync::uninstall(); CdiDBSync::install(); } $result["status"] = 'success'; } catch(Exception $e) { $result["status"] = "error"; $result["message"] = $e->getMessage(); Symphony::Log()->pushToLog('[CDI] ' . $e->getMessage(), E_ERROR, true); } }
public function savePreferences($context){ if(CdiPreferences::save()) { // apply config changes if(CdiUtil::isCdiSlave()) { CdiSlave::install(); } else if (CdiUtil::isCdiMaster()) { CdiMaster::install(); } else { CdiDBSync::install(); } } else { Administration::instance()->Page->pageAlert(_('An unknown error occurred while saving preferences for CDI. Your changes have not been saved.')); return false; } }