<?php

/*
    DB-Upload Utility - By Dennis Pallett (dennis@nocertainty.com)
    http://www.nocertainty.com

    Made available under the GNU General Public License (GPL)
    http://www.gnu.org/licenses/gpl.txt
*/

ob_start();
error_reporting (E_ALL E_NOTICE);

// Define file sizes
DEFINE ("KB"1024);
DEFINE ("MB"1024*1024);
DEFINE ("GB"1024*1024*1024);

$_GET strip_gpc_slashes ($_GET);

// Get settings
$filename $_GET['filename'];
$db_host $_GET['db_host'];
$db_name $_GET['db_name'];
$db_user $_GET['db_user'];
$db_password $_GET['db_password'];

// Are there any settings?
if (empty($filename) OR empty($db_host) OR empty($db_name) OR empty($db_password)) {
    
// Show the settings form:
    
?>
    <html>
        <head>
        <title>DB-Upload Utility</title>
        </head>

        <style type="text/css">
            body {
             background-color: #EFEFEF;
             font-family: Verdana, Arial, Times New Roman;
            }

            h2 {
             font-size: 120%;
             font-weight: normal;
             margin-left: 15px;
            }

            th {
             font-size: 0.7em;
             text-align: right;
             padding-right: 10px;
             vertical-align: top;
            }

            td {
             font-size: 62.5%; /* Resets 1em to 10px */
            }

            div {
             background-color: #FFF;
             border: 1px solid black;
             padding: 15px;
             padding-bottom: 0px;
             text-align: center;
            }

            #submit {
             font-family: Verdana;
             font-weight: bold;
             font-size: 0.7em;
             padding: 2px 60px;
             margin-top: 15px;
            }
        </style>

        <body>
        <div>
            <h2>DB-Upload Utility</h2>
            
            <form method="GET">
                <table border="0">
                    <tr>
                        <th scope="col">Filepath:</th>
                        <td><input type="text" size="100" name="filename" /><br />Path to the SQL on your server, e.g. /home/dennis/public_html/mydb.sql
                        </td>
                    </tr>

                    <tr>
                        <th scope="col">DB Host:</th>
                        <td><input type="text" name="db_host" value="localhost" /></td>
                    </tr>
                    <tr>
                        <th scope="col">DB Name:</th>
                        <td><input type="text"  name="db_name" /></td>
                    </tr>
                    <tr>
                        <th scope="col">DB User:</th>
                        <td><input type="text"  name="db_user" /></td>
                    </tr>
                    <tr>
                        <th scope="col">DB Password:</th>
                        <td><input type="password" name="db_password" /></td>
                    </tr>
                </table>
                <input id="submit" type="submit" value="Upload Database" />
            </form>
        </div>
        </body>
    </html>
    <?
    
die();
}

// Check if file exists
if (!file_exists($filename)) {
    die(
"Invalid File Specified. Go back and enter a different file path!");
}

// Establish connection with database
$link mysql_connect($db_host$db_user$db_password);

if (!
$link) {
    die(
'Unable to connect to MySQL');
}

// Select database
$db_selected mysql_select_db($db_name$link);

if (!
$db_selected) {
    die(
'Unable to select MySQL database');
}

// Get filesize (in bytes)
$filesize filesize($filename);

// Open the file
$fp fopen($filename'r');

// We haven't reached end of file yet, so et eof to false
$eof false;

// Get begin
$begin is_numeric($_GET['begin']) ? $_GET['begin'] : 0;

// Execute queryies in blocks of... 100 KB
$size 100*KB;

// First, remove data before
remove_data_before();

// Read in data we need
$data fread($fp$size);
        
// Find last SQL query
$pos strrpos($data";");

if (
$pos === false) { // note: three equal signs
    
die("Couldn't find SQL query. Sorry");
}

// Get new beginning for next round
$newbegin $begin $pos;

// Get all relevant data
$data substr($data0$pos);
$data trim($data);

// Slit SQL file into pieces
$pieces = array();
PMA_splitSqlFile ($pieces$data);

// Don't use last one (if we haven't reached the end of the file yet
if (($begin $size) < $filesize) {
    
// Set new begin
    
$newbegin $newbegin strlen($pieces[count($pieces)-1]);
    
// Remove last SQL query
    
array_pop ($pieces);
}

// Execute each SQL query
foreach ($pieces as $sql) {
    
query($sql);
}

// Have we reached the end?
if (($begin $size) >= $filesize) {
    
$eof true;
}

// Close database
mysql_close($link);

// Create url for next step
$nexturl $_SERVER['PHP_SELF'];
$nexturl .= '?filename=' urlencode($filename);
$nexturl .= '&db_host=' urlencode($db_host);
$nexturl .= '&db_name=' urlencode($db_name);
$nexturl .= '&db_user=' urlencode($db_user);
$nexturl .= '&db_password=' urlencode($db_password);
$nexturl .= '&begin=' $newbegin;

// Display status
?>
    <html>
        <head>
        <title>DB-Upload Utility</title>
        </head>

        <style type="text/css">
            body {
             background-color: #EFEFEF;
             font-family: Verdana, Arial, Times New Roman;
            }

            h2 {
             font-size: 120%;
             font-weight: normal;
             margin-left: 15px;
            }

            th {
             font-size: 0.7em;
             text-align: right;
             padding-right: 10px;
             vertical-align: top;
            }

            td {
             font-size: 62.5%; /* Resets 1em to 10px */
            }

            div {
             background-color: #FFF;
             border: 1px solid black;
             padding: 15px;
             padding-bottom: 0px;
             text-align: center;
            }

            #bytesread, #mbread, #bytesexec, #mbexec, #percentage {
             font-weight: bold;
            }

            div#done {
             border: 0;
            }

            div#done span {
             font-size: 130%;
            }

            #next {
             display: block;
             margin-top: 10px;
             margin-bottom: 15px;
            }

            #next:link, #next:visited {
             color: #000;
             font-size: 1.6em;
            }

            #next:hover {
             color: brown;
            }

        </style>

        <body>
        <div>
            <h2>DB-Upload Utility: Status</h2>
            
                <table border="0">
                    <tr>
                        <th scope="col">Size Read:</th>
                        <td><span id="bytesread"><?php echo $newbegin?></span> out of <strong><?php echo ($filesize); ?></strong> bytes (<span id="mbread"><?php echo round($newbegin/MB2); ?></span> out of <strong><?php echo round($filesize/MB2); ?></strong> MB)
                        </td>
                    </tr>

                    <tr>
                        <th scope="col">Size Executed:</th>
                        <td><span id="bytesexec"><?php echo $newbegin?></span> out of <strong><?php echo ($filesize); ?></strong> bytes (<span id="mbexec"><?php echo round($newbegin/MB2); ?></span> out of <strong><?php echo round($filesize/MB2); ?></strong> MB)
                        </td>
                    </tr>

                    <tr>
                        <th scope="col">Percentage Completed:</th>
                        <td><span id="percentage"><?php echo round(($newbegin/$filesize)*1002); ?></span>%
                        </td>
                    </tr>
                </table>

                <?php if ($eof === true) { ?>
                    <div id="done">
                        <span>All Done!</span>
                        <p>Your SQL file has been uploaded, and all the queries have been successfully executed.</p>
                    </div>
                <?php } else { ?>
                        <a id="next" href="<?php echo $nexturl?>">Go to the next step &raquo;</a>
                        <script type="text/javascript">
                            document.getElementById('next').style.display = 'none';
                        </script>
                <?php
                        
// Javascript redirect to next page
                        
js_redirect ($nexturl0.5);
                }
                
?>

        </div>
        </body>
    </html>
<?php


// Functions:
// functions that we need are all declared below
// *********************************************

// Does a JavaScript redirect to a certain URL
function js_redirect($url$seconds=5) {
    echo 
"<script language=\"JavaScript\">\n";
    echo 
"<!-- hide from old browser\n\n";
    
    echo 
"function redirect() {\n";
    echo 
"window.location = \"" $url "\";\n";
    echo 
"}\n\n";

    echo 
"timer = setTimeout('redirect()', '" . ($seconds*1000) . "');\n\n";

    echo 
"-->\n";
    echo 
"</script>\n";

    return 
true;
}

// Executes a SQL query
function query($sql) {
    
$link $GLOBALS['link'];

    
// do query (and surpress errors);
    
@mysql_query ($sql$link);
}

// remove_date_before
// Removes all the data before the begin position
function remove_data_before() {
    
$fp $GLOBALS['fp'];
    
$begin $GLOBALS['begin'];
    
$size $GLOBALS['size'];

    
// Get number of full steps we can remove
    
$steps floor($begin/$size);
    
$left $begin;

    
// Loop through each block (if there are multiple steps)
    
if ($begin >= $size) {
        for (
$i 1$i <= $steps$i++) {
            
// Remove 10MB from the begin and file pointer
            
$left $left $size;
            
fread ($fp$size);
        }
    }

    
// Read final bit
    
fread($fp$left);
}

// Splits an SQL file/string
function PMA_splitSqlFile(&$ret$sql)
{
    
$sql          trim($sql);
    
$sql_len      strlen($sql);
    
$char         '';
    
$string_start '';
    
$in_string    FALSE;
    
$time0        time();

    for (
$i 0$i $sql_len; ++$i) {
        
$char $sql[$i];

        
// We are in a string, check for not escaped end of strings except for
        // backquotes that can't be escaped
        
if ($in_string) {
            for (;;) {
                
$i         strpos($sql$string_start$i);
                
// No end of string found -> add the current substring to the
                // returned array
                
if (!$i) {
                    
$ret[] = $sql;
                    return 
TRUE;
                }
                
// Backquotes or no backslashes before quotes: it's indeed the
                // end of the string -> exit the loop
                
else if ($string_start == '`' || $sql[$i-1] != '\\') {
                    
$string_start      '';
                    
$in_string         FALSE;
                    break;
                }
                
// one or more Backslashes before the presumed end of string...
                
else {
                    
// ... first checks for escaped backslashes
                    
$j                     2;
                    
$escaped_backslash     FALSE;
                    while (
$i-$j && $sql[$i-$j] == '\\') {
                        
$escaped_backslash = !$escaped_backslash;
                        
$j++;
                    }
                    
// ... if escaped backslashes: it's really the end of the
                    // string -> exit the loop
                    
if ($escaped_backslash) {
                        
$string_start  '';
                        
$in_string     FALSE;
                        break;
                    }
                    
// ... else loop
                    
else {
                        
$i++;
                    }
                } 
// end if...elseif...else
            
// end for
        
// end if (in string)

        // We are not in a string, first check for delimiter...
        
else if ($char == ';') {
            
// if delimiter found, add the parsed part to the returned array
            
$ret[]      = substr($sql0$i);
            
$sql        ltrim(substr($sqlmin($i 1$sql_len)));
            
$sql_len    strlen($sql);
            if (
$sql_len) {
                
$i      = -1;
            } else {
                
// The submited statement(s) end(s) here
                
return TRUE;
            }
        } 
// end else if (is delimiter)

        // ... then check for start of a string,...
        
else if (($char == '"') || ($char == '\'') || ($char == '`')) {
            
$in_string    TRUE;
            
$string_start $char;
        } 
// end else if (is start of string)

        // ... for start of a comment (and remove this comment if found)...
        
else if ($char == '#'
                 
|| ($char == ' ' && $i && $sql[$i-2] . $sql[$i-1] == '--')) {
            
// starting position of the comment depends on the comment type
            
$start_of_comment = (($sql[$i] == '#') ? $i $i-2);
            
// if no "\n" exits in the remaining string, checks for "\r"
            // (Mac eol style)
            
$end_of_comment   = (strpos(' ' $sql"\012"$i+2))
                              ? 
strpos(' ' $sql"\012"$i+2)
                              : 
strpos(' ' $sql"\015"$i+2);
            if (!
$end_of_comment) {
                
// no eol found after '#', add the parsed part to the returned
                // array if required and exit
                
if ($start_of_comment 0) {
                    
$ret[]    = trim(substr($sql0$start_of_comment));
                }
                return 
TRUE;
            } else {
                
$sql          substr($sql0$start_of_comment)
                              . 
ltrim(substr($sql$end_of_comment));
                
$sql_len      strlen($sql);
                
$i--;
            } 
// end if...else
        
// end else if (is comment)

        // ... and finally disactivate the "/*!...*/" syntax if MySQL < 3.22.07
        
else if ($release 32270
                 
&& ($char == '!' && $i 1  && $sql[$i-2] . $sql[$i-1] == '/*')) {
            
$sql[$i] = ' ';
        } 
// end else if

        // loic1: send a fake header each 30 sec. to bypass browser timeout
        
$time1     time();
        if (
$time1 >= $time0 30) {
            
$time0 $time1;
            
header('X-pmaPing: Pong');
        } 
// end if
    
// end for

    // add any rest to the returned array
    
if (!empty($sql) && ereg('[^[:space:]]+'$sql)) {
        
$ret[] = $sql;
    }

    return 
TRUE;
// end of the 'PMA_splitSqlFile()' function

function strip_gpc_slashes ($input)
{
   if ( !
get_magic_quotes_gpc() || ( !is_string($input) && !is_array($input) ) )
   {
       return 
$input;
   }

   if ( 
is_string($input) )
   {
       
$output stripslashes($input);
   }
   elseif ( 
is_array($input) )
   {
       
$output = array();
       foreach (
$input as $key => $val)
       {
           
$new_key stripslashes($key);
           
$new_val strip_gpc_slashes($val);
           
$output[$new_key] = $new_val;
       }
   }

   return 
$output;
}
?>