Skip to content

Instantly share code, notes, and snippets.

@emohamed
Created January 15, 2013 14:23
Show Gist options
  • Select an option

  • Save emohamed/4539002 to your computer and use it in GitHub Desktop.

Select an option

Save emohamed/4539002 to your computer and use it in GitHub Desktop.
<?php
if ($_SERVER['REQUEST_METHOD']=='POST') {
21try {
$enable_gzip = isset($_POST['gzip']);
$migrator = new WpMigrator($_POST['new-home'], $_POST['new-prefix']);
if (is_uploaded_file($_FILES['dump']['tmp_name'])) {
$file_ext = preg_replace('~.*\.~', '', $_FILES['dump']['name']);
$file_ext = strtolower($file_ext);
$file_location = $_FILES['dump']['tmp_name'];
$original_name = $_FILES['dump']['name'];
} else if (is_valid_url($_POST['dump-url'])) {
$remote = $_POST['dump-url'];
$file_ext = preg_replace('~.*\.~', $remote);
$file_location = $migrator->get_tmp_file();
copy($remote, $file_location);
$original_name = basename($file_location);
} else {
$error = "Please specify either file or URL";
}
$result_filename = preg_replace('~.gz$~', '', $_FILES['dump']['name']);
if ($enable_gzip) {
$result_filename .= '.gz';
}
if (!isset($error)) {
if ($file_ext=='gz') {
$extracted = $migrator->get_tmp_file();
$migrator->_exec("gunzip -c $file_location > $extracted");
$file_location = $extracted;
}
$res = $migrator->migrate_file($file_location, $enable_gzip);
header('Content-Disposition: attachment; filename="' . $result_filename . '"');
readfile($res);
exit;
}
} catch (Exception $e) {
$error = $e->getMessage();
}
}
class WpMigrator {
var $to_be_cleaned = array(),
$seds = array();
function __construct($new_home, $new_prefix) {
# make sure that the URL is properly formatted
if (!is_valid_url($new_home)) {
throw new Exception("Home URL $url_pattern doesn't look correct. ");
}
$this->new_home = $new_home;
$this->new_prefix = $new_prefix;
}
# delete temp files ...
function __destruct () {
foreach ($this->to_be_cleaned as $filename) {
unlink($filename);
}
}
function get_tmp_file() {
$tmp_file_counter = 0;
$file = "/tmp/migration-tmp-file-$tmp_file_counter";
while (file_exists($file)) {
$tmp_file_counter++;
$file = "/tmp/migration-tmp-file-$tmp_file_counter";
}
$this->to_be_cleaned[] = $file;
return $file;
}
# wrapper for shell commands executing
function _exec($cmd) {
return trim(shell_exec($cmd));
}
function migrate_file($src_file, $enable_gzip) {
$this->src_file = $src_file;
$this->replace_tables();
$this->replace_urls();
$this->replace_misc();
$this->fix_serailized_arrays();
$tmp = $this->get_tmp_file();
$cmd = "cat " . escapeshellarg($this->src_file) . " | " .
implode(' | ', $this->seds) .
($enable_gzip ? ' | gzip ' : '') . " > " .
$tmp;
$this->_exec($cmd);
return $tmp;
}
function fix_serailized_arrays() {
$this->seds[] = "php fix-php-serialized-array.php";
}
function replace_tables () {
$tables_declarations = $this->_exec("grep \"^CREATE TABLE\" $this->src_file");
preg_match_all('~`(.*?)`~', $tables_declarations, $tables);
$tables = $tables[1];
$posts_tables = array_values(preg_grep('~posts$~', $tables));
if (count($posts_tables) > 1) {
# mutlistie -- take the table with shortest name
$shortest = '';
foreach ($posts_tables as $posts_table_name) {
if (strlen($shortest)==0) { $shortest = $posts_table_name; continue; }
if (strlen($posts_table_name) < strlen($shortest)) {
$shortest = $posts_table_name;
}
}
$posts_table = $shortest;
} else {
$posts_table = $posts_tables[0];
}
$this->old_prefix = $old_prefix = preg_replace('~posts$~', '', $posts_table);
foreach ($tables as $old_table) {
$new_table = preg_replace('~^' . $old_prefix . '~', $this->new_prefix, $old_table);
$this->seds[] = "sed s/$old_table/$new_table/g";
}
}
function replace_urls() {
$home_declaration = $this->_exec("grep \"'home'\" $this->src_file | head -n 1 | sed 's/),(/),\\n(/g' | grep \"home\" | head -n 1");
preg_match('~\'(http.*?)\'~', $home_declaration, $home);
$old_home = $home[1];
$new_home = $this->new_home;
if (has_trailing_slash($old_home) && !has_trailing_slash($new_home)) {
$new_home = add_trailing_slash($new_home);
} else if (!has_trailing_slash($old_home) && has_trailing_slash($new_home)) {
$new_home = remove_trailing_slash($new_home);
}
$this->seds[] = "sed 's/" . escape_for_sed($old_home) . "/" . escape_for_sed($new_home) . "/g'";
}
function replace_misc() {
$misc = array(
'user_roles',
'capabilities',
'user_level',
'user-settings',
);
foreach ($misc as $replace) {
$this->seds[] = "sed s/" . escape_for_sed("$this->old_prefix$replace") . "/" . escape_for_sed("$this->new_prefix$replace") . "/g";
}
}
}
function is_valid_url($url) {
return preg_match('~^https?://.+~i', $url);
}
function escape_for_sed($string) {
return str_replace('/', '\/', $string);
}
function has_trailing_slash($string) {
return preg_match('~/$~', $string);
}
function remove_trailing_slash($string) {
return preg_replace('~/$~', '', $string);;
}
function add_trailing_slash($string) {
return $string . "/";
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>WordPress Migration Tool</title>
<style type="text/css" media="screen">
* { padding:0; margin:0; }
body {
font-family: Georgia, sans-serif;
font-size: 13px;
line-height: 1.4;
background: #f5f5f5;
padding: 20px;
}
code {
display:block;
background:lightyellow;
border:solid 1px #ddd;
margin:10px 0;
padding:5px;
font-weight:bold;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
}
h2 { font-size: 19px; }
h2 span { cursor: pointer; font-size: 14px;}
.hidden { display: none; }
.red { color:red; }
strong.red { font-size:1.5em }
.info { padding:10px 30px; font-size:1em; }
h3 { font-size:1.3em; }
ol { padding:20px 40px }
ol ul li { margin-left: 35px; }
li { padding-bottom:20px; border-bottom:solid 1px #eee; margin-bottom:20px; }
li li { padding-bottom:10px; margin-bottom:0; border:0; }
p { font-size:1em; padding:10px 0; }
small { font-size:0.9em; font-weight:normal; }
#wrapper { width:1000px; margin:0 auto; padding:10px; background:#fff; border:solid 10px #fff; -moz-border-radius: 20px; -webkit-border-radius: 20px; }
.admin-path { background: #eee; padding: 2px 5px; }
h1 { color:darkred; border-bottom:solid 1px #eee; padding-bottom:15px; }
.checkbox { width:18px; height:18px; vertical-align:top; position:relative; top:5px; margin-right:10px; }
form { padding: 20px; }
.row label, .row input { float: left; margin-bottom: 10px }
.row label { width: 120px; }
label.second { border-left: solid 3px #ddd; padding-left: 10px; margin-left: 10px }
.error { width: 300px; background: #eee; text-align: center; margin: 30px auto 0; border: solid 1px red; color: red; padding: 10px; }
label.inline-label { margin-left: 5px; }
input[type=checkbox] { vertical-align:top; position:relative; top:3px;}
.cl { clear: both; height: 0px; font-size: 0px; line-height: 0px; }
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="wrapper">
<h1>WordPress Migration Tool</h1>
<?php if (!empty($error)) : ?>
<p class="error"><?php echo $error ?></p>
<?php endif ?>
<form method="POST" enctype="multipart/form-data">
<div class="row">
<label>File: </label>
<input type="file" name="dump" />
<label class="second">Or URL: </label>
<input type="text" name="dump-url" />
<div class="cl">&nbsp;</div>
</div>
<div class="row">
<label>New Home URL: </label>
<input type="text" name="new-home" value="http://" />
<div class="cl">&nbsp;</div>
</div>
<div class="row">
<label>New Prefix: </label>
<input type="text" name="new-prefix" value="wp_" />
<div class="cl">&nbsp;</div>
</div>
<div class="row">
<label>&nbsp;</label>
<input type="checkbox" name="gzip" id="gzip" />
<label for="gzip" class="inline-label">gzip result?</label>
<div class="cl">&nbsp;</div>
</div>
<div class="row">
<label>&nbsp;</label>
<input type="submit" value="Go" />
</div>
</form>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment