<?php

class Backup {

	var $connection;

	var $host;

	var $user;

	var $pwd;

    /**
     * database name
     */
    var $dbName;

    /**
     * file name where backup will be placed
     */
    var $fileName;

    /**
     * database prefix
     */
    var $prefix;

    /**
     * constructor
     * make connection to mysql database server and initialize some variables
     *
     * @param string $host
     * @param string $user
     * @param string $pwd
     * @param string $db (database name)
     * @param string $prefix (database prefix)
     *
     * @return boolean
     */
    function Backup($host, $user, $pwd, $db, $prefix) {
        $this->connection = @mysql_connect($host, $user, $pwd);

        if (!is_resource($this->connection)) {
        	return false;
        }

        $this->host = $host;
        $this->user = $user;
        $this->pwd	= $pwd;

        if (!@mysql_select_db($db, $this->connection)) {
        	$this->close_connection();

        	return false;
        }

        $this->dbName = $db;
        $this->prefix = $prefix;

        return true;
    }

    /**
     * set file name for dump file
     *
     * @param string $fileName
     * @return void
     */
    function setFileName($fileName) {
        $this->fileName = $fileName;
    }

    /**
     * create mysql dump
     *
     * @param string $fileName
     * @return void
     */
    function create() {
        $tables			= $this->_getTables();
        $tablesToBackup = $this->_getTablesToBackUp();
        $tables			= $this->_selectTablesToBackUp($tables, $tablesToBackup);

        if (empty($tables)) {
        	return false;
        }

		$tableAvarageRowLengths = $this->_getAvarageRowLengths($tables);
		$tableStructures		= $this->_getStructures($tables);

        if ($fp = @fopen($this->fileName, 'w')) {
			fwrite($fp, '# ' . $this->dbName . ' database dump file ' . "\n");

			foreach ($tableStructures as $key => $val) {
				$tableName		 = $this->_escape($val[0]);
				$Dx_Create_Table = "\r\n" . '# Drop table ' . $tableName . ' if exists' . "\r\n" .
                                   'DROP TABLE IF EXISTS ' . $this->_handlePrefix($tableName) . ";\r\n" .
                					$this->_removeDefaultCharSet($this->_handlePrefix($val[1], true)) . ";\r\n";

				//echo str_pad($tableName, 10000) . '<br />';
				fwrite($fp, $Dx_Create_Table);

                $limit = 1 + ceil(0.5 * 1048576 / ($tableAvarageRowLengths[$val[0]] + 1));
                $from  = 0;

                $this->_query('LOCK TABLE ' . $tableName . ' WRITE');

                while(($qresult = $this->_query('SELECT * FROM ' . $tableName . ' LIMIT ' . $from . ', ' . $limit)) && ($total = mysql_num_rows($qresult))) {
                	$myquery = "\r\n" . 'INSERT INTO ' . $this->_handlePrefix($tableName) . ' VALUES';
                	$i		 = 0;

                    while ($line = mysql_fetch_array($qresult)) {
                    	$i		 += 1;
    	                $values	  = $this->_getValues($line);
						$myquery .= ($i == 1 ? ' ' : ',') . "\n(" . $values . ')';

                        if (strlen($myquery) > 20000) {
							fwrite($fp, $myquery);

							$myquery = '';
                        }
					}

					fwrite($fp, $myquery . ";\r\n");

					mysql_free_result($qresult);

					if ($total < $limit) {
                       	break;
                    }

                    $from += $limit;
				}

				$this->_query('UNLOCK TABLES');
			}

			fclose($fp);
		}

		return true;
    }

    /**
     * check is need handle given dump file table or not
     *
     * @param string $tableName
     * @return boolean
     */
    function _needHandlePrefix($tableName, $extendedCheck = false) {
        if (empty($tableName)) {
        	return false;
        }

        if ($extendedCheck) {
        	$pattern = '/^(?:\s*(?:(?:CREATE TABLE)|(?:INSERT INTO)|UPDATE|(?:DROP TABLE)\s*(?:IF EXISTS)?))\s*`' . $this->prefix . '([^`]*)`/i';
        } else {
        	$pattern = '/^`' . $this->prefix . '([^`]*)`$/i';
        }

        return (bool)preg_match($pattern, $tableName, $matches);
    }

    /**
     * remove table prefix from the given string
     *
     * @param string $tableName
     * @return handled string
     */
    function _handlePrefix($tableName, $extendedCheck = false) {
    	if ($this->_needHandlePrefix($tableName, $extendedCheck)) {
    		if ($extendedCheck) {
    			$pattern = '/^(\s*(?:CREATE TABLE|INSERT INTO|UPDATE|DROP TABLE (?:IF EXISTS)?)\s*)`' . $this->prefix . '([^`]*)`/i';
    		} else {
        		$pattern = '/^`' . $this->prefix . '([^`]*)`$/i';
    		}

        	return preg_replace($pattern, $extendedCheck ? '$1`$2`' : '`$1`', $tableName);
    	}

    	return $tableName;
    }

    /**
     * add ` symbols beside start and end of string
     *
     * @param string $string
     * @return string
     */
    function _escape($string) {
        return '`' . $string . '`';
    }

    /**
     * wrapper for mysql_query
     *
     * @param string $query
     * @return resource
     */
    function _query($query) {
        return mysql_query($query, $this->connection);
    }

    /**
     * return fields for creating INSERT SQL statement
     *
     * @param string $line
     * @return string
     */
    function _getFields($line) {
        $fields = '';

        while (list($col_name, $col_value) = each($line)) {
            if (!is_int($col_name)) {
                $fields .= "`$col_name`,";
            }
        }

        return substr($fields, 0, strlen($fields) - 1);
    }

    /**
     * return values for creating INSERT SQL statement
     *
     * @param string $line
     * @return string
     */
    function _getValues($line) {
        $values = '';

        while (list($col_name, $col_value) = each($line)) {
            if (!is_int($col_name)) {
            	if (is_null($col_value)) {
            		$values .= 'NULL,';
            	} else {
                	$values .= '"' . $this->_escape_string($col_value) . '",';
            	}
            }
        }

        return substr($values, 0, strlen($values) - 1);
    }

    /**
     * escape srtring - wrapper for mysql_escape_string
     *
     * $param string $string
     * @return string
     */
    function _escape_string($string = '') {
        return mysql_real_escape_string($string, $this->connection);
    }

    /**
     * return `create table` structures
     *
     * @param array $tables (list of tables to backup)
     * @return array of structures
     */
    function _getStructures($tables) {
        $tableStructures = array();

        foreach($tables as $v){
            $res = $this->_query('SHOW CREATE TABLE ' . $this->dbName . '.' . $v);

            while ($row = mysql_fetch_row($res)) {
                $tableStructures[] = $row;
            }

            mysql_free_result($res);
        }

        return $tableStructures;
    }

    function _getAvarageRowLengths($tables) {
    	$tableAvarageRowLengths = array();
    	$res					 = $this->_query('SHOW TABLE STATUS');

    	while ($row = mysql_fetch_assoc($res)) {
    		if (in_array($row['Name'], $tables)) {
				$tableAvarageRowLengths[$row['Name']] = $row['Avg_row_length'];
    		}
		}

		mysql_free_result($res);

		return $tableAvarageRowLengths;
    }

    /**
     * get all tables from selected database
     *
     * @return array
     */
    function _getTables() {
        $res			   = $this->_query('SHOW TABLES');
        $tableStructureslt = array();

        while ($row = mysql_fetch_array($res)) {
            $tableStructureslt[] = $row[0];
        }

        mysql_free_result($res);

        return $tableStructureslt;
    }

    /**
     * return all tables that should be dumping
     *
     * @param array $allTables
     * @param array $required
     *
     * @return array
     */
    function _selectTablesToBackUp($allTables, $required) {
        return array_intersect($allTables, $required);
    }

    /**
     * return list files that should be deleted
     *
     * @return array
     */
    function _getTablesToBackUp() {
    	$tables = array(
    		'domains',
    		'links',
    		'tags',
    		'tag_links'
    	);

		foreach ($tables as $k => $v) {
			$tables[$k] = $this->prefix . trim($v);
		}

		return $tables;
    }

    /**
     * remove from dump default charset record
     *
     * @param string $tableStructure
     * @access private
     *
     * @return string
     */
    function _removeDefaultCharSet($tableStructure) {
        return preg_replace("/\s'?DEFAULT CHARSET=[^'\s;]*(?:'|\s|;)?/i", ' ', $tableStructure);
    }

    function close_connection() {
    	mysql_close($this->connection);
    }

    function restore_connection() {
    	$this->close_connection();

    	$this->connection = @mysql_connect($this->host, $this->user, $this->pwd);

    	if (!is_resource($this->connection)) {
    		return false;
    	}

    	if (!@mysql_select_db($this->dbName, $this->connection)) {
    		return false;
    	}

    	return true;
    }

    function complete() {
    	$this->close_connection();
    }

}

$loggin_type = 'sb_login';

require_once '_loader.php';

$cmd 	= _hr('cmd');
$errors = array();

switch ($cmd) {
	case 'check_license' :
		exit('true');

		break;

	case 'make_backup' :
		$dbHost   = NConfig::get('host', 'Database');
		$dbUser   = NConfig::get('user', 'Database');
		$dbPwd	  = NConfig::get('password', 'Database');
		$dbName	  = NConfig::get('dbname', 'Database');
		$dbPrefix = NConfig::get('prefix', 'Database');
		$dbBackup = dirname(__FILE__) . '/log/' . $dbName . '_dump.txt';

		$backup = new Backup($dbHost, $dbUser, $dbPwd, $dbName, $dbPrefix);

		@unlink($dbBackup);

		$backup->setFileName($dbBackup);
		$backup->create();
		$backup->complete();

		@chmod($dbBackup, 0644);

		if (!file_exists($dbBackup)) {
			exit('false');
		}

		exit('true');

		break;

	case 'get_backup_portion' :
		$dbName	  = NConfig::get('dbname', 'Database');
		$dbBackup = dirname(__FILE__) . '/log/' . $dbName . '_dump.txt';

		if (!file_exists($dbBackup) || (($fh = @fopen($dbBackup, 'r')) === false)) {
			exit('false');
		}

		$portion = (int)_hr('portion');

		fseek($fh, ($portion - 1)*1024*1024*10);

		$dbBackupPortion = fread($fh, 1024*1024*10);

		fclose($fh);

		if (strlen($dbBackupPortion) > 0) {
			exit($dbBackupPortion);
		}

		exit('end');

		break;

	default :
		exit('false');
}

?>