Файл: IPBMafia.ru_IPB_3.4.6_Final_Rus _Nulled/board/upload/admin/sources/classes/backup.php
Строк: 357
<?php
/**
* <pre>
* Invision Power Services
* IP.Board v3.4.6
* Back Up Model
* Last Updated: $Date: 2012-05-10 21:10:13 +0100 (Thu, 10 May 2012) $
* </pre>
*
* @author Matt Mecham
* @copyright (c) 2001 - 2009 Invision Power Services, Inc.
* @license http://www.invisionpower.com/company/standards.php#license
* @package IP.Board
* @link http://www.invisionpower.com
* @since Tue. 15th June 2012
* @version $Rev: 10721 $
*
*/
/**
* Back up model
* @author matt
*
*/
class ipsBackup
{
/**
* Holds the back-up variables
* @var array
*/
private $Vars = array();
/**
* DB tables and primary keys
* @var array
*/
private $Keys = array();
/**
* Contains list of tables NOT to gather.
* @var array
*/
private $BlackList = array();
/**
* Contains list of tables ONLY to gather.
* @var array
*/
private $WhiteList = array();
/**
* Contains all the schematic info. Use wisely, it can be 'uuuge (700k+)
*/
private $SchematicData = array();
/**
* Limits for the batches
* @var array
*/
private $Limits = array( 'rows' => 0, 'bytes' => 0 );
/**
* Construct
*/
public function __construct()
{
/* Make objects */
$this->registry = ipsRegistry::instance();
$this->DB = $this->registry->DB();
/* Fetch *lists */
$this->BlackList = $this->_getBlackList();
$this->Whitelist = $this->_getWhiteList();
/* Fetch data variables */
$this->Vars = $this->_getVars();
/* Fetch db table pkeys */
$this->Keys = $this->_getKeys();
/* Set default limits for the batch pulling */
$this->setLimits( 'rows', 10000 );
$this->setLimits( 'bytes', 20 * 1024 * 1024 );
}
/**
* Add an insert/delete/update/replace query to our log
* @param string $query
* @param string $table
*/
public function addRawQueryToLog( $query, $table )
{
/* This would be LOLs */
if ( $this->backUpRunning() && ! stristr( 'insert into ' . $this->registry->dbFunctions()->getPrefix() . 'backup_queue', $query ) )
{
$this->DB->insert( 'backup_queue', array( 'queue_entry_date' => IPS_UNIX_TIME_NOW,
'queue_entry_type' => 5,
'queue_entry_table' => $this->_stripPrefix( $table ),
'queue_entry_sql' => $query ) );
}
}
/**
* Is the back up system ready to process queries?
*
*/
public function backUpRunning()
{
return ( $this->Vars['populate_all_done'] > 0 ) ? true : false;
}
/**
* Does it need to reset?
*
*/
public function checkForRestart()
{
/* Eventually we'll expand the system so it can be pinged to see if a restart is needed but for now... */
return ( ! $this->Vars['populate_all_done'] ) ? true : false;
}
/**
* Send batch to the backup server
*/
public function sendBatch()
{
/* Fetch kernel class */
require_once( IPS_KERNEL_PATH . 'classFileManagement.php' );
$cfm = new classFileManagement();
/* Fetch DB data */
$tables = $this->_getDatabaseSchematics();
$sqlRows = array();
$touchedTables = array();
$bytesUsed = '';
$topId = 0;
$delIds = array();
/* Do we need to restart? */
if ( $this->checkForRestart() )
{
$this->populateLogWithAllTables();
return true;
}
/* Little short cut */
$p = $this->registry->dbFunctions()->getPrefix();
/* Start looping on the table */
$this->DB->build( array( 'select' => '*',
'from' => 'backup_queue',
'order' => 'queue_id',
'limit' => array( 0, $this->Limits['rows'] ) ) );
$o = $this->DB->execute();
while( $row = $this->DB->fetch( $o ) )
{
$tbl = $this->_stripPrefix( $row['queue_entry_table'] );
$sql = '';
$fields = array();
$touchedTables[ $tbl ] = $tbl;
if ( $row['queue_entry_sql'] )
{
$sql = $row['queue_entry_sql'];
}
else
{
/* Get fields */
foreach( $tables[ $row['queue_entry_table'] ]['cols'] as $col )
{
$fields[] = $col['Field'];
}
if ( ! count( $fields ) )
{
/* Empty - so remove this queue row or we'll never progress */
$delIds[] = $row['queue_id'];
continue;
}
/* INSERT */
if ( $row['queue_entry_type'] == 1 )
{
/* Get data */
$pKey = $row['queue_entry_key'];
$pKeyVal = ( $this->_isConcat( $pKey ) ) ? addslashes( $row['queue_entry_value'] ) : $row['queue_entry_value'];
$data = array();
$vals = array();
$data = $this->DB->buildAndFetch( array( 'select' => '`' . implode( "`, `", $fields ) . '`',
'from' => $tbl,
'where' => $pKey . "='" . $pKeyVal . "'" ) );
if ( ! is_array( $data ) OR ! count( $data ) )
{
/* Empty - so remove this queue row or we'll never progress */
$delIds[] = $row['queue_id'];
continue;
}
foreach( $data as $k => $v )
{
$vals[] = $this->_makeValueSafeForQuery( $v );
}
$sql = "INSERT INTO " . $p . $tbl . "(`" . implode( "`, `", $fields ). "`) " .
"VALUES( '" . implode( "', '", $vals ) . "');";
}
}
/* Got anything? */
if ( ! $sql )
{
/* Empty - so remove this queue row or we'll never progress */
$delIds[] = $row['queue_id'];
continue;
}
/* check size */
$bytesUsed += IPSLib::strlenToBytes( strlen( $sql ) );
/* Truth time! */
if ( $bytesUsed >= $this->Limits['bytes'] )
{
break;
}
else
{
$sqlRows[] = $sql;
/* top id to remove */
$topId = $row['queue_id'];
}
}
/* Anything to delete? */
if ( count( $delIds ) )
{
$this->DB->delete( 'backup_queue', 'queue_id IN (' . implode( ',', array_values( $delIds ) ) . ')' );
}
/* What do we have? */
if ( $topId && count( $sqlRows ) )
{
$dataToSend = $this->_createTextToSend( $sqlRows, array_keys( $touchedTables ) );
$returnedData = $cfm->postFileContents( $this->_getBackupServerUrl(), array( 'backup_data' => @gzcompress( $dataToSend ), 'lkey' => ipsRegistry::$settings['ipb_reg_number'] ) );
$test = json_decode( trim( $returnedData ), true );
if ( is_array( $test ) && $test['status'] == 'ok' )
{
$this->DB->delete( 'backup_queue', 'queue_id <= ' . intval( $topId ) );
$this->_addLog( intval( $test['rows'] ), $test['status'] );
$this->Vars['rows_sent'] = intval( $this->Vars['rows_sent'] ) + count( $sqlRows );
$this->Vars['rows_total'] = $this->_getStoredRowCount();
$this->_setVars();
}
else
{
# Fail lol
$this->_addLog( 0, $test['status'] );
}
}
}
/**
* Do the first run
* This will reset the system and re-populate the entire log table - USE WITH CAUTION!
*/
public function populateLogWithAllTables( $tablesToIndex=300 )
{
$lastTable = $this->Vars['populate_all_last_table'];
$lastProc = '';
/* Reset the system if not middle of processing */
if ( ! $lastTable )
{
$this->_resetSystem();
}
/* Little short cut */
$p = $this->registry->dbFunctions()->getPrefix();
/* Lets go */
foreach( $this->Keys as $table => $pKey )
{
/* Seek to the first unindexed table */
if ( ! $lastProc )
{
if ( $lastTable and $table != $lastTable )
{
continue;
}
if ( ( $lastTable == $table ) || ! $lastTable )
{
$lastProc = $table;
}
}
$this->DB->allow_sub_select = 1;
$pKeyText = ( $this->_isConcat( $pKey ) ) ? addslashes( $pKey ) : $pKey;
/* Fetch, then */
$this->DB->query( 'INSERT INTO ' . $p . 'backup_queue (queue_entry_date, queue_entry_type, queue_entry_table, queue_entry_key, queue_entry_value, queue_entry_sql)' .
"( SELECT UNIX_TIMESTAMP(), 1, '" . $table . "', '" . $pKeyText . "', " . $pKey . ", '' FROM " . $table . " )" );
$this->Vars['populate_all_last_table'] = $table;
$this->_setVars();
}
/* We are all done */
if ( ( $lastTable && $lastProc == $this->Vars['populate_all_last_table'] ) OR ! $lastProc OR ( $tablesToIndex >= count( $this->Keys ) ) )
{
$this->Vars['rows_sent'] = 0;
$this->Vars['rows_total'] = $this->_getStoredRowCount();
$this->Vars['populate_all_done'] = IPS_UNIX_TIME_NOW;
$this->Vars['populate_all_last_table'] = '';
$this->_setVars();
}
}
/**
* Ok to fetch the table data?
* @param string $table
*/
public function isOkToGetThisTableData( $table )
{
$table = $this->_stripPrefix( $table );
if ( count( $this->Whitelist ) )
{
if ( in_array( $table, $this->Whitelist ) )
{
return true;
}
}
return ( $this->_isBlackListTable( $table ) ) ? false : true;
}
/**
* Rebuilds the cache file so we can find out a little about the database structure
*/
public function rebuildPrimaryKeyCacheFile()
{
$cache = array();
$schematic = $this->_getDatabaseSchematics();
foreach( $schematic as $table => $data )
{
$hasKey = false;
if ( count( $data['idx'] ) )
{
foreach( $data['idx'] as $idx )
{
if ( $idx['Key_name'] == 'PRIMARY' )
{
$cache[ $table ] = $idx['Column_name'];
$hasKey = true;
break;
}
}
}
if ( ! $hasKey )
{
/* Lets make a key */
$c = 0;
$concat = array();
foreach( $data['cols'] as $col )
{
if ( strtolower( $col['Type'] ) != 'mediumtext' )
{
if ( stristr( strtolower( $col['Type'] ), 'int(' ) )
{
$concat[] = $col['Field'];
}
else
{
$concat[] = 'SUBSTR(' . $col['Field'] . ', 1, 32)';
}
$c++;
}
if ( $c > 5 )
{
break;
}
}
$cache[ $table ] = 'CONCAT_WS( ',', ' . implode( ',', $concat ) . ' )';
}
}
$contents = '<' . "?phpn" . '$keyCache = ' . var_export( $cache, true ) . ';' . "n?" . '>';
if ( ! file_put_contents( $this->_getBackUpKeyCacheFilename(), $contents ) )
{
trigger_error( 'Не удалось записать файл кэша системы резервного копирования' );
}
/* Reset table pkeys */
$this->Keys = $this->_getKeys();
}
/**
* Set a per batch limit
* @param string $key
* @param string $value
*/
public function setLimits( $key, $value )
{
switch( $key )
{
case 'row':
case 'pergo':
case 'rows':
$this->Limits['rows'] = $value;
break;
case 'bytes':
case 'b':
$this->Limits['bytes'] = $value;
break;
case 'kb':
$this->Limits['bytes'] = $value * 1024;
break;
case 'mb':
$this->Limits['bytes'] = $value * 1024 * 1024;
break;
}
}
/**
* Get the number of rows in the queue table
* @return int, yo
*/
private function _getStoredRowCount()
{
$count = $this->DB->buildAndFetch( array( 'select' => 'count(*) as tnuoc', 'from' => 'backup_queue' ) );
return $count['tnuoc'];
}
/**
* Resets the system and preps for re-logging all
*/
private function _resetSystem()
{
/* Reset */
$this->Vars['populate_all_start'] = IPS_UNIX_TIME_NOW;
$this->Vars['populate_all_done'] = 0;
$this->Vars['populate_all_last_table'] = '';
$this->_setVars();
/* Delete current logs */
$this->DB->delete('backup_queue');
$this->DB->delete('backup_log');
/* Rebuild cache file */
$this->rebuildPrimaryKeyCacheFile();
}
/**
* Gets the database keys
* @return array
*/
private function _getKeys()
{
$keyCache = array();
if ( ! is_file( $this->_getBackUpKeyCacheFilename() ) )
{
$this->rebuildPrimaryKeyCacheFile();
}
include( $this->_getBackUpKeyCacheFilename() );
return $keyCache;
}
/**
* Gets the vars from the deebee
* @return array:
*/
private function _getVars()
{
$vars = array();
$db = $this->DB->buildAndFetchAll( array( 'select' => '*',
'from' => 'backup_vars' ) );
if ( is_array( $db ) )
{
foreach( $db as $var )
{
$vars[ $var['backup_var_key'] ] = $var['backup_var_value'];
}
}
if( !isset($vars['populate_all_done']) )
{
$vars['populate_all_done'] = 0;
}
return $vars;
}
/**
* Update the variables
*/
private function _setVars()
{
foreach( $this->Vars as $k => $v )
{
$this->DB->replace( 'backup_vars',array( 'backup_var_key' => $k, 'backup_var_value' => $v ), array( 'backup_var_key' ) );
}
}
/**
* Removes table prefix if one exists
* @param string $table
* @return string
*/
private function _stripPrefix( $table )
{
if ( $this->registry->dbFunctions()->getPrefix() && preg_match( "/^" . $this->registry->dbFunctions()->getPrefix() ."/i", $table ) )
{
$table = preg_replace( "/^" . $this->registry->dbFunctions()->getPrefix() ."(.*)$/i", '1', $table );
}
return $table;
}
/**
* Returns ignored tables
*/
private function _getWhiteList()
{
return array();
}
/**
* Returns ignored tables
*/
private function _getBlackList()
{
/* @todo abstract this puppy */
return array( 'admin_login_logs',
'admin_logs',
'api_log',
'backup_log',
'backup_queue',
'backup_vars',
'blog_askimet_logs',
'blog_trackback_spamlogs',
'blog_views',
'chat_log_archive',
'content_cache_posts',
'content_cache_sigs',
'core_editor_autosave',
'core_item_markers',
'core_like_cache',
'core_share_links_caches',
'core_share_links_log',
'core_tags_cache',
'error_logs',
'gallery_image_views',
'mail_error_logs',
'moderator_logs',
'profile_friends_flood',
'profile_portal_views',
'reputation_cache',
'search_sessions',
'sessions',
'skin_cache',
'skin_templates_cache',
'spam_service_log',
'spider_logs',
'task_logs',
'topic_views' );
}
/**
* Return database schematic information
*/
private function _getDatabaseSchematics()
{
if ( count( $this->SchematicData ) )
{
return $this->SchematicData;
}
$this->DB->query( "SHOW TABLE STATUS FROM `" . $this->registry->dbFunctions()->getDatabaseName() . "`" );
/* Loop through the results */
$this->SchematicData = array();
while( $row = $this->DB->fetch() )
{
/* Check to ensure it's a table for this install... */
if ( $this->registry->dbFunctions()->getPrefix() && ! preg_match( "/^" . $this->registry->dbFunctions()->getPrefix() ."/i", $row['Name'] ) )
{
continue;
}
if ( ! $this->isOkToGetThisTableData( $row['Name'] ) )
{
continue;
}
/* Add to output array */
$this->SchematicData[ $row['Name'] ] = array( 'cols' => array(), 'idx' => array(), 'data' => $row );
}
/* Now fetch table information */
foreach( $this->SchematicData as $name => $data )
{
/* Fetch data */
$this->DB->query( "DESCRIBE " . $name );
while( $row = $this->DB->fetch() )
{
$this->SchematicData[ $name ]['cols'][] = $row;
}
/* Fetch index data */
$this->DB->query( "SHOW INDEX FROM `" . $this->registry->dbFunctions()->getDatabaseName() . "`.`" . $name . "`" );
while( $row = $this->DB->fetch() )
{
$this->SchematicData[ $name ]['idx'][] = $row;
}
}
return $this->SchematicData;
}
/**
* Check to see if this is an ignored table
* @param string $table
*/
private function _isBlackListTable( $table )
{
return ( in_array( $table, $this->BlackList ) ) ? true : false;
}
/**
* Add slashes to single quotes to stop sql breaks
*
* @param string $value String to add slashes too
* @return string
*/
private function _makeValueSafeForQuery( $value )
{
return $this->DB->addSlashes( $value );
}
/**
* @param string $str
* @return boolean
*/
private function _isConcat( $str )
{
return ( substr( $str, 0, 10 ) == 'CONCAT_WS(' ) ? true : false;
}
/**
* Creates the post text
* @param string $sqlData
*/
private function _createTextToSend( $sqlData, $touchedTables=null )
{
$tables = $this->_getDatabaseSchematics();
$tblsToSend = array();
$tblsToCreate = array();
$schematic = '';
/* Little short cut */
$p = $this->registry->dbFunctions()->getPrefix();
if ( is_array( $touchedTables ) )
{
foreach( $touchedTables as $tbl )
{
/* $touchedTables has no prefix */
$tblsToSend[ $p . $tbl ] = $tables[ $p . $tbl ];
$this->DB->query( "SHOW CREATE TABLE " . $p . $tbl );
$_f = $this->DB->fetch();
$tblsToCreate[] = str_replace( array( "n", "r" ), "n", $_f['Create Table'] );
}
}
$document = serialize( array( 'tableData' => $tblsToSend, 'createTables' => $tblsToCreate, 'sql' => $sqlData, 'vars' => $this->Vars ) );
return $document;
}
/**
* Should be face-smashingly obvious.
* @return string
*/
private function _getBackUpKeyCacheFilename()
{
return IPS_CACHE_PATH . 'cache/backUpKeyCache.php';
}
/**
* Gets the backup server URL (clearly)
* @return string
*/
private function _getBackupServerUrl()
{
return 'http://gateway.backuptest.lw.ipslink.com/index.php';
}
/**
* Adds a log to the back up system
* @param int $rows
* @param string $status
*/
private function _addLog( $rows, $status )
{
$this->DB->insert( 'backup_log', array( 'log_row_count' => $rows, 'log_result' => $status ) );
}
}