I think I've done it, just to be sure though I'm running a test right now; a very long test. I created 100 databases and inserted 100,000 dummy users into database number 1. If my math is correct that means there should be 100,000,000 iterations in total. I'm timing it to see how long that will take, I have a feeling it will be close to tomorrow evening before it's finished.
Now practically your probably never going to reach 100,000 total users and 100 databases and if you did this whole thing would have to be rethought and perhaps rewritten in C to speed things up a bit. Until then though, this script should get you by for quite a while.
I would also suggest that before ever running this on a production server get your first board completely setup including and mods, initial users (like admins if more than one) and generally anything that will be the same from board to board. Then, for each board after the first you can bypass the installer script. Just create a backup of that first setup, create the new boards folder and drop the files in, create the new db and use a dump from your first db to populate it. You will likely still have to edit the config file and perhaps a couple of settings stored in the db but other than that doing it this way should work.
Here are the files and some simple instructions, see if you can replicate what I've done on your setup.
replicate.php
Code: Select all
<?php
error_reporting(0);
require_once('dbArray.php');
require_once('errorHandler.php');
$old_error_handler = set_error_handler("ErrorHandler");
$errorLog = 'error.log';
$email = "your_email_here@yourdomain.com";
//Start of measure
$timeparts = explode(' ',microtime());
$starttime = $timeparts[1].substr($timeparts[0],1);
// to keep track of which array index were on
$i = 1;
// Loop through our array of databases
foreach($dbArray as $item) {
// Set up the database connection
$dbConn1 = new mysqli($item['host'], $item['user'], $item['pass'], $item['db']);
if(mysqli_connect_error()) {
trigger_error(mysqli_error($dbConn1), E_USER_WARNING);
continue;
}else{
// Get the last users signup timestamp
//$timestamp = file_get_contents('timestamp.txt');
//echo $timestamp;
//echo $item['users_table'];
// grab all the new users since last run
if(!$result = $dbConn1->query("SELECT * FROM `$item[users_table]` WHERE `user_regdate` > CONVERT('$timestamp',SIGNED)")) {
trigger_error(mysqli_error($dbConn1), E_USER_WARNING);
continue;
}else{
while($users = $result->fetch_array(MYSQL_ASSOC)) {
echo "Working on user $users[username] of $item[db]<br />";
// Loop over every database but the one who's
// index were on and insert the user info.
foreach($dbArray as $db) {
// check to make sure this is the current db
// from our parent loop.
if($db['id'] = $i) {
echo "Current working database...skipping<br />";
continue;
}else{
// create a new database connection
$dbConn2 = new mysqli($db['host'], $db['user'], $db['pass'], $db['db']);
if(mysqli_connect_error()) {
trigger_error(mysqli_error($dbConn2), E_USER_WARNING);
continue;
}else{
if($dbConn2->query("INSERT IGNORE INTO $db[users_table]
(`user_type`,
`group_id`,
`user_permissions`,
`user_perm_from`,
`user_ip`,
`user_regdate`,
`username`,
`username_clean`,
`user_password`,
`user_passchg`,
`user_pass_convert`,
`user_email`,
`user_email_hash`,
`user_birthday`,
`user_inactive_reason`,
`user_inactive_time`,
`user_lang`,
`user_timezone`,
`user_dst`,
`user_dateformat`,
`user_message_rules`,
`user_emailtime`,
`user_topic_show_days`,
`user_topic_sortby_type`,
`user_topic_sortby_dir`,
`user_post_show_days`,
`user_post_sortby_type`,
`user_post_sortby_dir`,
`user_notify`,
`user_notify_pm`,
`user_notify_type`,
`user_allow_pm`,
`user_allow_viewonline`,
`user_allow_viewemail`,
`user_allow_massemail`,
`user_options`,
`user_from`,
`user_icq`,
`user_aim`,
`user_yim`,
`user_msnm`,
`user_jabber`,
`user_website`,
`user_occ`,
`user_interests`,
`user_actkey`,
`user_newpasswd`,
`user_form_salt`
)
VALUES ('$users[user_type]',
'$users[group_id]',
'$users[user_permissions]',
'$users[user_perm_from]',
'$users[user_ip]',
'$users[user_regdate]',
'$users[username]',
'$users[username_clean]',
'$users[user_password]',
'$users[user_passchg]',
'$users[user_pass_convert]',
'$users[user_email]',
'$users[user_email_hash]',
'$users[user_birthday]',
'$users[user_inactive_reason]',
'$users[user_inactive_time]',
'$users[user_lang]',
'$users[user_timezone]',
'$users[user_dst]',
'$users[user_dateformat]',
'$users[user_message_rules]',
'$users[user_emailtime]',
'$users[user_topic_show_days]',
'$users[user_topic_sortby_type]',
'$users[user_topic_sortby_dir]',
'$users[user_post_show_days]',
'$users[user_post_sortby_type]',
'$users[user_post_sortby_dir]',
'$users[user_notify]',
'$users[user_notify_pm]',
'$users[user_notify_type]',
'$users[user_allow_pm]',
'$users[user_allow_viewonline]',
'$users[user_allow_viewemail]',
'$users[user_allow_massemail]',
'$users[user_options]',
'$users[user_from]',
'$users[user_icq]',
'$users[user_aim]',
'$users[user_yim]',
'$users[user_msnm]',
'$users[user_jabber]',
'$users[user_website]',
'$users[user_occ]',
'$users[user_interests]',
'$users[user_actkey]',
'$users[user_newpasswd]',
'$users[user_form_salt]')"))
{
// The insert was succesful update the timestamp file
// with the last users reg date.
echo "\tUser #$users[user_id] successfully added to $db[db]<br />";
echo "\tUpdating timestamp.txt with last users registration date<br /><br />";
file_put_contents('timestamp.txt', $users['users_regdate']);
continue;
}else{
trigger_error(mysqli_error($dbConn2), E_USER_WARNING);
continue;
}
$dbConn2->close();
}
}
}
}
}
}
$i++;
$dbConn1->close();
}
// end of measure
$timeparts = explode(" ",microtime());
$endtime = $timeparts[1].substr($timeparts[0],1);
// display
echo number_format(bcsub($endtime,$starttime,6),3);echo " s ";
?>
dbArray.php
Code: Select all
// Fill with more as needed
// every database in this
// array will be replicated
$dbArray = array(
array('id' => 1,
'host' => 'localhost',
'user' => 'root',
'pass' => '',
'db' => "forum1",
'users_table' => 'phpbb_users'
),
array('id' => 2,
'host' => 'localhost',
'user' => 'root',
'pass' => '',
'db' => "forum2",
'users_table' => 'phpbb_users'
)
);
errorHandler.php
Code: Select all
<?php
$email = '';
$errorLog = '';
function ErrorHandler($errno, $errmsg, $filename, $linenum, $vars) {
// timestamp for the error entry
$dt = date("Y-m-d H:i:s (T)");
// define an assoc array of error string
// in reality the only entries we should
// consider are E_WARNING, E_NOTICE, E_USER_ERROR,
// E_USER_WARNING and E_USER_NOTICE
$errortype = array (
E_ERROR => 'Error',
E_WARNING => 'Warning',
E_PARSE => 'Parsing Error',
E_NOTICE => 'Notice',
E_CORE_ERROR => 'Core Error',
E_CORE_WARNING => 'Core Warning',
E_COMPILE_ERROR => 'Compile Error',
E_COMPILE_WARNING => 'Compile Warning',
E_USER_ERROR => 'User Error',
E_USER_WARNING => 'User Warning',
E_USER_NOTICE => 'User Notice',
E_STRICT => 'Runtime Notice',
E_RECOVERABLE_ERROR => 'Catchable Fatal Error'
);
// set of errors for which a var trace will be saved
$user_errors = array(E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE);
$err = "<errorentry>\n";
$err .= "\t<datetime>" . $dt . "</datetime>\n";
$err .= "\t<errornum>" . $errno . "</errornum>\n";
$err .= "\t<errortype>" . $errortype[$errno] . "</errortype>\n";
$err .= "\t<errormsg>" . $errmsg . "</errormsg>\n";
$err .= "\t<scriptname>" . $filename . "</scriptname>\n";
$err .= "\t<scriptlinenum>" . $linenum . "</scriptlinenum>\n";
if (in_array($errno, $user_errors)) {
$err .= "\t<vartrace>" . wddx_serialize_value($vars, "Variables") . "</vartrace>\n";
}
$err .= "</errorentry>\n\n";
// for testing
// echo $err;
// save to the error log, and e-mail me if there is a critical user error
switch($errno) {
case E_USER_ERROR:
error_log($err, 1, $errorLog);
mail($email, "User error in phpbb replication script", $err);
case E_USER_WARNING:
error_log($err, 2, $errorLog);
mail($email, "User warning in phpbb replication script", $err);
case E_USER_NOTICE:
error_log($err, 3, $errorLog);
mail($email, "User notice in phpbb replication script", $err);
}// end of switch
}// end of ErrorHandler
?>
Also create timestamp.txt and error.log and make them writeable. Place all the files in the same directory and run replicate.php from the command line to get around php's maximum execution time limits.
Another thing that might be a good idea is if you run this code past that other forum you frequent and just see if anyone notices any bugs that I missed.