├── .gitignore ├── Readme.md ├── db-config-sample-16.php ├── db-config-sample-256.php ├── db-config.php ├── db-tools ├── db.php ├── db_array.php ├── db_servers.php ├── db_sql.php ├── index.php └── md5.php ├── db.php ├── fix-db-encoding.php ├── license.txt ├── move-blogs-rollback.php └── move-blogs.php /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Multi DB 2 | 3 | **INACTIVE NOTICE: This plugin is unsupported by WPMUDEV, we've published it here for those technical types who might want to fork and maintain it for their needs.** 4 | 5 | The standard WordPress Multisite installation requires only one database – which is great for hobbyists or people just looking to host a few dozen or few hundred sites. 6 | 7 | When you get past a few hundred sites, a single database can get cramped. 8 | 9 | Multi-DB works to make better use of your server by creating either 16, 256 or 4096 database tables and spreading new blogs evenly across your system. 10 | 11 | 12 | If you’re in need of a tool that spreads sites on your network across multiple database tables, Multi-DB has been tested and used on thousands of sites since 2008. 13 | 14 | It is a fantastic foundation for anyone looking to spread their content across more than one database. 15 | 16 | ## Usage Docs 17 | 18 | **Important: Please note that this is not your normal “drop-the-files-here” plugin, and it is not to be uploaded to wp-content/plugins** 19 | 20 | This is sysadmin-level stuff. But don’t be scared off, with the right mindset (and server configuration) you can do it! 21 | 22 | #### First, is your server setup right for this? 23 | 24 | * Do you have root access to your server, access to phpMyAdmin, and can you run SQL scripts on your database? 25 | * If you are big enough to need Multi-DB, you really should be using a VPS or dedicated server that gives you root access. 26 | * If your host or server is using a control panel like cPanel, or they run DB servers externally (ie – shared hosting, grid hosting, etc), you may not have permissions to create DBs via an SQL script. 27 | * So first see if you can login as root and run stuff via command line. If not, you may need to create the DBs manually one at a time through the control panel (cPanel). 28 | Your server meets the requirements and you’re ready to roll? Then let’s do this! 29 | 30 | ## Preparation is Key 31 | 32 | Multi-DB is one of those plugins that becomes an absolute necessity for any Multisite network that is seeing or expecting substantial numbers of blogs/sites. 33 | 34 | It is powerful in what it does (spreading the WordPress tables across several databases), but as with anything else, getting it set up correctly with adequate preparation for installation is essential to success. 35 | 36 | The key to success with this plugin is to have the settings edited and triple-checked BEFORE uploading to your site. 37 | 38 | If you’ve not attempted this before, we recommend reading through this entire process first. Then read it again and follow along. Finally, go back through and make sure each setting is correct. Then you should be ready for an install without incident! 39 | 40 | *STOP! Before going any further, please make a full backup of your multisite so, just in case things go kaflooey, you can restore it!* 41 | 42 | ## Creating Your Databases 43 | 44 | Decide how many databases you want (16, 256, 4096) 45 | So, how do you know that this plugin is necessary for your install? Well, there are several factors to consider beyond the scope of this walkthrough, but here’s a basic guideline: 46 | 47 | * 1 – 5,000 blogs/sites: you should be fine with your WordPress default database 48 | * 5,000 – 50,000 blogs/sites: go with 16 databases 49 | * 50,000 – 100,000 blogs/sites: use 256 databases 50 | * 100,000+ blogs/sites: use 4096 databases 51 | 52 | There’s no performance hit for using 256 databases over 16. But if you’re expecting massive growth, planning ahead at this point will save you additional work down the road. 53 | 54 | In fact, unless you already know you won’t be growing past 50,000 blogs/sites it’s best just to do the 256 just in case. Using 4096 DBs is usually overkill unless you plan on being the next wordpress.com or edublogs.org! 55 | 56 | As stated earlier, there are several factors to consider and this is meant to be a general guide. It’s really a decision specific to your site needs. 57 | 58 | ### Decide if you need VIP databases 59 | This plugin has a cool feature that allows for VIP databases. It enables you to place specific blog(s) in specific database(s). 60 | 61 | * Unless you have a blog/site that gets a ton of traffic and you want to put it on another physical server for performance reasons, then it’s not really worth it to bother with this feature. 62 | * The vast majority of installs do not need to use VIP blogs, so skip it unless you are sure you need to use this feature. 63 | * Each VIP blog/site will have its own database, and they will be identified as vip1, vip2, etc. 64 | * If you do decide you need this, you’ll be using the add_vip_blog() function in db-config.php to move specific blogs to these databases (more on that below). 65 | 66 | ## Create the mySQL command 67 | 68 | While you can name your databases anything you like, we know from experience that ordering them as we have in this walkthrough will make management easier down the road, and it also lets you more easily use the included db-config.php file. 69 | 70 | We’ll get to that file in the next step below, but first we need to get the proper SQL command set up. We’ve provided an easy tool for that, you can check it under /db-tools/ within this repository. 71 | 72 | **IMPORTANT: Once you upload the db-tools directory to your site, any logged in user will be able to access it.** 73 | 74 | Be sure you’re on the correct tool for database creation by clicking the DB SQL link at the top of the page. 75 | 76 | ![M](https://premium.wpmudev.org/wp-content/uploads/2008/08/multi-db-3240-db-tools.png) 77 | 78 | * In the DB Name field, type in your database name (it should be the same name as your current WordPress DB) followed by an underscore ( _ ). The underscore is very important as this creates the prefix for your new databases. Without that underscore, nothing will work! 79 | * Next, choose the number of databases you need from the dropdown. Then click the Submit button. 80 | 81 | In the textarea below, you’ll now see all the instructions mySQL needs to create your new DBs. 82 | 83 | ![M](https://premium.wpmudev.org/wp-content/uploads/2008/08/multi-db-3240-dbs-created.png) 84 | 85 | Well, almost all; there is one other line you need to add manually to create the required global database. 86 | 87 | * Copy the final line generated by the database tool, and paste it directly beneath all the others in the textarea of the DB creation tool. 88 | * Then change dbname_f to dbname_global in that new line. That’s it. 89 | 90 | Your final output for the required global database will look something like this: 91 | 92 | `CREATE DATABASE 'dbname_global' DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;` 93 | 94 | Did you also decide to create optional VIP databases for some of your blogs/sites as mentioned above? If so… 95 | 96 | * Add another line in the textarea for each one you need. 97 | * Change dbname_f to dbname_vip1 for the first one. 98 | * If you are creating more than one, change dbname_f to dbname_vip2 for the second one, dbname_vip3 for the third one, and so on. 99 | 100 | The final output for each of your VIP databases would look something like this: 101 | 102 | `CREATE DATABASE 'dbname_vip1' DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;` 103 | 104 | Be sure you’ve added these extra line(s) directly beneath those created by the DB SQL tool. 105 | 106 | ## Create the Databases 107 | Now, you need to create the databases, either via command line (hardcore) or through phpMyAdmin (much easier). 108 | 109 | Log into your server and, if you’re using phpMyAdmin, be sure you’re in the root and click the SQL tab. Then paste in the SQL command you just generated (the contents of the textarea from the DB SQL tool), and click the “Go” button. 110 | 111 | Note that the screenshot below does not include any lines for VIP databases. However, if you are creating some, they would be there. 112 | 113 | ![M](https://premium.wpmudev.org/wp-content/uploads/2008/08/multi-db-3240-phpmyadmin-created.png) 114 | 115 | Now when you click the “Databases” tab in a tool like **phpMyAdmin**, you should see loads of new databases where there used to be only one or two. 116 | 117 | ![M](https://premium.wpmudev.org/wp-content/uploads/2008/08/multi-db-3240-phpmyadmin-create.png) 118 | 119 | Note that even though your new databases may appear instantly in phpMyAdmin, it can sometimes take several minutes – even hours – for them to appear in cPanel. 120 | 121 | In some instances, you may even need to wait until the next day. This is beyond our, and your, control. Patience, Grasshopper. :) 122 | 123 | ## Assigning Users & Passwords 124 | 125 | A username and password must be associated with each database. 126 | 127 | * This could be the same as your username and password for the original WordPress database. Or you could create new users for your new databases. 128 | * It’s up to you, just make sure that there IS a username and password associated with each one and note what they are. You’ll need this information for the next part of the installation. 129 | 130 | You can create and assign usernames & passwords either directly in phpMyAdmin, or use the **MySQL Databases** section in your cPanel. 131 | 132 | ## Creating Users & Passwords in phpMyAdmin 133 | If you have CREATE USER privileges in phpMyAdmin, you can use any of the following commands in the SQL tab (the same place where you just added the command to create your new databases). 134 | 135 | To assign all privileges on all databases to an existing user (probably you), you can use this command: 136 | 137 | `GRANT ALL PRIVILEGES ON * . * TO 'username'@'localhost'; 138 | FLUSH PRIVILEGES;` 139 | 140 | Or, if you want to create a new username/password combination & assign all privileges on all databases to that user, use this command: 141 | 142 | `CREATE USER 'username'@'localhost' IDENTIFIED BY 'password'; 143 | GRANT ALL PRIVILEGES ON * . * TO 'username'@'localhost'; 144 | FLUSH PRIVILEGES;` 145 | 146 | The asterisks in the above commands represent, respectively, all databases & all tables. 147 | 148 | If you are using VIP databases, and want to create and grant privileges to different users in each of those, you’d first create the user(s) and their password(s), then specify the username for each database using a command like this (note the database specified instead of the first asterisk): 149 | 150 | ``` 151 | CREATE USER 'user1'@'localhost' IDENTIFIED BY 'pass1'; 152 | CREATE USER 'user2'@'localhost' IDENTIFIED BY 'pass2'; 153 | GRANT ALL PRIVILEGES ON dbname_vip1 . * TO 'user1'@'localhost'; 154 | GRANT ALL PRIVILEGES ON dbname_vip2 . * TO 'user2'@'localhost'; 155 | GRANT ALL PRIVILEGES ON dbname_global . * TO 'username'@'localhost'; 156 | GRANT ALL PRIVILEGES ON dbname_0 . * TO 'username'@'localhost'; 157 | GRANT ALL PRIVILEGES ON dbname_1 . * TO 'username'@'localhost'; 158 | GRANT ALL PRIVILEGES ON dbname_2 . * TO 'username'@'localhost'; 159 | GRANT ALL PRIVILEGES ON dbname_3 . * TO 'username'@'localhost'; 160 | GRANT ALL PRIVILEGES ON dbname_4 . * TO 'username'@'localhost'; 161 | GRANT ALL PRIVILEGES ON dbname_5 . * TO 'username'@'localhost'; 162 | ... 163 | FLUSH PRIVILEGES; 164 | ``` 165 | 166 | Be sure to include an additional line for each database as indicated by the ellipsis (…). 167 | 168 | In each of the above cases, replace the words `user1`, `user2`, `pass1`, `pass2`, username & password in the code with the actual usernames & passwords. :) 169 | 170 | Also remember to change `dbname_0`, `dbname_1`, etc, to the actual names of your databases. 171 | 172 | [For more on this, see this handy tutorial at DigitalOcean](https://www.digitalocean.com/community/tutorials/how-to-create-a-new-user-and-grant-permissions-in-mysql). 173 | 174 | ##Creating Users & Passwords in cPanel 175 | If you do not have CREATE USER privileges in phpMyAdmin, or just don’t want to mess around in there, you can add the username & password to each new database in your cPanel. 176 | 177 | To do that, scroll down to the Databases section on the main page of your cPanel, and click the **MySQL Databases** link. 178 | 179 | ![](https://premium.wpmudev.org/wp-content/uploads/2008/08/multi-db-3240-cpanel-phpmyadmin.png) 180 | 181 | On the next screen, fill in the fields in the **Add New User** section to create any new user(s) that you may want. 182 | 183 | Then, assign existing user(s) to the appropriate database(s) in the **Add User To Database** section. 184 | 185 | ![](https://premium.wpmudev.org/wp-content/uploads/2008/08/multi-db-3240-cpanel-add-users.png) 186 | 187 | When you click the **Add** button to add a user to a database, you’ll get a screen where you can assign the privileges for that user & database. 188 | 189 | ![](https://premium.wpmudev.org/wp-content/uploads/2008/08/multi-db-3240-cpanel-user-privileges.png) 190 | 191 | Simply check the **All Privileges** box and click **Make Changes**. 192 | 193 | You’ll need to add a user to each database and grant permissions for each one in the manner detailed above. 194 | 195 | So, if you have added 16 databases, you’ll do this 16 times; for 256 databases, you’ll do it 256 times; 4096 databases, well, you get the idea. :) 196 | 197 | 198 | ## Configuring the Plugin Files 199 | 200 | Your databases are created and you’ve assigned usernames & passwords to each one? 201 | 202 | Excellent! Now it’s time to start configuring the plugin to handle the heavy lifting. We’ve got several areas to configure in 2 different files. 203 | 204 | So if you haven’t already downloaded your copy of Multi-DB by clicking the big button at the top of this page, please do that now. 205 | 206 | ### Configuring `db-config.php` 207 | Unzip the file you just downloaded, and open `db-config.php` in a text editor like Sublime Text 208 | 209 | The first thing to do is enter the number of new databases you just created, and the IP address of your multisite. 210 | 211 | ![](https://premium.wpmudev.org/wp-content/uploads/2008/08/multi-db-3240-db-config-1.png) 212 | 213 | * Line 10: Change the number next to DB_SCALING to however many new databases you created (16, 256, or 4096) 214 | * Line 16: On this line, enter ONLY the first 3 quadrants of your multisite’s IP address, with a dot at the end.For example, if your IP is `111.222.333.444` you would enter `111.222.333`. including the dot. It would look like this: `add_dc_ip('111.222.333.', 'dc1');` 215 | 216 | Next, we want to add in the new global database name. 217 | 218 | ![](https://premium.wpmudev.org/wp-content/uploads/2008/08/multi-db-3240-db-config-2.png) 219 | 220 | * Scroll down to line 25, and add a new blank line there. On that line, enter the the command for your new global database.Remember to change `dbname_global` to the actual name of the global database you created. It would look like this: `add_global_table('dbname_global');` 221 | 222 | The other global table lines in there are required by the plugins specified. 223 | 224 | * If you’re not using any of those plugins, you can safely leave those lines there. It’s like having an empty closet: you’re not using it, but it’s nice to know it’s there if you do need it. 225 | 226 | The next thing we want to configure in this file is the *DB Servers* section. 227 | 228 | To do that, we’re going to use another of the online tools we have provided: 229 | http://yourdomain.com/db-tools/db_servers.php 230 | 231 | Click on that link now, and be sure you’re on the correct tool by clicking the DB Servers link at the top of the page. 232 | 233 | ![](https://premium.wpmudev.org/wp-content/uploads/2008/08/multi-db-3240-db-tools-2.png) 234 | 235 | * In the **DB Name** field, type in your database name just like you did with the previous tool, followed by the underscore ( _ ). Again, the underscore is very important here; without it, stuff won’t work. 236 | * Enter your username in the **DB User** field, and your password in the **DB Pass** field. 237 | * In the **DB Local Host** field, enter the full IP of your multisite. Ex: `111.222.333.444` 238 | * The DB Remote Host field is only required if your databases are hosted on a different IP from your WordPress install (a remote server). If they are, enter that IP here.If, as is usually the case, your databases are at the same IP as your WordPress site, you can ignore the need for a remote server entirely, and leave the field blank. 239 | * Finally, select the number of databases you already created from the dropdown. Then click the **Submit** button. 240 | 241 | In the textarea below, you’ll now see all the instructions you need to paste in the *DB Servers* section of `db-config.php` 242 | 243 | Your output should look similar to the following: 244 | 245 | ![Multi-DB Servers Created](https://premium.wpmudev.org/wp-content/uploads/2008/08/multi-db-3240-db-tools-3.png) 246 | 247 | The actual values will be the ones you entered. If you did not enter anything for the remote host, that value will simply be empty. 248 | 249 | Just as we did when creating the new databases, we want to add a special line here too for our global database. 250 | 251 | * Copy one of the lines generated, and paste it directly **above** all the others in the textarea of the DB Servers tool. 252 | * Change the number at the beginning of that new line to`global`. 253 | * Change the `dbname_x` to the name of your global database. For ex: `dbname_global`. 254 | * The new line for your global database will look something like this: 255 | 256 | `add_db_server('global', 'dc1', 1, 1,'','111.222.333.444', 'dbname_global', 'username', 'password');` 257 | 258 | Did you also create VIP database(s)? If so, you’ll want to add a line here too for each one. 259 | 260 | * Copy one of the lines generated, and paste it directly `beneath` the line for your global database. 261 | * Change the number at the beginning of that new line to `vip1` * Change the `dbname_x` to the name of your VIP database. For ex: `dbname_vip1`. 262 | * The new line for your VIP database will look something like this: 263 | 264 | `add_db_server('vip1', 'dc1', 1, 1,'','111.222.333.444', 'dbname_vip1', 'username', 'password');` 265 | 266 | If you have created more than one VIP database, add a similar line for each one. Change `vip1` and `dbname_vip1` in each new line to the corresponding values (`vip2`, `dbname_vip2`, etc). 267 | 268 | **Important: If you have assigned different username(s) & password(s) to different databases in the previous steps, be sure to edit them here now for each of those databases.** 269 | 270 | All done? Please double-check to make sure that you have the correct number of lines in there corresponding to the number of databases you created (16, 256 or 4096), as well as one for the global database, and any VIP databases you may have created too. 271 | 272 | Now copy the entire contents of the textarea, and paste it in db-config.php at line 67, replacing all the existing examples there. 273 | 274 | That section in your `db-config.php` should now look like this: 275 | 276 | Again, this screenshot does not include any lines for VIP databases. But if you created some, they should be there. 277 | 278 | ![](https://premium.wpmudev.org/wp-content/uploads/2008/08/multi-db-3240-db-config-3.png) 279 | 280 | 281 | The last section we want to configure is the VIP Blogs section. This is where you will actually designate which database(s) should be used by which blog(s). 282 | 283 | **If you did not create any databases for VIP blogs in the previous steps, you can skip this part.** 284 | 285 | To designate a blog/site as a VIP blog/site and give it its own database, simply follow the example given at the very bottom of the file. 286 | 287 | To add your blog with an ID of ‘4’ to the vip1 database, just enter the following: 288 | 289 | `add_vip_blog(4, 'vip1');` 290 | 291 | Create a new line for each of the VIP databases you need. Paste them all in directly above the `?>` which closes the file. 292 | 293 | ![Multi-DB VIP Blogs](https://premium.wpmudev.org/wp-content/uploads/2008/08/multi-db-3240-vip-blogs.png) 294 | 295 | Note that you can only designate a VIP database for your main site if the table names are prefixed with a number, like this: 296 | `wp_1_posts` 297 | `wp_1_options` 298 | etc... 299 | 300 | However, if they do not have a numerical prefix as follows, then they cannot be moved from the global database (the table names are dependent on how/when multisite was installed). 301 | `wp_posts` 302 | `wp_options` 303 | etc... 304 | 305 | All done with db-config.php? Save your file! 306 | 307 | ## Configuring move-blogs.php 308 | Now open `move-blogs.php` in your text editor. 309 | 310 | This file is much simpler to configure as we only need to enter a few bits of data. 311 | 312 | However, please take care to enter the data exactly as described below. 313 | 314 | * Line 19: Change `old_db_name` to the name of your current database. Following the same examples we’ve been using from the beginning, you would enter dbname here. **Important: do NOT add an underscore ( _ ) here.** 315 | * Line 20: If the main prefix of your current database tables is the default `wp_`, you can leave this as-is. However, if you have changed the prefix of your current database tables, enter that here. 316 | * Line 21: Change `newdbname` to the prefix used for all your new databases. Following the examples we’ve been using, you would enter `dbname_ `here (with the underscore this time, which designates the database prefix). 317 | * Line 25: Change user to the username currently associated with your database. This must not be any of the new usernames you may have created in the previous steps. 318 | * Line 26: Change pass to the password currently associated with your database. Again, this should not be any of the new passwords you may have created earlier. 319 | Line 29: Change 256 to the number of databases you created at the beginning (16, 256 or 4096). 320 | 321 | The screenshot below shows what the move-blogs.php file would look like with all the same sample data as given throughout this usage guide. Yours will, of course, contain your own data. :) 322 | 323 | ![Multi-DB Files Uploaded](https://premium.wpmudev.org/wp-content/uploads/2008/08/multi-db-3240-move-blogs.png) 324 | 325 | All done with `move-blogs.php`? Remember to save that file too. 326 | 327 | ## Uploading the Plugin Files 328 | 329 | NOW it’s time. Here is where all our labor finally pays off. You did double and triple check everything above, right? 330 | 331 | There are 3 files we need to upload: the 2 you just edited – `db-config.php` and `move-blogs.php` – as well as the `db.php` file which does not require any edits. 332 | 333 | Upload both `db.php` and the `db-config.php` that you edited to your `wp-content` folder. 334 | 335 | You can upload the files either via FTP, or use the File Manager in your cPanel. 336 | The screenshot below shows the result of the upload via FTP using FileZilla. 337 | 338 | ![Multi-DB Files Uploaded](https://premium.wpmudev.org/wp-content/uploads/2008/08/multi-db-3240-files-uploaded-1.png) 339 | 340 | Next, we want to upload `move-blogs.php`. We recommend creating a folder inside `wp-content` called `scripts` and uploading the file there. Some hosts may prevent direct access to your `wp-content` folder, in which case you can create or move your `/scripts/` directory to the root directory of your WP installation. Your scripts directory will need execute permissions in order for this to work correctly. 341 | 342 | It really doesn’t matter though, as long as you remember where you put it, as we’ll need to head there in our web browser next. 343 | 344 | 345 | ## Final Step: Copy & Verify DBs 346 | 347 | We’re almost done! This last step is the one that actually copies existing tables to their respective databases according to the configuration you just completed, and ensures that new blogs/sites get properly distributed amongst those new databases. 348 | 349 | Open up your web browser and enter the full URL to the `move-blogs.php` file on your server. If you created a scripts folder and uploaded it there, the URL would look like this (of course, replace yourdomain.com with your actual site name): 350 | 351 | ``` 352 | http://yourdomain.com/wp-content/scripts/move-blogs.php 353 | ``` 354 | 355 | You’ll see that there are 10 instructions at the top of this page. 356 | 357 | ![Multi-DB Move Blogs Tool](https://premium.wpmudev.org/wp-content/uploads/2008/08/multi-db-3240-move-blogs-tool.png) 358 | 359 | Simply follow the instructions at the top of that screen. The main things to check are: 360 | 361 | * The `new db` column should display a green `exists` on each line. 362 | * The `status` column should show `not in new db` on each line. 363 | 364 | When you’ve verified that everything looks right, click the link in step 5 of that screen. Once the process completes, click the link in step 7 to refresh the page. You should now see 'table in new db' under the status column for each row. 365 | 366 | If all is good there, then you have successfully completed your multi-db installation! Congratulations! 367 | 368 | ## Upgrade Instructions 369 | 370 | To upgrade from one version of Multi-DB to another, unless otherwise noted, you can simply upload the `db.php` file from the new version to overwrite the old one. 371 | 372 | If you have trouble with any aspect of configuration, or if you have a cool feature suggestion to make, please head on over to the community forums where support staff and other helpful members are waiting to lend a hand. 373 | -------------------------------------------------------------------------------- /db-config-sample-16.php: -------------------------------------------------------------------------------- 1 | 6 |

You must be logged in to access this tool.

7 | 10 |

11 | Incsub DB Tools
12 | ====================================================================
13 | DB List | DB SQL | DB Servers | DB Array | MD5
14 | ==================================================================== 15 |

16 |
17 | 18 | DB Name: ex: yoursite_
19 | 24 | 25 |
26 | 27 | '; 30 | $hash_list[0] = '0'; 31 | $hash_list[1] = '1'; 32 | $hash_list[2] = '2'; 33 | $hash_list[3] = '3'; 34 | $hash_list[4] = '4'; 35 | $hash_list[5] = '5'; 36 | $hash_list[6] = '6'; 37 | $hash_list[7] = '7'; 38 | $hash_list[8] = '8'; 39 | $hash_list[9] = '9'; 40 | $hash_list[10] = 'a'; 41 | $hash_list[11] = 'b'; 42 | $hash_list[12] = 'c'; 43 | $hash_list[13] = 'd'; 44 | $hash_list[14] = 'e'; 45 | $hash_list[15] = 'f'; 46 | ?> 47 |
48 | 84 |
85 | 88 | 91 | -------------------------------------------------------------------------------- /db-tools/db_array.php: -------------------------------------------------------------------------------- 1 | 6 |

You must be logged in to access this tool.

7 | 10 |

11 | Incsub DB Tools
12 | ====================================================================
13 | DB List | DB SQL | DB Servers | DB Array | MD5
14 | ==================================================================== 15 |

16 |
17 | 18 | DB Name: ex: yoursite_
19 | DB Host:
20 | DB User:
21 | DB Pass:
22 | 27 | 28 |
29 | 30 | '; 33 | $hash_list[0] = '0'; 34 | $hash_list[1] = '1'; 35 | $hash_list[2] = '2'; 36 | $hash_list[3] = '3'; 37 | $hash_list[4] = '4'; 38 | $hash_list[5] = '5'; 39 | $hash_list[6] = '6'; 40 | $hash_list[7] = '7'; 41 | $hash_list[8] = '8'; 42 | $hash_list[9] = '9'; 43 | $hash_list[10] = 'a'; 44 | $hash_list[11] = 'b'; 45 | $hash_list[12] = 'c'; 46 | $hash_list[13] = 'd'; 47 | $hash_list[14] = 'e'; 48 | $hash_list[15] = 'f'; 49 | ?> 50 |
51 | 105 |
106 | 109 | 112 | -------------------------------------------------------------------------------- /db-tools/db_servers.php: -------------------------------------------------------------------------------- 1 | 6 |

You must be logged in to access this tool.

7 | 10 |

11 | Incsub DB Tools
12 | ====================================================================
13 | DB List | DB SQL | DB Servers | DB Array | MD5
14 | ==================================================================== 15 |

16 |
17 | 18 | DB Name: ex: yoursite_
19 | DB User:
20 | DB Pass:
21 | DB Local Host:
22 | DB Remote Host:
23 | 28 | 29 |
30 | 31 | '; 34 | $hash_list[0] = '0'; 35 | $hash_list[1] = '1'; 36 | $hash_list[2] = '2'; 37 | $hash_list[3] = '3'; 38 | $hash_list[4] = '4'; 39 | $hash_list[5] = '5'; 40 | $hash_list[6] = '6'; 41 | $hash_list[7] = '7'; 42 | $hash_list[8] = '8'; 43 | $hash_list[9] = '9'; 44 | $hash_list[10] = 'a'; 45 | $hash_list[11] = 'b'; 46 | $hash_list[12] = 'c'; 47 | $hash_list[13] = 'd'; 48 | $hash_list[14] = 'e'; 49 | $hash_list[15] = 'f'; 50 | ?> 51 |
52 | 97 |
98 | 101 | 104 | -------------------------------------------------------------------------------- /db-tools/db_sql.php: -------------------------------------------------------------------------------- 1 | 6 |

You must be logged in to access this tool.

7 | 10 |

11 | Incsub DB Tools
12 | ====================================================================
13 | DB List | DB SQL | DB Servers | DB Array | MD5
14 | ==================================================================== 15 |

16 |
17 | 18 | DB Name: ex: yoursite_
19 | 24 | 25 |
26 | 27 | '; 30 | $hash_list[0] = '0'; 31 | $hash_list[1] = '1'; 32 | $hash_list[2] = '2'; 33 | $hash_list[3] = '3'; 34 | $hash_list[4] = '4'; 35 | $hash_list[5] = '5'; 36 | $hash_list[6] = '6'; 37 | $hash_list[7] = '7'; 38 | $hash_list[8] = '8'; 39 | $hash_list[9] = '9'; 40 | $hash_list[10] = 'a'; 41 | $hash_list[11] = 'b'; 42 | $hash_list[12] = 'c'; 43 | $hash_list[13] = 'd'; 44 | $hash_list[14] = 'e'; 45 | $hash_list[15] = 'f'; 46 | ?> 47 |
48 | 90 |
91 | 94 | 97 | -------------------------------------------------------------------------------- /db-tools/index.php: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /db-tools/md5.php: -------------------------------------------------------------------------------- 1 | 6 |

You must be logged in to access this tool.

7 | 10 |

11 | Incsub DB Tools
12 | ====================================================================
13 | DB List | DB SQL | DB Servers | DB Array | MD5
14 | ==================================================================== 15 |

16 |
17 | 18 | 19 | 20 |
21 | 22 | 27 | 30 | -------------------------------------------------------------------------------- /db.php: -------------------------------------------------------------------------------- 1 | $dc ) { 144 | if ( substr( $_SERVER['SERVER_ADDR'], 0, strlen( $dc_ip ) ) == $dc_ip ) { 145 | define( 'DATACENTER', $dc ); 146 | break; 147 | } 148 | } 149 | } 150 | 151 | if ( file_exists( WP_CONTENT_DIR . '/db-list.php' ) ) { 152 | require_once WP_CONTENT_DIR . '/db-list.php'; 153 | } 154 | 155 | // To allow extending of database class 156 | $wpdb = 'we-need-to-pre-populate-this-variable'; 157 | require_once ABSPATH . WPINC . '/wp-db.php'; 158 | 159 | if ( !defined( 'MULTI_DB_VERSION' ) ) define( 'MULTI_DB_VERSION', '4.0' ); 160 | if ( !defined( 'WP_USE_MULTIPLE_DB' ) ) define( 'WP_USE_MULTIPLE_DB', false ); 161 | if ( !defined( 'DB_SCALING' ) ) define( 'DB_SCALING', '16' ); 162 | if ( !defined( 'EZSQL_VERSION' ) ) define( 'EZSQL_VERSION', 'WP1.25' ); 163 | if ( !defined( 'OBJECT' ) ) define( 'OBJECT', 'OBJECT', true ); 164 | if ( !defined( 'OBJECT_K' ) ) define( 'OBJECT_K', 'OBJECT_K', false ); 165 | if ( !defined( 'ARRAY_A' ) ) define( 'ARRAY_A', 'ARRAY_A', false ); 166 | if ( !defined( 'ARRAY_N' ) ) define( 'ARRAY_N', 'ARRAY_N', false ); 167 | 168 | /** 169 | * Multi-DB database access abstraction class. 170 | */ 171 | class m_wpdb extends wpdb { 172 | 173 | /** 174 | * The array of open connections. 175 | * 176 | * @access protected 177 | * @var array 178 | */ 179 | var $dbh_connections = array(); 180 | 181 | /** 182 | * The maximum number of open connections. 183 | * 184 | * @access protected 185 | * @var type 186 | */ 187 | var $max_connections = 10; 188 | 189 | /** 190 | * Current database handle 191 | * 192 | * @access protected 193 | * @var resource 194 | */ 195 | var $dbh; 196 | 197 | /** 198 | * Global database handle 199 | * 200 | * @access protected 201 | * @var resource 202 | */ 203 | var $dbhglobal; 204 | 205 | /** 206 | * The array containing the last query data received from analyze_query method. 207 | * 208 | * @access protected 209 | * @var array 210 | */ 211 | protected $_last_query_data; 212 | 213 | /** 214 | * Connects to the database server and selects a database 215 | * 216 | * @access public 217 | * @param string $dbuser MySQL database user 218 | * @param string $dbpassword MySQL database password 219 | * @param string $dbname MySQL database name 220 | * @param string $dbhost MySQL database host 221 | */ 222 | public function __construct( $dbuser, $dbpassword, $dbname, $dbhost ) { 223 | register_shutdown_function( array( $this, '__destruct' ) ); 224 | $this->use_mysqli=true; 225 | if ( WP_DEBUG && WP_DEBUG_DISPLAY ) { 226 | $this->show_errors(); 227 | } 228 | 229 | $this->init_charset(); 230 | 231 | $this->dbuser = $dbuser; 232 | $this->dbpassword = $dbpassword; 233 | $this->dbname = $dbname; 234 | $this->dbhost = $dbhost; 235 | 236 | // Try to connect to the database 237 | $global = $this->_get_global_read(); 238 | $this->dbhglobal = mysqli_connect( $global['host'], $global['user'], $global['password'] ); 239 | 240 | $this->dbh = mysqli_connect( $global['host'], $global['user'], $global['password'] ); 241 | 242 | if ( ! $this->dbhglobal ) { 243 | $this->_bail_db_connection_error(); 244 | } 245 | 246 | $this->set_charset( $this->dbhglobal ); 247 | $this->ready = true; 248 | 249 | $this->select( $global['name'], $this->dbhglobal ); 250 | } 251 | 252 | /** 253 | * Wraps database connection error in a nice header and footer and dies. 254 | * Will not die if wpdb::$show_errors is false. 255 | * 256 | * @access private 257 | * @return false|void 258 | */ 259 | private function _bail_db_connection_error() { 260 | return $this->bail( sprintf( /*WP_I18N_DB_CONN_ERROR*/" 261 |

Error finding a global database

262 |

This either means that the username and password information in your db-config.php file is incorrect, you haven't declared a global database or we can't contact the global database server. This could mean your host's database server is down.

263 | 268 |

If you're unsure what these terms mean you should probably contact your host. If you still need help you can always visit the WordPress Support Forums.

269 | "/*/WP_I18N_DB_CONN_ERROR*/ ), 'db_connect_fail' ); 270 | } 271 | 272 | /** 273 | * Returns global database information 274 | * 275 | * @access private 276 | * @global array $db_servers The array of databases. 277 | * @return boolean|array The global database information on success, otherwise FALSE. 278 | */ 279 | private function _get_global_read() { 280 | global $db_servers; 281 | 282 | if ( is_array( $db_servers['global'] ) ) { 283 | if ( count( $db_servers['global'] ) > 1 ) { 284 | $dc = defined( 'DATACENTER' ) ? DATACENTER : false; 285 | foreach ( $db_servers['global'] as $global ) { 286 | if ( $global['dc'] == $dc && $global['read'] > 0 ) { 287 | return $global; 288 | } 289 | } 290 | 291 | // If still here we can't find a local readable global database so return first readable one 292 | foreach ( $db_servers['global'] as $global ) { 293 | if ( $global['read'] > 0 ) { 294 | return $global; 295 | } 296 | } 297 | 298 | // Nope, none of those either so exit. 299 | return false; 300 | } else { 301 | return $db_servers['global'][0]; 302 | } 303 | } 304 | 305 | return false; 306 | } 307 | 308 | /** 309 | * Real escapes, using mysqli_real_escape_string() or addslashes() 310 | * 311 | * @see mysqli_real_escape_string() 312 | * @see addslashes() 313 | * 314 | * @access private 315 | * @param string $string The string to escape. 316 | * @return string Escaped string. 317 | */ 318 | function _real_escape( $string ) { 319 | if ( is_object( $this->dbhglobal ) ) 320 | return mysqli_real_escape_string( $this->dbhglobal,$string ); 321 | else 322 | return addslashes( $string ); 323 | } 324 | 325 | /** 326 | * Returns global database version number. 327 | * 328 | * @access public 329 | * @return false|string The version number on success, otherwise FALSE. 330 | */ 331 | public function db_version() { 332 | return is_object( $this->dbhglobal ) ? 333 | preg_replace( '/[^0-9.].*/', '', mysqli_get_server_info( $this->dbhglobal ) ) 334 | : false; 335 | } 336 | 337 | /** 338 | * Returns all tables available in the database. 339 | * 340 | * @filter tables_to_repair 341 | * 342 | * @access public 343 | * @param array $tables The initial array of tables. 344 | * @return array The array of database tables. 345 | */ 346 | public function get_all_tables( $tables ) { 347 | $blogs_ids = $this->get_col( "SELECT blog_id FROM {$this->base_prefix}blogs WHERE deleted = 0 AND spam = 0 AND archived = '0'" ); 348 | 349 | foreach ( $blogs_ids as $blog_id ) { 350 | $new_tables = $this->get_col( "SHOW TABLES LIKE '{$this->base_prefix}{$blog_id}_%';" ); 351 | if ( $new_tables && is_array( $new_tables ) && count( $new_tables ) > 0 ) { 352 | $tables = array_merge( $tables, $new_tables ); 353 | } 354 | } 355 | 356 | return $tables; 357 | } 358 | 359 | /** 360 | * Connects to database based on incoming query. 361 | * 362 | * @access public 363 | * @param string $query The query which will be executed. 364 | * @return boolean|resource The database connection resource on success, otherwise FALSE. 365 | */ 366 | public function db_connect( $query = 'SELECT 1' ) { 367 | if ( empty( $query ) ) { 368 | return false; 369 | } 370 | 371 | $dbh = false; 372 | $this->_last_query_data = $query_data = $this->analyze_query( $query ); 373 | $this->last_table = $query_data['table_name']; 374 | $this->last_db_used = $query_data['query_type']; 375 | 376 | $operation = $query_data['query_type'] == 'write' ? 'write' : 'read'; 377 | 378 | // Return a global read database as if already have it connected 379 | if ( $operation == 'read' && $query_data['dataset'] == 'global' && is_object( $this->dbhglobal ) ) { 380 | return $this->dbhglobal; 381 | } 382 | 383 | if ( $query_data['query_type'] == 'write' && defined( 'MASTER_DB_DEAD' ) ) { 384 | die( "We're updating the database, please try back in 5 minutes. If you are posting to your blog please hit the refresh button on your browser in a few minutes to post the data again. It will be posted as soon as the database is back online again." ); 385 | } 386 | 387 | // check if we're already connected. 388 | $dataset_key = "{$query_data['dataset']}.{$operation}"; 389 | if ( isset( $this->dbh_connections[$dataset_key] ) && is_object( $this->dbh_connections[$dataset_key]['connection'] ) ) { 390 | return $this->dbh_connections[$dataset_key]['connection']; 391 | } 392 | 393 | foreach ( self::_get_servers( $query_data['dataset'], $operation ) as $server ) { 394 | if ( ( $dbh = $this->_connect_to_server( $server, $query_data['dataset'], $operation ) ) ) { 395 | return $dbh; 396 | } 397 | } 398 | 399 | $this->_bail_db_connection_error(); 400 | return false; 401 | } 402 | 403 | /** 404 | * Closes MySQL connection to a database. 405 | * 406 | * @access public 407 | * @param string $dbhname The database name to close connection to. 408 | */ 409 | public function disconnect( $dbhname ) { 410 | if ( isset( $this->dbh_connections[$dbhname]['connection'] ) && is_object( $this->dbh_connections[$dbhname]['connection'] ) ) { 411 | mysqli_close( $this->dbh_connections[$dbhname]['connection'] ); 412 | unset( $this->dbh_connections[$dbhname] ); 413 | } 414 | } 415 | 416 | /** 417 | * Sanitizes select query's table names by adding database prefixes. 418 | * 419 | * This function solves the issue when we have JOINs in a select query, 420 | * which connects global tables from global database. For instance: 421 | * 422 | * SELECT * FROM {$wpdb->posts} AS p LEFT JOIN {$wpdb->users} AS u ON u.ID = p.post_author WHERE p.ID = 2; 423 | * 424 | * @since 3.1.2 425 | * @filter query 426 | * 427 | * @access public 428 | * @global array $global_tables The array of globals tables. 429 | * @param string $query The initial query. 430 | * @return string Sanitized query. 431 | */ 432 | public function sanitize_multidb_query_tables( $query ) { 433 | global $global_tables; 434 | 435 | // look through all local tables and add blog database prefix if it has been found 436 | if ( $this->blogid > 1 ) { 437 | 438 | // add whitespace at the end of the query to make our patterns working properly 439 | $query = trim( $query ) . ' '; 440 | 441 | $blog_database = self::_get_servers( self::_get_blog_dataset( $this->blogid ), 'read' ); 442 | if ( empty( $blog_database ) ) { 443 | return $query; 444 | } 445 | 446 | $global = $this->_get_global_read(); 447 | 448 | //if not on same physical mysql server, and same username, we can't do joins 449 | if ( $global[0]['host'] != $blog_database[0]['host'] || $global[0]['user'] != $blog_database[0]['user']) { 450 | return $query; 451 | } 452 | 453 | // don't touch non select queries. 454 | if ( !preg_match( '/^SELECT\s+/is', $query ) ) { 455 | return $query; 456 | } 457 | 458 | if ( ! preg_match( '/^JOIN\s+/is', $query ) ) { 459 | return $query; 460 | } 461 | 462 | $global_prefix = isset( $this->base_prefix ) ? $this->base_prefix : $this->prefix; 463 | 464 | // look through all global tables and add global database prefix if it has been found 465 | foreach ( $global_tables as $table ) { 466 | $query = preg_replace( "/\s{$global_prefix}{$table}(\s|\.|,)/", " {$global['name']}.{$global_prefix}{$table}$1", $query ); 467 | } 468 | 469 | $blog_database = $blog_database[0]['name']; 470 | $query = preg_replace( "/\s{$this->prefix}(.*?)(\s|\.|,|\()/", " {$blog_database}.{$this->prefix}$1$2", $query ); 471 | } 472 | 473 | return trim( $query ); 474 | } 475 | 476 | /** 477 | * Performs a MySQL database query, using current database connection. 478 | * 479 | * @access public 480 | * @param string $query Database query to execute. 481 | * @return int|false Number of rows affected/selected or false on error 482 | */ 483 | public function query( $query ) { 484 | if ( !$this->ready ) { 485 | return false; 486 | } 487 | 488 | // some queries are made before the plugins have been loaded, and thus cannot be filtered with this method 489 | if ( function_exists( 'apply_filters' ) ) { 490 | $query = apply_filters( 'query', $query ); 491 | } 492 | 493 | $return_val = 0; 494 | $this->flush(); 495 | 496 | // use $this->dbh for read ops, and $this->dbhwrite for write ops 497 | // use $this->dbhglobal for gloal table ops 498 | //unset( $dbh ); 499 | 500 | // Test the global is set and if not then set it 501 | $dbh = $this->db_connect( $query ); 502 | if ( !is_object( $dbh ) ) { 503 | $this->_bail_db_connection_error(); 504 | return false; 505 | } 506 | 507 | // Log how the function was called 508 | $this->func_call = '$db->query("' . $query . '")'; 509 | // Keep track of the last query for debug.. 510 | $this->last_query = $query; 511 | 512 | if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) { 513 | $this->timer_start(); 514 | } 515 | 516 | $this->result = mysqli_query( $dbh, $query ); 517 | $this->num_queries++; 518 | 519 | if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) { 520 | $this->queries[] = array( $query, $this->timer_stop(), $this->get_caller() ); 521 | } 522 | 523 | // If there is an error then take note of it.. 524 | if ( is_object( $dbh ) && ( $this->last_error = mysqli_error( $dbh ) ) ) { 525 | $this->print_error( $this->last_error ); 526 | return false; 527 | } 528 | 529 | //Remove carriage returns https://stackoverflow.com/questions/3059091/how-to-remove-carriage-returns-from-output-of-string 530 | $query=trim(preg_replace('~[[:cntrl:]]~', ' ', $query)); 531 | 532 | if ( preg_match( "/^\\s*(insert|delete|update|replace|alter|create|drop|truncate) /i", $query ) ) { 533 | $this->rows_affected = mysqli_affected_rows( $dbh ); 534 | // Take note of the insert_id 535 | if ( preg_match( "/^\\s*(insert|replace) /i", $query ) ) { 536 | $this->insert_id = mysqli_insert_id( $dbh ); 537 | } 538 | // Return number of rows affected 539 | $return_val = $this->rows_affected; 540 | } else { 541 | $i = 0; 542 | $thefield_count=$this->result->field_count; 543 | while ( $i < $thefield_count ) { 544 | $this->col_info[$i] = mysqli_fetch_field( $this->result ); 545 | $i++; 546 | } 547 | 548 | $num_rows = 0; 549 | while ( $row = $this->result->fetch_object() ) { 550 | $this->last_result[$num_rows] = $row; 551 | $num_rows++; 552 | } 553 | 554 | //mysqli_free_result( $this->result ); 555 | 556 | // Log number of rows the query returned and return number of rows selected 557 | $this->num_rows = $num_rows; 558 | $return_val = $num_rows; 559 | } 560 | 561 | return $return_val; 562 | } 563 | 564 | /** 565 | * Returns connection information based on incoming query. 566 | * 567 | * @access public 568 | * @global type $original_table_prefix 569 | * @global type $global_tables 570 | * @param string $query The query string to analyze. 571 | * @return array The connection information array. 572 | */ 573 | public function analyze_query( $query ) { 574 | global $original_table_prefix, $global_tables; 575 | 576 | //Remove carriage returns https://stackoverflow.com/questions/3059091/how-to-remove-carriage-returns-from-output-of-string 577 | $query=trim(preg_replace('~[[:cntrl:]]~', ' ', $query)); 578 | // trim query 579 | $query = rtrim( trim( $query ), ';' ); 580 | // Set initial force local stuff. 581 | $forcelocal = false; 582 | 583 | $maybe = $return = array(); 584 | $table_name = 'unknown'; 585 | if ( preg_match( '/^SELECT.*?\s+FROM\s+`?([0-9,a-z,A-Z$_\.]+)`?\s*/is', $query, $maybe ) ) { 586 | $table_name = $maybe[1]; 587 | } else if ( preg_match( '/^UPDATE IGNORE\s+`?([0-9,a-z,A-Z$_]+)`?\s*/is', $query, $maybe ) ) { 588 | $table_name = $maybe[1]; 589 | } else if ( preg_match( '/^UPDATE\s+`?([0-9,a-z,A-Z$_]+)`?\s*/is', $query, $maybe ) ) { 590 | $table_name = $maybe[1]; 591 | } else if ( preg_match( '/^INSERT.*?\s+INTO\s+`?([0-9,a-z,A-Z$_]+)`?[\(\s]/is', $query, $maybe ) ) { 592 | $table_name = $maybe[1]; 593 | } else if ( preg_match( '/^REPLACE.*?\s+INTO\s+`?([0-9,a-z,A-Z$_]+)`?[\(\s]/is', $query, $maybe ) ) { 594 | $table_name = $maybe[1]; 595 | } else if ( preg_match( '/^DELETE.*?\s+FROM\s+`?([0-9,a-z,A-Z$_]+)`?\s*/is', $query, $maybe ) ) { 596 | $table_name = $maybe[1]; 597 | } else if ( preg_match( '/^(?:TRUNCATE|RENAME|OPTIMIZE|LOCK|UNLOCK)\s+TABLE\s+`?([0-9,a-z,A-Z$_]+)`?\s*/is', $query, $maybe ) ) { 598 | $table_name = $maybe[1]; 599 | } else if ( preg_match( '/^(?:TRUNCATE|RENAME|OPTIMIZE|LOCK|UNLOCK)\s+`?([0-9,a-z,A-Z$_]+)`?\s*/is', $query, $maybe ) ) { 600 | $table_name = $maybe[1]; 601 | } else if ( preg_match( '/^SHOW TABLE STATUS (LIKE|FROM) \'?`?([0-9,a-z,A-Z$_]+)\'?`?\s*/is', $query, $maybe ) ) { 602 | $table_name = $maybe[1]; 603 | } else if ( preg_match( '/^SHOW TABLES LIKE \'?`?([0-9,a-z,A-Z$_]+)\'?`?\s*/is', $query, $maybe ) ) { 604 | $table_name = $maybe[1]; 605 | } else if ( preg_match( '/^SHOW TABLES/is', $query, $maybe ) ) { 606 | $forcelocal = true; 607 | } else if ( preg_match( '/^SHOW INDEX FROM `?([0-9,a-z,A-Z$_]+)`?\s*/is', $query, $maybe ) ) { 608 | $table_name = $maybe[1]; 609 | } else if ( preg_match( '/^SHOW\s+\w*\s*COLUMNS (?:FROM|IN) `?([0-9,a-z,A-Z$_]+)`?\s*/is', $query, $maybe ) ) { 610 | $table_name = $maybe[1]; 611 | } else if ( preg_match( '/^CREATE\s+TABLE\s+IF\s+NOT\s+EXISTS\s+`?([0-9,a-z,A-Z$_]+)`?\s+/is', $query, $maybe ) ) { 612 | $table_name = $maybe[1]; 613 | } else if ( preg_match( '/^SHOW CREATE TABLE `?([0-9,a-z,A-Z$_]+?)`?\s*/is', $query, $maybe ) ) { 614 | $table_name = $maybe[1]; 615 | } else if ( preg_match( '/^CREATE\s+TABLE\s+`?([0-9,a-z,A-Z$_]+)`?\s*/is', $query, $maybe ) ) { 616 | $table_name = $maybe[1]; 617 | } else if ( preg_match( '/^DROP\s+TABLE\s+IF\s+EXISTS\s+`?([0-9,a-z,A-Z$_]+)`?\s*/is', $query, $maybe ) ) { 618 | $table_name = $maybe[1]; 619 | } else if ( preg_match( '/^DROP\s+TABLE\s+`?([0-9,a-z,A-Z$_]+)`?\s*/is', $query, $maybe ) ) { 620 | $table_name = $maybe[1]; 621 | } else if ( preg_match( '/^DESCRIBE\s+`?([0-9,a-z,A-Z$_]+)`?\s*/is', $query, $maybe ) ) { 622 | $table_name = $maybe[1]; 623 | } else if ( preg_match( '/^ALTER\s+TABLE\s+`?([0-9,a-z,A-Z$_]+)`?\s+/is', $query, $maybe ) ) { 624 | $table_name = $maybe[1]; 625 | } else if ( preg_match( '/^CHECK\s+TABLE\s+?([0-9,a-z,A-Z$_]+)?\s*/is', $query, $maybe ) ) { 626 | $table_name = $maybe[1]; 627 | } else if ( preg_match( '/^ANALYZE\s+TABLE\s+`?([0-9,a-z,A-Z$_]+)`?\s*/is', $query, $maybe ) ) { 628 | $table_name = $maybe[1]; 629 | } else { 630 | $select_without_from = preg_match( '/^SELECT\s+/is', $query ) && !preg_match( '/^SELECT.*?\s+FROM\s+`?([0-9,a-z,A-Z$_]+)`?\s*/is', $query ); 631 | $transaction_stuff = preg_match( '/^(START TRANSACTION|BEGIN|COMMIT|ROLLBACK)/is', $query ); 632 | $set = preg_match( '/^SET\s+/is', $query ); 633 | if ( $select_without_from || $transaction_stuff || $set ) { 634 | if ( $this->_last_query_data ) { 635 | return $this->_last_query_data; 636 | } 637 | } 638 | } 639 | 640 | $table_name = explode( '.', $table_name ); 641 | $table_name = array_pop( $table_name ); 642 | 643 | // determine whether global or blog table type is 644 | $blog_id = false; 645 | if ( $forcelocal == true ) { 646 | $table_type = 'blog'; 647 | $blog_id = $this->blogid; 648 | } else { 649 | $base_table_name = substr( $table_name, strlen( $original_table_prefix ) ); 650 | if ( in_array( $base_table_name, $global_tables ) ) { 651 | // This is a global table 652 | $table_type = 'global'; 653 | $blog_id = 'global'; 654 | } else { 655 | // Should be a blog related table 656 | $table_type = 'blog'; 657 | 658 | $base_match = array(); 659 | if ( preg_match( "|^[0-9]{1,20}_?|", $base_table_name, $base_match ) && isset( $base_match[0] ) ) { 660 | $base_table_name = str_replace( $base_match[0], '', $base_table_name ); 661 | } 662 | 663 | if ( preg_match( "|^{$original_table_prefix}([0-9]{1,20})_?{$base_table_name}|", $table_name, $match ) ) { 664 | $blog_id = absint( $match[1] ); 665 | } 666 | } 667 | } 668 | 669 | $query_type = 'read'; 670 | $patterns = array( 671 | '/^UPDATE/is', 672 | '/^INSERT/is', 673 | '/^REPLACE/is', 674 | '/^DELETE/is', 675 | '/^OPTIMIZE/is', 676 | '/^SHOW\s+TABLE\s+STATUS/is', 677 | '/^CREATE\s+TABLE/is', 678 | '/^TRUNCATE\s+TABLE/is', 679 | '/^SHOW\s+CREATE\s+TABLE/is', 680 | '/^DROP\s+TABLE/is', 681 | '/^ALTER\s+TABLE/is', 682 | '/^RENAME\s+TABLE/i', 683 | ); 684 | 685 | foreach ( $patterns as $pattern ) { 686 | if ( preg_match( $pattern, $query ) ) { 687 | $query_type = 'write'; 688 | break; 689 | } 690 | } 691 | 692 | // dataset 693 | if ( $table_type == 'global' ) { 694 | $dataset = 'global'; 695 | } elseif ( $table_type == 'blog' ) { 696 | // check if the blog_id is set. 697 | if ( empty( $blog_id ) ) { 698 | // we are on a multi-site blog without a number, or we have an unidentified global table 699 | $blog_id = 'global'; 700 | $dataset = 'global'; 701 | } else { 702 | $dataset = self::_get_blog_dataset( $blog_id ); 703 | } 704 | } 705 | 706 | $return['table_name'] = $table_name; 707 | $return['table_type'] = $table_type; 708 | $return['blog_id'] = $blog_id; 709 | $return['query_type'] = $query_type; 710 | $return['dataset'] = $dataset; 711 | 712 | return $return; 713 | } 714 | 715 | /** 716 | * Returns blog dataset. 717 | * 718 | * @since 3.2.0 719 | * 720 | * @static 721 | * @access protected 722 | * @param int $blog_id The blog ID. 723 | * @return string The dataset string. 724 | */ 725 | protected static function _get_blog_dataset( $blog_id ) { 726 | global $vip_blogs_datasets; 727 | 728 | //check if this is a VIP blog 729 | if ( isset( $vip_blogs_datasets[ $blog_id ] ) ) { 730 | return $vip_blogs_datasets[ $blog_id ]; 731 | } 732 | 733 | $hash_value = md5( $blog_id ); 734 | if ( defined( 'DB_SCALING' ) ) { 735 | if ( DB_SCALING == 4096 ) { 736 | return substr( $hash_value, 0, 3 ); 737 | } elseif ( DB_SCALING == 256 ) { 738 | return substr( $hash_value, 0, 2 ); 739 | } 740 | } 741 | 742 | return substr( $hash_value, 0, 1 ); 743 | } 744 | 745 | /** 746 | * Returns the array of appropriate servers to connect to. 747 | * 748 | * @since 3.2.0 749 | * 750 | * @static 751 | * @access protected 752 | * @global array $db_servers The array of database servers. 753 | * @param string $dataset The current dataset to use. 754 | * @param string $operation The operation type (read/write). 755 | * @return array The array of servers to connect to. 756 | */ 757 | protected static function _get_servers( $dataset, $operation ) { 758 | global $db_servers; 759 | 760 | $dc = defined( 'DATACENTER' ) ? DATACENTER : false; 761 | 762 | // Group eligible servers by R (plus 10,000 if remote) 763 | $server_groups = array(); 764 | if ( isset( $db_servers[$dataset] ) ) { 765 | foreach ( $db_servers[$dataset] as $server ) { 766 | if ( $server[$operation] ) { 767 | // Add a penality to those dbs not in our datacenter 768 | if ( $server['dc'] != $dc ) { 769 | $server[$operation] += 10000; 770 | } 771 | 772 | // Try the local hostname first when connecting within the DC 773 | if ( $server['dc'] == $dc ) { 774 | $lserver = $server; 775 | if ( isset( $lserver['lhost'] ) ) { 776 | $lserver['host'] = $lserver['lhost']; 777 | } 778 | 779 | $priority = $server[$operation] - 0.5; 780 | $server_groups["{$priority}"][] = $lserver; 781 | } 782 | 783 | $priority = $server[$operation]; 784 | $server_groups["{$priority}"][] = $server; 785 | } 786 | } 787 | } 788 | 789 | // Randomize each group and add its members to 790 | $servers = array(); 791 | ksort( $server_groups ); 792 | foreach ( $server_groups as $group ) { 793 | if ( count( $group ) > 1 ) { 794 | shuffle( $group ); 795 | } 796 | 797 | $servers = array_merge( $servers, $group ); 798 | } 799 | 800 | return $servers; 801 | } 802 | 803 | /** 804 | * Connects to the server. 805 | * 806 | * @since 3.2.0 807 | * 808 | * @access protected 809 | * @param array $server The server configuration info. 810 | * @param string $dataset The current dataset to use. 811 | * @param string $operation The operation type (read/write). 812 | * @return resource|boolean The MySQL connection on success, otherwise FALSE. 813 | */ 814 | protected function _connect_to_server( $server, $dataset, $operation ) { 815 | $dbh = mysqli_connect( $server['host'], $server['user'], $server['password'] ); 816 | if ( !is_object( $dbh ) ) { 817 | return false; 818 | } 819 | 820 | $this->set_charset( $dbh ); 821 | $this->select( $server['name'], $dbh ); 822 | 823 | // save connection 824 | $this->dbh_connections["{$dataset}.{$operation}"] = array( 825 | 'connection' => $dbh, 826 | 'name' => $server['name'], 827 | 'ds' => $server['ds'], 828 | 'dc' => $server['dc'], 829 | 'read' => $server['read'], 830 | 'write' => $server['write'], 831 | 'host' => $server['host'], 832 | 'user' => $server['user'], 833 | 'password' => $server['password'], 834 | 'lhost' => isset( $server['lhost'] ) ? $server['lhost'] : '', 835 | ); 836 | 837 | // disconnect old connection if total number of connections more then allowed one 838 | while ( $this->max_connections > 0 && count( $this->dbh_connections ) > $this->max_connections ) { 839 | reset( $this->dbh_connections ); 840 | $this->disconnect( key( $this->dbh_connections ) ); 841 | } 842 | 843 | return $dbh; 844 | } 845 | 846 | } 847 | 848 | // redefine database connection class 849 | $wpdb = new m_wpdb( DB_USER, DB_PASSWORD, DB_NAME, DB_HOST ); 850 | 851 | add_filter( 'tables_to_repair', array( $wpdb, 'get_all_tables' ) ); 852 | //add_filter( 'query', array( $wpdb, 'sanitize_multidb_query_tables' ) ); 853 | -------------------------------------------------------------------------------- /fix-db-encoding.php: -------------------------------------------------------------------------------- 1 | 18 | 19 | > 20 | 21 | 22 | <?php _e('Multi DB › Database Repair'); ?> 23 | 24 | 25 | 26 |

WordPress

27 | 28 | '.__('To allow use of this page to automatically repair database encoding problems and other commeon DB problems, please add the following line to your wp-config.php file. Once this line is added to your config, reload this page.')."

define('WP_ALLOW_REPAIR', true);"; 32 | } elseif ( isset($_GET['repair']) ) { 33 | $problems = array(); 34 | 35 | if ( 2 == $_GET['repair'] ) 36 | $optimize = true; 37 | else 38 | $optimize = false; 39 | 40 | $okay = true; 41 | 42 | $tables = $wpdb->tables(); 43 | // Sitecategories may not exist if global terms are disabled. 44 | if ( is_multisite() && ! $wpdb->get_var( "SHOW TABLES LIKE '$wpdb->sitecategories'" ) ) 45 | unset( $tables['sitecategories'] ); 46 | $tables = array_merge( $tables, (array) apply_filters( 'tables_to_repair', array() ) ); // Return tables with table prefixes. 47 | // Loop over the tables, checking and repairing as needed. 48 | foreach ( $tables as $table ) { 49 | if ($_GET['fix_100']) { 50 | $cols = $wpdb->get_results("SHOW FULL COLUMNS FROM `{$table}` WHERE (Type IN ('CHAR', 'TEXT', 'TINYTEXT', 'MEDIUMTEXT', 'LONGTEXT') OR Type LIKE 'VARCHAR%');"); 51 | } else { 52 | $cols = $wpdb->get_results("SHOW FULL COLUMNS FROM `{$table}` WHERE (Type IN ('CHAR', 'TEXT', 'TINYTEXT', 'MEDIUMTEXT', 'LONGTEXT') OR Type LIKE 'VARCHAR%') AND Collation NOT LIKE 'utf8%';"); 53 | } 54 | 55 | if (is_array($cols) && count($cols) > 0) { 56 | foreach ($cols as $col) { 57 | if ($_GET['fix_100']) { 58 | $wpdb->query("ALTER TABLE `{$table}` CHANGE {$col->Field} {$col->Field} {$col->Type} CHARACTER SET latin1 COLLATE latin1_general_ci;"); 59 | } 60 | switch (strtolower($col->Type)) { 61 | case 'longtext': 62 | $wpdb->query("ALTER TABLE `{$table}` CHANGE {$col->Field} {$col->Field} longblob;"); 63 | break; 64 | case 'mediumtext': 65 | $wpdb->query("ALTER TABLE `{$table}` CHANGE {$col->Field} {$col->Field} mediumblob;"); 66 | break; 67 | case 'tinytext': 68 | $wpdb->query("ALTER TABLE `{$table}` CHANGE {$col->Field} {$col->Field} tinyblob;"); 69 | break; 70 | case 'text': 71 | $wpdb->query("ALTER TABLE `{$table}` CHANGE {$col->Field} {$col->Field} blob;"); 72 | break; 73 | case 'char': 74 | $wpdb->query("ALTER TABLE `{$table}` CHANGE {$col->Field} {$col->Field} binary;"); 75 | break; 76 | case 'varchar': 77 | $wpdb->query("ALTER TABLE `{$table}` CHANGE {$col->Field} {$col->Field} varbinary;"); 78 | break; 79 | } 80 | $wpdb->query("ALTER TABLE `{$table}` CHANGE {$col->Field} {$col->Field} {$col->Type};"); 81 | } 82 | } 83 | 84 | $wpdb->query("ALTER TABLE `{$table}` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;"); 85 | 86 | $check = $wpdb->get_row("CHECK TABLE {$table}"); 87 | if ( 'OK' == $check->Msg_text ) { 88 | echo "

The $table table is okay."; 89 | } else { 90 | echo "

The $table table is not okay. It is reporting the following error: $check->Msg_text. WordPress will attempt to repair this table…"; 91 | $repair = $wpdb->get_row("REPAIR TABLE $table"); 92 | if ( 'OK' == $check->Msg_text ) { 93 | echo "
    Successfully repaired the $table table."; 94 | } else { 95 | echo "
    Failed to repair the $table table. Error: $check->Msg_text
"; 96 | $problems["$table"] = $check->Msg_text; 97 | $okay = false; 98 | } 99 | } 100 | if ( $okay && $optimize ) { 101 | $check = $wpdb->get_row("ANALYZE TABLE $table"); 102 | if ( 'Table is already up to date' == $check->Msg_text ) { 103 | echo "
    The $table table is already optimized."; 104 | } else { 105 | $check = $wpdb->get_row("OPTIMIZE TABLE $table"); 106 | if ( 'OK' == $check->Msg_text || 'Table is already up to date' == $check->Msg_text ) 107 | echo "
    Successfully optimized the $table table."; 108 | else 109 | echo "
    Failed to optimize the $table table. Error: $check->Msg_text"; 110 | } 111 | } 112 | echo '

'; 113 | } 114 | 115 | if ( !empty($problems) ) { 116 | printf('

'.__('Some database problems could not be repaired. Please copy-and-paste the following list of errors to the WordPress support forums to get additional assistance.').'

', 'http://wordpress.org/support/forum/3'); 117 | $problem_output = array(); 118 | foreach ( $problems as $table => $problem ) 119 | $problem_output[] = "$table: $problem"; 120 | echo ''; 121 | } else { 122 | echo '

'.__('Repairs complete. Please remove the following line from wp-config.php to prevent this page from being used by unauthorized users.')."

define('WP_ALLOW_REPAIR', true);"; 123 | } 124 | } else { 125 | if ( isset($_GET['referrer']) && 'is_blog_installed' == $_GET['referrer'] ) 126 | _e('One or more database tables are unavailable. To allow WordPress to attempt to repair these tables, press the “Repair Database” button. Repairing can take a while, so please be patient.'); 127 | else 128 | _e('WordPress can automatically look for some common database problems and repair them. Repairing can take a while, so please be patient.') 129 | ?> 130 |

131 |

132 | 133 |

134 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin St, Fifth Floor, Boston, MA 02110, USA 6 | 7 | Everyone is permitted to copy and distribute verbatim copies 8 | of this license document, but changing it is not allowed. 9 | 10 | Preamble 11 | 12 | The licenses for most software are designed to take away your 13 | freedom to share and change it. By contrast, the GNU General Public 14 | License is intended to guarantee your freedom to share and change free 15 | software--to make sure the software is free for all its users. This 16 | General Public License applies to most of the Free Software 17 | Foundation's software and to any other program whose authors commit to 18 | using it. (Some other Free Software Foundation software is covered by 19 | the GNU Library General Public License instead.) You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | this service if you wish), that you receive source code or can get it 26 | if you want it, that you can change the software or use pieces of it 27 | in new free programs; and that you know you can do these things. 28 | 29 | To protect your rights, we need to make restrictions that forbid 30 | anyone to deny you these rights or to ask you to surrender the rights. 31 | These restrictions translate to certain responsibilities for you if you 32 | distribute copies of the software, or if you modify it. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must give the recipients all the rights that 36 | you have. You must make sure that they, too, receive or can get the 37 | source code. And you must show them these terms so they know their 38 | rights. 39 | 40 | We protect your rights with two steps: (1) copyright the software, and 41 | (2) offer you this license which gives you legal permission to copy, 42 | distribute and/or modify the software. 43 | 44 | Also, for each author's protection and ours, we want to make certain 45 | that everyone understands that there is no warranty for this free 46 | software. If the software is modified by someone else and passed on, we 47 | want its recipients to know that what they have is not the original, so 48 | that any problems introduced by others will not reflect on the original 49 | authors' reputations. 50 | 51 | Finally, any free program is threatened constantly by software 52 | patents. We wish to avoid the danger that redistributors of a free 53 | program will individually obtain patent licenses, in effect making the 54 | program proprietary. To prevent this, we have made it clear that any 55 | patent must be licensed for everyone's free use or not licensed at all. 56 | 57 | The precise terms and conditions for copying, distribution and 58 | modification follow. 59 | 60 | GNU GENERAL PUBLIC LICENSE 61 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 62 | 63 | 0. This License applies to any program or other work which contains 64 | a notice placed by the copyright holder saying it may be distributed 65 | under the terms of this General Public License. The "Program", below, 66 | refers to any such program or work, and a "work based on the Program" 67 | means either the Program or any derivative work under copyright law: 68 | that is to say, a work containing the Program or a portion of it, 69 | either verbatim or with modifications and/or translated into another 70 | language. (Hereinafter, translation is included without limitation in 71 | the term "modification".) Each licensee is addressed as "you". 72 | 73 | Activities other than copying, distribution and modification are not 74 | covered by this License; they are outside its scope. The act of 75 | running the Program is not restricted, and the output from the Program 76 | is covered only if its contents constitute a work based on the 77 | Program (independent of having been made by running the Program). 78 | Whether that is true depends on what the Program does. 79 | 80 | 1. You may copy and distribute verbatim copies of the Program's 81 | source code as you receive it, in any medium, provided that you 82 | conspicuously and appropriately publish on each copy an appropriate 83 | copyright notice and disclaimer of warranty; keep intact all the 84 | notices that refer to this License and to the absence of any warranty; 85 | and give any other recipients of the Program a copy of this License 86 | along with the Program. 87 | 88 | You may charge a fee for the physical act of transferring a copy, and 89 | you may at your option offer warranty protection in exchange for a fee. 90 | 91 | 2. You may modify your copy or copies of the Program or any portion 92 | of it, thus forming a work based on the Program, and copy and 93 | distribute such modifications or work under the terms of Section 1 94 | above, provided that you also meet all of these conditions: 95 | 96 | a) You must cause the modified files to carry prominent notices 97 | stating that you changed the files and the date of any change. 98 | 99 | b) You must cause any work that you distribute or publish, that in 100 | whole or in part contains or is derived from the Program or any 101 | part thereof, to be licensed as a whole at no charge to all third 102 | parties under the terms of this License. 103 | 104 | c) If the modified program normally reads commands interactively 105 | when run, you must cause it, when started running for such 106 | interactive use in the most ordinary way, to print or display an 107 | announcement including an appropriate copyright notice and a 108 | notice that there is no warranty (or else, saying that you provide 109 | a warranty) and that users may redistribute the program under 110 | these conditions, and telling the user how to view a copy of this 111 | License. (Exception: if the Program itself is interactive but 112 | does not normally print such an announcement, your work based on 113 | the Program is not required to print an announcement.) 114 | 115 | These requirements apply to the modified work as a whole. If 116 | identifiable sections of that work are not derived from the Program, 117 | and can be reasonably considered independent and separate works in 118 | themselves, then this License, and its terms, do not apply to those 119 | sections when you distribute them as separate works. But when you 120 | distribute the same sections as part of a whole which is a work based 121 | on the Program, the distribution of the whole must be on the terms of 122 | this License, whose permissions for other licensees extend to the 123 | entire whole, and thus to each and every part regardless of who wrote it. 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | -------------------------------------------------------------------------------- /move-blogs-rollback.php: -------------------------------------------------------------------------------- 1 | 48 | 49 | 50 | Multiple Databases Roll-Back Tool 51 | 57 | 58 | 59 | 60 | 61 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | $hex){ 91 | 92 | $current_db_name = $multi_db_prefix . str_pad( $hex, $newdbsize, "0", STR_PAD_LEFT ); 93 | //Get our table list from each multi DB. 94 | $result = mysql_query( 'SHOW TABLES FROM ' . $current_db_name, $dbh_multi ); 95 | if ( !$result ) { 96 | echo "DB Error, could not list tables
Make sure you configure your original table in the dbname variable at the top of the script!
"; 97 | echo 'MySQL Error: ' . mysql_error(); 98 | exit; 99 | } 100 | while ( $row = mysql_fetch_row( $result ) ) { 101 | 102 | $dbh_target = mysql_connect( $dbhost, $dbuname, $dbpass ) or die( "Houston, we have a problem!
Database Error: " . mysql_error() ); 103 | mysql_select_db( $target_dbname, $dbh_target ) or die( "Houston, we have a problem!
Looks like you need to create your target DB '" . $target_dbname . "'.
Database Error: " . mysql_error() ); 104 | 105 | $tableexists = mysql_num_rows( mysql_query( "SHOW TABLES LIKE '{$row[0]}'", $dbh_target ) ); 106 | $tabletest = $tableexists 107 | ? 'table in target db' 108 | : "table not in target db"; 109 | 110 | //CHeck if we are executing the rollback process. 111 | if ( $doing_rollback && !$tableexists ) { 112 | mysql_query( "CREATE TABLE {$row[0]} LIKE {$current_db_name}.{$row[0]}", $dbh_target ); 113 | mysql_query( "INSERT INTO {$row[0]} SELECT * FROM {$current_db_name}.{$row[0]}", $dbh_target ); 114 | } 115 | 116 | $testpass = ' exists'; 117 | echo "
"; 118 | echo ""; 119 | echo ""; 120 | echo ""; 121 | 122 | mysql_close( $db ); 123 | } // end while 124 | } 125 | 126 | ?>
62 |
    63 |
  1. Tested on PHP 5 & MySQL 5
  2. 64 |
  3. Note this will only work if all the new databases are on the same MySQL server, and ONE set of credentials has access to all of them.
  4. 65 |
  5. Make sure that your target DB "" exist (green text next to table name in db column below)
  6. 66 |
  7. In the status section, each table should show not in target db (unless you've already run this script)
  8. 67 |
  9. To start the rollback process click here
  10. 68 |
  11. Be patient, depending on how many blogs you have, this could take a while
  12. 69 |
  13. Once completed, refresh this page by clicking here
  14. 70 |
  15. Check to make sure that in the status section all tables say table in target db
  16. 71 |
  17. Rejoice, I probably just saved you hours of your life!
  18. 72 |
  19. If this didn't work, don't blame me. Sometimes life is just like that..
  20. 73 |
74 |
DB nametable nametarget dbstatus
" . $current_db_name . "{$row[0]}{$target_dbname} {$testpass}{$tabletest}
127 | 128 | -------------------------------------------------------------------------------- /move-blogs.php: -------------------------------------------------------------------------------- 1 | Make sure you configure your original table in the dbname variable at the top of the script!
"; 57 | echo 'MySQL Error: ' . mysql_error(); 58 | exit; 59 | } 60 | 61 | 62 | 63 | //------------------------------------------------------------------------// 64 | //---Table----------------------------------------------------------------// 65 | //------------------------------------------------------------------------// 66 | 67 | ?> 68 | 69 | 70 | Multiple Databases Conversion Tool 71 | 77 | 78 | 79 | 80 | 81 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | Database Error: " . mysql_error() ); 116 | mysql_select_db( $this_blog_new_db, $db ) or die( "Houston, we have a problem!
Looks like you need to create your new db's! If you're lucky, this link still works - click me
Database Error: " . mysql_error() ); 117 | 118 | $tableexists = mysql_num_rows( mysql_query( "SHOW TABLES LIKE '{$row[0]}'" ) ); 119 | $tabletest = $tableexists 120 | ? 'table in new db' 121 | : "table not in new db"; 122 | 123 | //Next we check to see if we are actually moving anything yet 124 | if ( !empty( $tabletomove ) && !$tableexists ) { 125 | mysql_query( "CREATE TABLE {$row[0]} LIKE {$dbname}.{$row[0]}" ); 126 | mysql_query( "INSERT INTO {$row[0]} SELECT * FROM {$dbname}.{$row[0]}" ); 127 | } 128 | 129 | $testpass = ' exists'; 130 | echo ""; 133 | 134 | mysql_close( $db ); 135 | } // end while 136 | 137 | ?>
82 |
    83 |
  1. Tested on PHP 5 & MySQL 5
  2. 84 |
  3. Note this will only work if all the new databases are on the same MySQL server, and ONE set of credentials has access to all of them.
  4. 85 |
  5. Make sure all of your new db's exist (green text next to table name in db column below)
  6. 86 |
  7. In the status section, each table should show not in new db (unless you've already run this script)
  8. 87 |
  9. To start the copy process click here
  10. 88 |
  11. Be patient, depending on how many blogs you have, this could take a while
  12. 89 |
  13. Once completed, refresh this page by clicking here
  14. 90 |
  15. Check to make sure that in the status section all tables say table in new db
  16. 91 |
  17. Rejoice, I probably just saved you hours of your life!
  18. 92 |
  19. If this didn't work, don't blame me. Sometimes life is just like that..
  20. 93 |
94 |
table nametable infonew dbstatus
{$row[0]}"; 131 | echo is_numeric( $blogid ) ? 'blog ' . $blogid : 'global'; 132 | echo "{$this_blog_new_db} {$testpass}{$tabletest}
138 | 139 | --------------------------------------------------------------------------------