Source for file import-mt.php
Documentation is available at import-mt.php
* This file implements importing of Movable Type entries into b2evolution.
* - Wrap this by an abstract import class!
* - list of all posts, editable (overkill?)
* - assign comment_author_ID to comments if user exist?! }}}
* This script was developed and tested with b2evolution 0.9.0.4 (on Sourceforge CVS)
* and Movable Type 2.64 and 2.661.
* It should work quite alright with b2evo 0.9 and later though.
* This file is part of the b2evolution/evocms project - {@link http://b2evolution.net/}.
* See also {@link http://sourceforge.net/projects/evocms/}.
* @copyright (c)2003-2005 by Francois PLANQUE - {@link http://fplanque.net/}.
* Parts of this file are copyright (c)2004-2005 by Daniel HAHLER - {@link http://thequod.de/contact}.
* Credits go to the WordPress team (@link http://wordpress.org), where I got the basic
* import-mt.php script with most of the core functions. Thank you!
* @license http://b2evolution.net/about/license.html GNU General Public License (GPL)
* b2evolution is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* b2evolution is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with b2evolution; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* In addition, as a special exception, the copyright holders give permission to link
* the code of this program with the PHP/SWF Charts library by maani.us (or with
* modified versions of this library that use the same license as PHP/SWF Charts library
* by maani.us), and distribute linked combinations including the two. You must obey the
* GNU General Public License in all respects for all of the code used other than the
* PHP/SWF Charts library by maani.us. If you modify this file, you may extend this
* exception to your version of the file, but you are not obligated to do so. If you do
* not wish to do so, delete this exception statement from your version.
* Daniel HAHLER grants François PLANQUE the right to license
* Daniel HAHLER's contributions to this file and the b2evolution project
* under any OSI approved OSS license (http://www.opensource.org/licenses/).
* {@internal Below is a list of authors who have contributed to design/coding of this file: }}
* @author fplanque: François PLANQUE
* @author blueyed: Daniel HAHLER
* @version $Id: import-mt.php,v 1.1.2.25 2005/10/03 23:33:02 blueyed Exp $
* Enter the relative path of the import.txt file containing the MT entries.
* If the file is called import.txt and it is in /admin, then this line should be:
* define('MTEXPORT', 'import.txt');
* You only need this to force a specific file instead of using a dropdown list
* Set to true to get a lot of var_dumps, wrapped in pre tags
// ----------- don't change below if you don't know what you do ------------------------
<!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">
<title>b2evolution › Import from Movable Type</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<link href="variation.css" rel="stylesheet" type="text/css" title="Variation" />
<link href="desert.css" rel="alternate stylesheet" type="text/css" title="Desert" />
<link href="legacy.css" rel="alternate stylesheet" type="text/css" title="Legacy" />
$head .=
'<link href="custom.css" rel="alternate stylesheet" type="text/css" title="Custom" />';
<script type="text/javascript" src="styleswitcher.js"></script>
<a href="http://b2evolution.net"><img id="evologo" src="../img/b2evolution_minilogo2.png" alt="b2evolution" title="visit b2evolution's website" width="185" height="40" /></a>
<br /><span style="font-size:150%; font-weight:bold">Import Movable Type into b2evolution</span>
dieerror( "There doesn't seem to be a conf/_config.php file. You must install b2evolution before you can import any entries.", $head );
require
( '../conf/_config.php' );
if( (!isset
($config_is_done) ||
!$config_is_done) )
require
( dirname(__FILE__
).
"/
$admin_dirout/
$core_subdir/_conf_error_page.php
" );
dieerror( 'b2evolution configuration is not done yet.', $head );
$use_obhandler =
0; // no output buffering!
require
( '../b2evocore/_main.php' );
// Check if user is logged in and is in group #1 (admins)
$error =
'You must login with an administrator (group #1) account.';
require
( dirname(__FILE__
) .
"/
$admin_dirout/
$htsrv_subdir/login.php
" );
param( 'exportedfile', 'string', '' );
param( 'mode', 'string', 'normal' );
foreach( array( 'easy', 'normal', 'expert' ) as $tab )
echo
( $tab ==
$mode ) ?
'<li class="current">' :
'<li>';
echo
'<a href="import-mt.php?mode='.
$tab.
( !empty($exportedfile) ?
'&exportedfile='.
$exportedfile :
'' ).
'">'.
ucwords($tab).
'</a></li>';
<div style="padding-top:1em;clear:both;">
// check existence of export-file
if( empty($exportedfile) )
The MT export file you defined in MTEXPORT at top of the script does not seem to exist.
Please check the path you've given for MTEXPORT or choose a file below.
if( empty($exportedfile) )
{ // no valid MTEXPORT defined
die( '</div></div></body></html>' );
dieerror("The MT export file [$exportedfile] you've chosen does not seem to exist. Please check path/permission.");
param( 'simulate', 'integer', 0 );
param( 'default_password', 'string', 'changeme' );
param( 'default_password2', 'string', 'changeme' );
param( 'post_locale', 'string', $Settings->get( 'default_locale' ) );
if( $default_password !=
$default_password2 )
dieerror( 'The two passwords for new users are not identical.' );
param( 'default_userlevel', 'integer', 1 );
if( $default_userlevel >
10 ) $default_userlevel =
10;
param( 'default_usergroup', 'integer', $Settings->get('newusers_grp_ID') );
param( 'default_convert_breaks', 'integer', 1 );
param( 'convert_html_tags', 'integer', 0 );
param( 'action', 'string', '' );
$categories_countprim =
array(); // counts posts in primary categories
param( 'mode', 'string', 'normal', true );
<p>We are about to import
<?php
echo
'['.
$exportedfile.
'].';
?> [<a href="import-mt.php?mode=
<?php echo
$mode ?>">choose another export-file</a>]
<?php
<p>This file contains
<?php echo
count( $posts ) ?> post(s) from
<?php echo
count( $authors ) ?> author(s) in
<?php echo
count( $categories ) ?> category(ies).</p>
<p>We'll import into b2evolution's database "
<?php echo
DB_NAME ?>".</p>
<p>Before importing, you should check the URLs of any <img> tags you may have in
<?php echo
$exportedfile ?>. Will these URLs still be valid after the migration? If not, we advise you do a search and replace on
<?php echo
$exportedfile ?> before continuing.</p>
<p>Preferred location for inline images is [
<?php echo
$fileupload_realpath ?>]<br />
If you decide to use this location, your IMG SRC urls should point to [
<?php echo
$fileupload_url ?>]</p>
<p>You can also handle the images later, but it might be easier now :)</p>
<p>The importer is smart enough not to import duplicates, so you can run this procedure multiple times without worrying if — for whatever reason — it doesn't finish (script timeout for example).</p>
<form class="fform" action="import-mt.php" method="post">
<input type="hidden" name="action" value="import" />
if( !empty($exportedfile) )
?><input type="hidden" name="exportedfile" value="
<?php echo
format_to_output( $exportedfile, 'formvalue' ) ?>" />
<li>MT users with no matching b2evolution user login will be automatically created.</li>
<li>MT categories with no matching b2evolution category name will be automatically created (in the default blog selected below.)</li>
if( isset
($categories_countprim['[no category assigned]']) )
<li>Entries without categories (
<?php echo
$categories_countprim['[no category assigned]'] ?>) will be imported to category '[no category assigned]' in the default blog.</li>
<li>MT users can be mapped to existing b2evo users, mapped to new users (provide login) or ignored.</li>
<li>Categories can be mapped to existing b2evo categories, mapped to new categories (provide location + name) or ignored.</li>
<p>This gives you as much power as we can provide. It's like normal mode, but lets you map categories to a whole set of b2evo categories (one main category and as many extra categories as you like). You can run the importer multiple times to use different sets of b2evo categories for different sets of MT categories.</p>
<?php if( $mode !=
'expert' ) { ?>
<legend>Default blog</legend>
<div class="label">
<?php echo
( $mode ==
'easy' ) ?
'Create categories in blog' :
'Use as default blog for categories' ?>:</div>
<select name="default_blog">
$BlogCache->option_list( 2 ); // use first non-all blog as default
<?php if( $mode !=
'easy' ) { ?>
<fieldset><legend>Author mapping</legend>
$evousers =
$DB->get_results("SELECT * FROM $tableusers ORDER BY ID");
foreach ($authors as $author)
<div class="label"><label>
<?php echo
$author ?></label></div>
<select name="user_select[]">
<option value="#CREATENEW#" selected="selected"> Create new: </option>
<option value="#IGNORE#"> Ignore! </option>
foreach( $evousers as $user )
?><option value="
<?php echo
$user->ID ?>"
<?php if( strtolower($author) ==
strtolower( $user->user_login ) ) echo
' selected="selected"';
<input type="text" value="
<?php echo
format_to_output($author, 'formvalue') ?>" name="user_name[]" maxlength="30" class="input" />
<span class="notes">(login for new user)</span>
<fieldset><legend>New user defaults</legend>
form_text( 'default_password', $default_password, 20, 'Password for new users', 'this will be the password for users created during migration (default is "changeme")', 30 , '', 'password' );
form_text( 'default_password2', $default_password, 20, 'Confirm password', 'please confirm the password', 30 , '', 'password' );
form_select_object( 'default_usergroup', $Settings->get('newusers_grp_ID'), $GroupCache, T_('User group') );
$field_note =
'[0 - 10] '.
sprintf( T_('See <a %s>online manual</a> for details.'), 'href="http://b2evolution.net/man/user_levels.html"' );
form_text( 'default_userlevel', $Settings->get('newusers_level'), 2, T_('Level'), $field_note, 2 );
<?php if( $mode !=
'easy' ){ ?>
<fieldset><legend>Category mapping</legend>
foreach( $categories as $cat )
<br /><span class="notes" style="font-weight:normal">used
<?php echo
@(int)
$categories_countprim[$cat] ?> times as primary category</span>
<div class="input"><select name="catmap_select[]">
echo
'<option value="#DEFAULTSET#">Map to default categories set (see below)</option>';
else echo
'<option value="#DEFAULTBLOG#">Create in default blog:</option>'; ?>
<option value="#IGNORE#">Ignore entries with this primary cat</option>
<input type="text" name="catmap_name[]" value="
<?php echo
format_to_output( $cat, 'formvalue' ) ?>" size="30" />
<fieldset><legend>Post/Entry defaults</legend>
form_checkbox( 'default_convert_breaks', $default_convert_breaks, 'Convert-Breaks default', 'will be used for posts with empty CONVERT BREAKS or "__default__"' );
form_select( 'post_locale', $Settings->get('default_locale'), 'locale_options', T_('Default locale'), 'Locale for posts.' );
form_checkbox( 'convert_html_tags', $convert_html_tags, 'Convert ugly HTML', 'this will lowercase all html tags and add a XHTML compliant closing tag to <br>, <img>, <hr> (you\'ll get notes)' );
{ // we'll use 'default' when importing
<div class="label">Renderers:</div>
<?php /*<fieldset style="padding-left:1ex"><legend><img>-URL mapping</legend>
<a name="imgurls"><p class="notes">This lets you map found image urls (their basename) to another basename.
You probably want to put the images that you had on your MT installation into b2evo's media (fileupload) folder.<br />
So you would use <strong><?php echo $fileupload_url ?></strong> for replacement.<br />
You can leave this empty, of course and nothing will be replaced, but then you'll have probably broken images.</p></a>
preg_match_all( '#<img .*?src="([^"]*)/.*?"#is', $importdata, $matches );
foreach( $matches[1] as $imgurl )
if( !isset($imgurlscount[ $imgurl ]) )
$imgurlscount[ $imgurl ] = 1;
else $imgurlscount[ $imgurl ]++;
$imgurlscount = array_reverse( $imgurlscount );
param( 'singleimgurls', 'integer', 0 );
foreach( $imgurlscount as $imgurl => $counter ) if( $counter > 1 || $singleimgurls )
?><input type="hidden" name="url_search[<?php echo $i ?>]" value="<?php echo format_to_output( $imgurl, 'formvalue' ) ?>" />
<strong><?php echo $imgurl ?></strong>:<br />
<div class="input"><input style="clear:left" type="text" name="url_replace[]" size="50" /></div>
<span class="notes" style="font-weight:normal"> (used <?php echo $counter ?> times)</span>
echo '<p class="center"><a name="imgurls" href="import-mt.php?tab=import&singleimgurls='.( $singleimgurls ? '0' : '1' );
if( !empty($exportedfile) ) echo '&exportedfile='.$exportedfile;
echo '">'.( $singleimgurls ? 'hide img urls only used once' : 'show also img urls only used once').'</a></p>';
<fieldset><legend>other settings</legend>
form_checkbox( 'simulate', $simulate, 'Simulate: do not import really', 'Use this to test importing, without really changing the target database.' );
<li>b2evolution does not support excerpts yet.
So, we will import them in front of the body with "
<?php echo
htmlspecialchars('<!--more-->< !--noteaser-->') ?>" tags,
but only if there is no extended body for the post. In that case we'll use the extended body appended with the <!--more--> tag to the body - excerpts are lost then (but you'll get a note about it).
<fieldset class="submit">
<input type="hidden" name="mode" value="
<?php echo
$mode ?>" />
<input class="search" type="submit" value=" Import! " />
<input class="search" type="reset" value="Reset form" />
elseif( $action ==
'import' )
<h4>Importing from [
<?php echo
$exportedfile ?>]..
<?php if( $simulate ) echo
' (simulating)' ?></h4>
set_time_limit( 900 ); // 15 minutes ought to be enough for everybody *g
@ini_set( 'max_execution_time', '900' );
$count_commentscreated =
0;
$count_trackbackscreated =
0;
param( 'mode', 'string', true );
param( 'default_blog', 'integer', true );
* associative array that maps MT cats to b2evo.
* key is the MT category name.
* - 'blogid': blog_id, new name
if( !isset
($_POST['catmap_select']) )
foreach( $categories as $cat )
$catsmapped[ $cat ] =
array('blogid', $default_blog, $cat );
else foreach( $_POST['catmap_select'] as $cat )
$catsmapped[ $categories[$i_cat] ] =
array( 'ignore' );
elseif( $cat ==
'#DEFAULTSET#' )
if( !isset
( $default_post_category ) )
{ // get the default category set
if( isset
($_POST['post_category']) )
$default_post_category = (int)
$_POST['post_category'];
dieerror( 'You have chosen to map at least one category to the default category set, but you have not selected a main category for this set!<br />Please go back and correct that..' );
$default_post_extracats =
array();
if( isset
( $_POST['post_extracats'] ) )
foreach( $_POST['post_extracats'] as $tcat )
$default_post_extracats[] = (int)
$tcat;
$catsmapped[ $categories[$i_cat] ] =
array( 'defaultset' );
{ // we map to a b2evo cat
$catsmapped[ $categories[$i_cat] ] =
array('catid', (int)
$cat);
elseif( $cat ==
'#DEFAULTBLOG#'
{ // we want a new category
$blog_id =
($cat ==
'#DEFAULTBLOG#') ?
$default_blog :
$match[1];
// remember the name to create it when posts get inserted
$catsmapped[ $categories[$i_cat] ] =
array( 'blogid', $blog_id, remove_magic_quotes( $_POST['catmap_name'][$i_cat]) );
dieerror('This should never happen @catmapping. Please report it! (cat='.
$cat.
' / ');
foreach( $catsmapped as $mtcat =>
$values ) if( $values[0] ==
'blogid' )
echo
'Category <span style="color:#09c">'.
$values[2].
'</span> (for blog #'.
$values[1].
') ';
// check if it already exists
$cat_ID =
$DB->get_var("SELECT cat_ID FROM $tablecategories
WHERE cat_blog_ID = {$values[1]}
AND cat_name = ".
$DB->quote( $values[2] ));
echo
'will be created with first post.<br />';
echo
'already exists.<br />';
$catsmapped[ $mtcat ] =
array('catid', (int)
$cat_ID); // map to existing category
$default_renderers =
array();
if( !isset
($_POST['renderers']) )
$default_renderers =
array();
else $default_renderers =
$_POST['renderers'];
// the special Auto-P renderer
param( 'autop', 'string', true );
$default_renderers[] =
'b2WPAutP';
$default_renderers =
$Renderer->validate_list( array('default') );
foreach( $_POST['url_replace'] as $replace )
$urlsearch[] = remove_magic_quotes($_POST['url_search'][$i]);
$urlreplace[] = remove_magic_quotes( $replace );
if( !isset
($_POST['user_select']) )
foreach( $authors as $author )
$usersmapped[ $author ] =
array('createnew', $author );
else foreach( $_POST['user_select'] as $select )
$mtauthor =
$authors[ $i_user ];
if( $select ==
'#IGNORE#' )
$usersmapped[ $mtauthor ] =
array( 'ignore' );
elseif( $select ==
'#CREATENEW#' )
$usersmapped[ $mtauthor ] =
array( 'createnew', remove_magic_quotes( $_POST['user_name'][$i_user] ) );
$usersmapped[ $mtauthor ] =
array( 'b2evo', $select );
?><p class="error">Unknown user mapping. This should never ever happen. Please report it.</p>
<?php
$simulate_cat_id =
$DB->get_var( 'SELECT MAX( cat_ID )+1 FROM T_categories' );
foreach ($posts as $post)
$post_renderers =
$default_renderers;
$post_status =
'published';
// strip the post's last '-----'
// first line is author of post
$message =
"\n<li>Post from ".
format_to_output( $post_author, 'entityencoded' ).
' <ul>';
// Take the pings out first
preg_match("|(-----\n\nPING:.*)|s", $post, $pings);
// Then take the comments out
preg_match("|(-----\nCOMMENT:.*)|s", $post, $comments);
// We ignore the keywords
// We want the excerpt - it's put with more and noteaser tag into main body, only if we have no extended body!
preg_match("|-----\nEXCERPT:(.*)|s", $post, $excerpt);
$excerpt =
trim($excerpt[1]);
// We're going to put extended body into main body with a more tag
preg_match("|-----\nEXTENDED BODY:(.*)|s", $post, $extended);
$extended =
trim($extended[1]);
$post =
preg_replace("|(-----\nEXTENDED BODY:.*)|s", '', $post);
{ // no extended body, so we can use the excerpt
else $post_content =
$excerpt.
"\n<!--more--><!--noteaser-->\n".
$body;
{ // we'll use body and extended body
$message .=
'<li><span style="color:red">Excerpt discarded because of existing extended body:</span>
$post_content =
$body.
"\n<!--more-->\n".
$extended;
// Grab the metadata from what's left
$post_categories =
array();
foreach ($metadata as $line) if( !empty($line) )
$message .=
"<li class=\"notes\">Unknown meta-data: [$line] (ignoring)</li>";
$key =
trim( $token[1] );
$value =
trim( $token[2] );
// Now we decide what it is and what to do with it
$message .=
'<li>title: '.
strip_tags($value).
'</li>';
$post_status =
'published';
$message .=
'<li>Unknown post status ['.
$value.
'], using "draft".</li>';
$post_allow_comments =
$value;
switch( $post_allow_comments ) {
case 0:
$comment_status =
'disabled'; break;
case 1:
$comment_status =
'open'; break;
case 2:
$comment_status =
'closed'; break;
$message .=
'<li>Unknown comment status ['.
$value.
'], using "closed".</li>';
$comment_status =
'closed';
if( $value ==
'__default__' ||
empty($value) )
$post_convert_breaks =
$default_convert_breaks;
elseif( $value ==
'textile_2' &&
array_search( 'b2DATxtl', $post_renderers ) ===
false )
{ // add the textile 2 renderer to the post's renderers
$post_renderers[] =
'b2DATxtl';
$post_convert_breaks =
1; // TODO: check if this makes sense!
$post_convert_breaks = (int)
( $value >
0 );
$message .=
'<li>Unknown CONVERT BREAKS value, using default ('.
$default_convert_breaks.
')..</li>';
$post_convert_breaks =
$default_convert_breaks;
if( $autop ==
'depends' &&
$post_convert_breaks &&
array_search( 'b2WPAutP', $post_renderers ) ===
false )
{ // add the Auto-P renderer
$post_renderers[] =
'b2WPAutP';
$post_allow_pings =
'open';
$post_allow_pings =
'closed';
if( !empty($value) &&
!isset
($post_categories[$value]) )
if( $catsmapped[ $value ][0] ==
'defaultset' )
$post_categories[$value] =
$default_post_extracats;
array_unshift( $post_categories[$value], 'catid', $default_post_category );
else $post_categories[$value] =
$catsmapped[ $value ];
$post_date =
date('Y-m-d H:i:s', $post_date);
$message .=
"\n<li>Unknown key [$key] in metadata:\nvalue: $value\n</li>";
} // End foreach (metadata)
if( empty($post_categories) )
{ // no category metadata found!
if( $catsmapped[ '[no category assigned]' ][0] ==
'defaultset' )
{ // we must convert default set
$post_categories['[no category assigned]'] =
$default_post_extracats;
array_unshift( $post_categories['[no category assigned]'], 'catid', $default_post_category );
else $post_categories[ '[no category assigned]' ] =
$catsmapped[ '[no category assigned]' ];
// Let's check to see if it's in already
if( $post_ID =
$DB->get_var("SELECT ID FROM $tableposts WHERE post_title = ".
$DB->quote($post_title).
" AND post_issue_date = '$post_date'")) {
$message .=
'<li style="color:blue">Post already imported.</li>';
switch( $usersmapped[ $post_author ][0] )
$message .=
'<li style="color:blue">User ignored!</li>';
$post_author =
$usersmapped[ $post_author ][1];
// check if the user already exists
$post_author =
$user_data['ID'];
$new_user->set('login', strtolower($usersmapped[ $post_author ][1]));
$new_user->set('nickname', $usersmapped[ $post_author ][1]);
$new_user->set('pass', md5( $default_password ));
$new_user->set('level', $default_userlevel);
$new_user_Group =
$GroupCache->get_by_ID( $default_usergroup );
$new_user->setGroup( $new_user_Group );
$new_user->set_datecreated( time() +
($Settings->get('time_difference') *
3600) );
$cache_userdata[ $post_author ] =
array( 'ID' =>
'simulating' );
$message .=
'<li style="color:orange">user '.
$usersmapped[ $post_author ][1].
' created</li>';
$post_author =
$new_user->ID;
$message .=
'<li style="color:red">unknown type in checkauthor ('.
$usersmapped[ $author ][0].
'). This should never ever happen. Post ignored. Please report it.</li>';
foreach( $post_categories as $catname =>
$checkcat )
case 'catid':
// existing b2evo catids
$post_catids[] =
$cat_id; // get all catids
case 'ignore':
// category is ignored
{ // main category ignored, don't import post
$message_ignored .=
'<li>Main Category "'.
$catname.
'" ignored! - no import</li>';
{ // ignored category in extracats, remove it there
$message_ignored .=
'<li>Extra category '.
$catname.
' ignored.</li>';
unset
( $post_categories[ $catname ] );
case 'blogid':
// category has to be created
// create it and remember ID
$cat_id = ++
$simulate_cat_id;
$cat_id =
cat_create( $checkcat[2], 'NULL', $checkcat[1] );
$catsmapped[ $catname ] =
array( 'catid', $cat_id ); // use ID from now on.
if( !isset
($cache_categories[ $cat_id ] ) )
{ // stupid workaround because of a bug where cache_categories does not get updated and we want to use get_catname later
$cache_categories[ $cat_id ] =
array(
'cat_name' =>
$checkcat[2],
'cat_blog_ID' =>
$checkcat[1],
$post_catids[] =
$cat_id;
$message .=
'<li style="color:orange">category '.
$checkcat[2].
' [ID '.
$cat_id.
'] created</li>';
$message .=
'<li style="color:red">This should never ever happen @check_cats. Please report it! (checkcat[0]: '.
$checkcat[0].
')</li>';
if( !empty($message_ignored) )
$message .=
'<li style="color:blue">Categories ignored: <ul>'.
$message_ignored.
'</ul></li>';
$old_content =
$post_content;
// convert tags to lowercase
$post_content =
preg_replace( "/(<\/?)(\w+)([^>]*>)/e", "'\\1'.strtolower('\\2').'\\3'", $post_content);
// close br, hr and img tags
// add quotes for href tags that don't have them
$post_content =
preg_replace( '|href=([^"\'][^\s>"\']+)["\']?|', 'href="$1"', $post_content );
if( $post_content !=
$old_content )
$message .=
'<li><p style="color:darkblue;border:1px dashed orange;">'.
htmlspecialchars($old_content).
'</p>
html-converted to: <p style="color:darkblue;border:1px dashed orange;">'.
htmlspecialchars($post_content).
'</p></li>';
/*if( count($urlreplace) )
$old_content = $post_content;
foreach( $urlreplace as $search => $replace )
$post_content = str_replace( $urlsearch, $urlreplace, $post_content );
if( $post_content != $old_content )
echo '<p style="color:darkblue;border:1px dashed orange;">'.htmlspecialchars($old_content).'</p>
converted img-links to: <p style="color:darkblue;border:1px dashed orange;">'.htmlspecialchars($post_content).'</p>';
debug_dump( $post_categories, 'post_categories' );
bpost_create( $post_author, $post_title, $post_content, $post_date, $post_category, $post_catids,
$post_status, $post_locale, '' /* $post_trackbacks */, $post_convert_breaks, true /* $pingsdone */,
'' /* $post_urltitle */, '' /* $post_url */, $comment_status, $post_renderers );
$message .=
'<li><span style="color:green">Imported successfully</span><ul><li>main category: <span style="color:#09c">'.
get_catname( $post_category ).
'</span></li>';
if( count($post_catids) )
$message .=
'<li>extra categories: <span style="color:#09c">'.
preg_replace( '/(\d+)/e', "get_catname('\\1')", implode( ', ', $post_catids ) ).
'</span></li>';
$message .=
'</ul></li>';
$comments =
explode("-----\nCOMMENT:", $comments[0]);
foreach ($comments as $comment)
$comment =
trim($comment);
if( empty($comment) ) continue;
$comment_author =
ripline( 'AUTHOR:', $comment );
$comment_email =
ripline( 'EMAIL:', $comment );
$comment_ip =
ripline( 'IP:', $comment );
$comment_url =
ripline( 'URL:', $comment );
$comment_content =
preg_replace("/\n*-----$/", '', $comment);
// Check if it's already in there
if( !$DB->get_row("SELECT * FROM $tablecomments WHERE comment_date = '$comment_date' AND comment_content = ".
$DB->quote( $comment_content )) )
$DB->query( "INSERT INTO $tablecomments( comment_post_ID, comment_type, comment_author_ID, comment_author,
comment_author_email, comment_author_url, comment_author_IP,
comment_date, comment_content)
VALUES( $post_ID, 'comment', 'NULL', ".
$DB->quote($comment_author).
",
".
$DB->quote($comment_email).
", ".
$DB->quote($comment_url).
",
".
$DB->quote($comment_ip).
", '$comment_date', ".
$DB->quote($comment_content).
" )" );
$message .=
'<li>Comment from '.
$comment_author.
' added.</li>';
$count_commentscreated++
;
echo
'<ul>'.
$message.
'</ul>';
// fix the double newline on the first one
$pings[0] =
str_replace("-----\n\n", "-----\n", $pings[0]);
$pings =
explode("-----\nPING:", $pings[0]);
foreach( $pings as $ping )
if( empty($ping) ) continue;
$comment_author =
ripline( 'BLOG NAME:', $ping );
$comment_ip =
ripline( 'IP:', $ping );
$comment_url =
ripline( 'URL:', $ping );
$ping_title =
ripline( 'TITLE:', $ping );
$comment_content =
"<strong>$ping_title</strong><br />$comment_content";
// Check if it's already there
if (!$DB->get_row("SELECT * FROM $tablecomments WHERE comment_date = '$comment_date' AND comment_type = 'trackback' AND comment_content = ".
$DB->quote($comment_content)))
$DB->query( "INSERT INTO $tablecomments
(comment_post_ID, comment_type, comment_author, comment_author_email, comment_author_url,
comment_author_IP, comment_date, comment_content )
($post_ID, 'trackback', ".
$DB->quote($comment_author).
", ".
$DB->quote($comment_email).
", ".
$DB->quote($comment_url).
",
".
$DB->quote($comment_ip).
", ".
$DB->quote($comment_date).
", ".
$DB->quote($comment_content).
" )" );
$message .=
'<li>Trackback from '.
$comment_url.
' added.</li>';
$count_trackbackscreated++
;
<h4>All done.
<?php if( $simulate ) echo
' (simulated - no real import!)' ?></h4>
<li>
<?php echo
$count_postscreated ?> post(s) imported.</li>
<li>
<?php echo
$count_userscreated ?> user(s) created.</li>
<li>
<?php echo
$count_commentscreated ?> comment(s) imported.</li>
<li>
<?php echo
$count_trackbackscreated ?> trackback(s) imported.</li>
<form action="import-mt.php" method="post">
<strong>This was only simulated..</strong>
foreach( $_POST as $key =>
$value )
foreach( $value as $key2 =>
$value2 )
echo
'<input type="hidden" name="'.
$key.
'['.
$key2.
']" value="'.
format_to_output( $value2, 'formvalue' ).
'" />';
echo
'<input type="hidden" name="'.
$key.
'" value="'.
format_to_output( $value, 'formvalue' ).
'" />';
echo
'<input type="submit" value="Do it for real now!" /></p></form>'.
"\n";
<a href="
<?php echo
$admin_dirout ?>">Have fun in your blogs</a> or <a href="
<?php echo
$admin_url ?>">go to admin</a> (it's fun there, too)
if( $count_userscreated )
echo
'<p class="note">Please note that the new users being created are not member of any blog yet. You\'ll have to setup this in the <a href="'.
$admin_url.
'/b2blogs.php">blogs admin</a>.</p>';
Feel free to <a href="http://thequod.de/contact">contact me</a> in case of suggestions, bugs and lack of clarity.
Of course, you're also welcome to <a href="https://sourceforge.net/donate/index.php?user_id=663176">donate to me</a> or <a href="http://sourceforge.net/donate/index.php?group_id=85535">the b2evolution project</a>.. :)
<?php if( $output_debug_dump ) $DB->dump_queries() ?>
/* ------ FUNCTIONS ------ */
global $cache_blogs, $cache_categories;
<fieldset title="default categories set" style="background-color:#fafafa; border:1px solid #ccc; padding: 1em; display:inline; float:right; white-space:nowrap;">
<legend>Default categories set (only needed if you want to map categories to this)</legend>
if( count( $cache_categories ) )
echo
T_('Select main category in target blog and optionally check additional categories').
':';
echo
'No categories in your blogs..';
// ---------------------------- CATEGORIES ------------------------------
// ----------------- START RECURSIVE CAT LIST ----------------
cat_query( false ); // make sure the caches are loaded
{ // callback to start sublist
{ // callback to display sublist element
global $current_blog_ID, $blog, $cat, $postdata, $default_main_cat, $action, $tabindex, $allow_cross_posting;
if( $allow_cross_posting )
{ // We allow cross posting, display checkbox:
echo
'<input type="checkbox" name="post_extracats[]" class="checkbox" title="', T_('Select as an additionnal category') , '" value="',$cat_ID,'"';
if( $current_blog_ID ==
$blog )
if( ($default_main_cat ==
0) &&
($action ==
'post') )
{ // Assign default cat for new post
$default_main_cat =
$cat_ID;
echo
' <input type="radio" name="post_category" class="checkbox" title="', T_('Select as MAIN category'), '" value="',$cat_ID,'"';
if( ($cat_ID ==
$postdata["Category"]) ||
($cat_ID ==
$default_main_cat))
echo
' checked="checked"';
echo
' '.
$this_cat['cat_name'];
{ // callback after each sublist element
{ // callback to end sublist
// go through all blogs with cats:
foreach( $cache_blogs as $i_blog )
{ // run recursively through the cats
$current_blog_ID =
$i_blog->blog_ID;
#if( ! $current_User->check_perm( 'blog_post_statuses', 'any', false, $current_blog_ID ) ) continue;
echo
"<h4>".
$i_blog->blog_name.
"</h4>\n";
cat_children( $cache_categories, $current_blog_ID, NULL, 'cat_select_before_first',
'cat_select_before_each', 'cat_select_after_each', 'cat_select_after_last', 1 );
// ----------------- END RECURSIVE CAT LIST ----------------
-- Category options list --
global $cache_categories, $cache_blogs, $cache_optionslist;
if( !isset
($cache_optionslist) )
foreach( $cache_blogs as $i_blog )
$cache_optionslist .=
'<option value="#NEW#'.
$i_blog->blog_ID.
'">[-- create in blog '.
$i_blog->blog_shortname.
' --]:</option>';
foreach( $cache_categories as $key =>
$value )
if( $value['cat_name'] ==
$forcat )
echo
str_replace( '<option value="'.
$cat_id.
'">', '<option value="'.
$cat_id.
'" selected="selected">', $cache_optionslist );
$ccats, // PHP requires this stupid cloning of the cache_categories array in order to be able to perform foreach on it
$level =
0 ) // Caller nesting level, just to keep track of how far we go :)
global $cache_optionslist;
// echo 'Number of cats=', count($ccats);
if( ! empty( $ccats ) ) // this can happen if there are no cats at all!
foreach( $ccats as $icat_ID =>
$i_cat )
if( $icat_ID &&
(($blog_ID ==
0) ||
($i_cat['cat_blog_ID'] ==
$blog_ID)) &&
($i_cat['cat_parent_ID'] ==
$parent_ID) )
{ // this cat is in the blog and is a child of the parent
$cache_optionslist .=
'<option value="'.
$icat_ID.
'">';
for( $i =
0; $i <
$level; $i++
)
$cache_optionslist .=
'-';
$cache_optionslist .=
'> '.
format_to_output( $ccats[ $icat_ID ]['cat_name'], 'entityencoded' ).
'</option>';
* extracts unique authors and cats from posts array
global $authors, $categories, $posts;
global $categories_countprim;
$fp =
fopen( $exportedfile, 'rb');
dieerror("The file [$exportedfile] does not seem to be a MT exported file.. ".
'[<a href="import-mt.php?mode='.
$mode.
'">choose another export-file</a>]');
$posts =
preg_split( '/(^|--------\n)(AUTHOR: |$)/', $importdata );
$authors =
array(); $tempauthors =
array();
$categories =
array(); $tempcategories =
array();
foreach ($posts as $nr =>
$post)
// first line is author of post
$oldcatcount =
count( $tempcategories );
if( preg_match_all( "/^(PRIMARY )?CATEGORY: (.*)/m", $post, $matches ) )
for( $i =
1; $i <
count( $matches[2] ); $i++
)
$cat =
trim( $matches[2][$i] );
if( !empty( $cat ) ) $tempcategories[] =
$cat;
// main category last (-> counter)
if( !empty($matches[2][0]) ) $tempcategories[] =
$matches[2][0];
if( $oldcatcount ==
count( $tempcategories ) )
$tempcategories[] =
'[no category assigned]';
// remember how many times used as primary category
@$categories_countprim[ $tempcategories[ count( $tempcategories )-
1 ] ]++
;
// we need to find unique values of author names, while preserving the order, so this function emulates the unique_value(); php function, without the sorting.
$y =
count($tempauthors) +
1;
for ($x =
1; $x <
$y; $x++
)
if( !(in_array($next,$authors)) ) $authors[] =
$next;
$y =
count($tempcategories) +
1;
for ($x =
1; $x <
$y; $x++
)
if( !(in_array($next, $categories)) ) $categories[] =
$next;
* Outputs a list of available renderers (not necessarily installed).
global $Renderer, $renderers;
$renderers =
array('default');
$Renderer->restart(); // make sure iterator is at start position
while( $loop_RendererPlugin =
$Renderer->get_next() )
{ // Go through whole list of renders
// echo ' ',$loop_RendererPlugin->code;
if( $loop_RendererPlugin->apply_when ==
'stealth'
||
$loop_RendererPlugin->apply_when ==
'never' )
{ // This is not an option.
elseif( $loop_RendererPlugin->code ==
'b2WPAutP' )
{ // special Auto-P plugin
<label for="textile" title="
<?php $loop_RendererPlugin->short_desc(); ?>"><strong>
<?php echo
$loop_RendererPlugin->name() ?>:</strong></label>
<div style="margin-left:2ex" />
<input type="radio" name="autop" value="1" class="checkbox" checked="checked" /> yes (always)<br>
<input type="radio" name="autop" value="0" class="checkbox" /> no (never)<br>
<input type="radio" name="autop" value="depends" class="checkbox" /> depends on CONVERT BREAKS
<span class="notes"> ..that means it will apply if convert breaks results to true (set to either 1, textile_2 or __DEFAULT__ (and "Convert-breaks default" checked above)</span>
<input type="checkbox" class="checkbox" name="renderers[]"
value="
<?php $loop_RendererPlugin->code() ?>" id="
<?php $loop_RendererPlugin->code() ?>"
switch( $loop_RendererPlugin->apply_when )
echo
' checked="checked"';
echo
' disabled="disabled"';
if( in_array( $loop_RendererPlugin->code, $renderers ) // Option is activated
||
in_array( 'default', $renderers ) ) // OR we're asking for default renderer set
echo
' checked="checked"';
if( in_array( $loop_RendererPlugin->code, $renderers ) ) // Option is activated
echo
' checked="checked"';
if( in_array( $loop_RendererPlugin->code, $renderers ) ) // Option is activated
echo
' checked="checked"';
echo
' disabled="disabled"';
title="
<?php $loop_RendererPlugin->short_desc(); ?>" />
<label for="
<?php $loop_RendererPlugin->code() ?>" title="
<?php $loop_RendererPlugin->short_desc(); ?>"><strong>
<?php echo
$loop_RendererPlugin->name(); ?></strong></label>
* @param string the message (wrapped in div and p tag of class error)
* @param string optional head
function dieerror( $message, $before =
'' )
die( '<div class="error"><p class="error">'.
$message.
'</p></div>
global $output_debug_dump;
global $exportedfile, $mode;
while( $this_file =
$this_dir->read() )
if( $exportedfile ==
$this_file ) $r .=
' selected="selected"';
<form action="import-mt.php" class="center">
<p>First, choose a file to import (.TXT files from /admin dir):</p>
<select name="exportedfile" onChange="submit()">
<input type="hidden" name="mode" value="
<?php echo
$mode ?>" />
<input type="submit" value="Next step..." class="search" />
<p class="center">No .TXT file found in /admin. Nothing to import...</p>
<p class="center">Please copy your Movable Type .TXT export file to the /admin directory.</p>
function ripline( $prefix, &$haystack )
if( preg_match( '|^'.
$prefix.
'(.*)|m', $haystack, $match ) )
$haystack =
preg_replace('|^'.
$prefix.
".*\n?|m", '', $haystack );
return trim( $match[1] );