Make WordPress Core


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2/wp-admin/import/blogger.php

    r4679 r5405  
    11<?php
    22
     3define( 'MAX_RESULTS',        50 ); // How many records per GData query
     4define( 'MAX_EXECUTION_TIME', 20 ); // How many seconds to let the script run
     5define( 'STATUS_INTERVAL',     3 ); // How many seconds between status bar updates
     6
    37class Blogger_Import {
    48
    5     var $lump_authors = false;
    6     var $import = array();
    7 
    8     // Shows the welcome screen and the magic iframe.
     9    // Shows the welcome screen and the magic auth link.
    910    function greet() {
    10         $title = __('Import Old Blogger');
    11         $welcome = __('Howdy! This importer allows you to import posts and comments from your Old Blogger account into your WordPress blog.');
    12         $noiframes = __('This feature requires iframe support.');
    13         $warning = js_escape(__('This will delete everything saved by the Blogger importer except your posts and comments. Are you sure you want to do this?'));
    14         $reset = __('Reset this importer');
    15         $incompat = __('Your web server is not properly configured to use this importer. Please enable the CURL extension for PHP and then reload this page.');
    16 
    17         echo "<div class='wrap'><h2>$title</h2><p>$welcome</p>";
    18         echo "<p>" . __('Please note that this importer <em>does not work with new Blogger (using your Google account)</em>.') . "</p>";
    19         if ( function_exists('curl_init') )
    20             echo "<iframe src='admin.php?import=blogger&amp;noheader=true' height='350px' width = '99%'>$noiframes</iframe><p><a href='admin.php?import=blogger&amp;restart=true&amp;noheader=true' onclick='return confirm(\"$warning\")'>$reset</a></p>";
     11        $next_url = get_option('siteurl') . '/wp-admin/index.php?import=blogger&noheader=true';
     12        $auth_url = "https://www.google.com/accounts/AuthSubRequest";
     13        $title = __('Import Blogger');
     14        $welcome = __('Howdy! This importer allows you to import posts and comments from your Blogger account into your WordPress blog.');
     15        $prereqs = __('To use this importer, you must have a Google account, an upgraded (New, was Beta) blog, and it must be on blogspot or a custom domain (not FTP).');
     16        $stepone = __('The first thing you need to do is tell Blogger to let WordPress access your account. You will be sent back here after providing authorization.');
     17        $auth = __('Authorize');
     18
     19        echo "
     20        <div class='wrap'><h2>$title</h2><p>$welcome</p><p>$prereqs</p><p>$stepone</p>
     21            <form action='$auth_url' method='get'>
     22                <p class='submit' style='text-align:left;'>
     23                    <input type='submit' value='$auth' />
     24                    <input type='hidden' name='scope' value='http://www.blogger.com/feeds/' />
     25                    <input type='hidden' name='session' value='1' />
     26                    <input type='hidden' name='secure' value='0' />
     27                    <input type='hidden' name='next' value='$next_url' />
     28                </p>
     29            </form>
     30        </div>\n";
     31    }
     32
     33    function uh_oh($title, $message, $info) {
     34        echo "<div class='wrap'><h2>$title</h2><p>$message</p><pre>$info</pre></div>";
     35    }
     36
     37    function auth() {
     38        // We have a single-use token that must be upgraded to a session token.
     39        $token = preg_replace( '/[^-_0-9a-zA-Z]/', '', $_GET['token'] );
     40        $headers = array(
     41            "GET /accounts/AuthSubSessionToken HTTP/1.0",
     42            "Authorization: AuthSub token=\"$token\""
     43        );
     44        $request = join( "\r\n", $headers ) . "\r\n\r\n";
     45        $sock = $this->_get_auth_sock( );
     46        if ( ! $sock ) return false;
     47        $response = $this->_txrx( $sock, $request );
     48        preg_match( '/token=([-_0-9a-z]+)/i', $response, $matches );
     49        if ( empty( $matches[1] ) ) {
     50            $this->uh_oh(
     51                __( 'Authorization failed' ),
     52                __( 'Something went wrong. If the problem persists, send this info to support:' ),
     53                htmlspecialchars($response)
     54            );
     55            return false;
     56        }
     57        $this->token = $matches[1];
     58
     59        wp_redirect( remove_query_arg( array( 'token', 'noheader' ) ) );
     60    }
     61
     62    function get_token_info() {
     63        $headers = array(
     64            "GET /accounts/AuthSubTokenInfo  HTTP/1.0",
     65            "Authorization: AuthSub token=\"$this->token\""
     66        );
     67        $request = join( "\r\n", $headers ) . "\r\n\r\n";
     68        $sock = $this->_get_auth_sock( );
     69        if ( ! $sock ) return;
     70        $response = $this->_txrx( $sock, $request );
     71        return $this->parse_response($response);
     72    }
     73
     74    function token_is_valid() {
     75        $info = $this->get_token_info();
     76
     77        if ( $info['code'] == 200 )
     78            return true;
     79
     80        return false;
     81    }
     82
     83    function show_blogs($iter = 0) {
     84        if ( empty($this->blogs) ) {
     85            $headers = array(
     86                "GET /feeds/default/blogs HTTP/1.0",
     87                "Host: www2.blogger.com",
     88                "Authorization: AuthSub token=\"$this->token\""
     89            );
     90            $request = join( "\r\n", $headers ) . "\r\n\r\n";
     91            $sock = $this->_get_blogger_sock( );
     92            if ( ! $sock ) return;
     93            $response = $this->_txrx( $sock, $request );
     94
     95            // Quick and dirty XML mining.
     96            list( $headers, $xml ) = explode( "\r\n\r\n", $response );
     97            $p = xml_parser_create();
     98            xml_parse_into_struct($p, $xml, $vals, $index);
     99            xml_parser_free($p);
     100
     101            $this->title = $vals[$index['TITLE'][0]]['value'];
     102
     103            // Give it a few retries... this step often flakes out the first time.
     104            if ( empty( $index['ENTRY'] ) ) {
     105                if ( $iter < 3 ) {
     106                    return $this->show_blogs($iter + 1);
     107                } else {
     108                    $this->uh_oh(
     109                        __('Trouble signing in'),
     110                        __('We were not able to gain access to your account. Try starting over.'),
     111                        ''
     112                    );
     113                    return false;
     114                }
     115            }
     116
     117            foreach ( $index['ENTRY'] as $i ) {
     118                $blog = array();
     119                while ( ( $tag = $vals[$i] ) && ! ( $tag['tag'] == 'ENTRY' && $tag['type'] == 'close' ) ) {
     120                    if ( $tag['tag'] == 'TITLE' ) {
     121                        $blog['title'] = $tag['value'];
     122                    } elseif ( $tag['tag'] == 'SUMMARY' ) {
     123                        $blog['summary'] == $tag['value'];
     124                    } elseif ( $tag['tag'] == 'LINK' ) {
     125                        if ( $tag['attributes']['REL'] == 'alternate' && $tag['attributes']['TYPE'] == 'text/html' ) {
     126                            $parts = parse_url( $tag['attributes']['HREF'] );
     127                            $blog['host'] = $parts['host'];
     128                        } elseif ( $tag['attributes']['REL'] == 'edit' )
     129                            $blog['gateway'] = $tag['attributes']['HREF'];
     130                    }
     131                    ++$i;
     132                }
     133                if ( ! empty ( $blog ) ) {
     134                    $blog['total_posts'] = $this->get_total_results('posts', $blog['host']);
     135                    $blog['total_comments'] = $this->get_total_results('comments', $blog['host']);
     136                    $blog['mode'] = 'init';
     137                    $this->blogs[] = $blog;
     138                }
     139            }
     140
     141            if ( empty( $this->blogs ) ) {
     142                $this->uh_oh(
     143                    __('No blogs found'),
     144                    __('We were able to log in but there were no blogs. Try a different account next time.'),
     145                    ''
     146                );
     147                return false;
     148            }
     149        }
     150//echo '<pre>'.print_r($this,1).'</pre>';
     151        $start    = js_escape( __('Import') );
     152        $continue = js_escape( __('Continue') );
     153        $stop     = js_escape( __('Importing...') );
     154        $authors  = js_escape( __('Set Authors') );
     155        $loadauth = js_escape( __('Preparing author mapping form...') );
     156        $authhead = js_escape( __('Final Step: Author Mapping') );
     157        $nothing  = js_escape( __('Nothing was imported. Had you already imported this blog?') );
     158        $title    = __('Blogger Blogs');
     159        $name     = __('Blog Name');
     160        $url      = __('Blog URL');
     161        $action   = __('The Magic Button');
     162        $posts    = __('Posts');
     163        $comments = __('Comments');
     164        $noscript = __('This feature requires Javascript but it seems to be disabled. Please enable Javascript and then reload this page. Don\'t worry, you can turn it back off when you\'re done.');
     165
     166        $interval = STATUS_INTERVAL * 1000;
     167
     168        foreach ( $this->blogs as $i => $blog ) {
     169            if ( $blog['mode'] == 'init' )
     170                $value = $start;
     171            elseif ( $blog['mode'] == 'posts' || $blog['mode'] == 'comments' )
     172                $value = $continue;
     173            else
     174                $value = $authors;
     175            $blogtitle = js_escape( $blog['title'] );
     176            $pdone = isset($blog['posts_done']) ? (int) $blog['posts_done'] : 0;
     177            $cdone = isset($blog['comments_done']) ? (int) $blog['comments_done'] : 0;
     178            $init .= "blogs[$i]=new blog($i,'$blogtitle','{$blog['mode']}'," . $this->get_js_status($i) . ');';
     179            $pstat = "<div class='ind' id='pind$i'>&nbsp;</div><div id='pstat$i' class='stat'>$pdone/{$blog['total_posts']}</div>";
     180            $cstat = "<div class='ind' id='cind$i'>&nbsp;</div><div id='cstat$i' class='stat'>$cdone/{$blog['total_comments']}</div>";
     181            $rows .= "<tr id='blog$i'><td class='blogtitle'>$blogtitle</td><td class='bloghost'>{$blog['host']}</td><td class='bar'>$pstat</td><td class='bar'>$cstat</td><td class='submit'><input type='submit' id='submit$i' value='$value' /><input type='hidden' name='blog' value='$i' /></td></tr>\n";
     182        }
     183
     184        echo "<div class='wrap'><h2>$title</h2><noscript>$noscript</noscript><table cellpadding='5px'><thead><td>$name</td><td>$url</td><td>$posts</td><td>$comments</td><td>$action</td></thead>\n$rows</table></form></div>";
     185        echo "
     186        <script type='text/javascript'>
     187            var strings = {cont:'$continue',stop:'$stop',stopping:'$stopping',authors:'$authors',nothing:'$nothing'};
     188            var blogs = {};
     189            function blog(i, title, mode, status){
     190                this.blog   = i;
     191                this.mode   = mode;
     192                this.title  = title;
     193                this.status = status;
     194                this.button = document.getElementById('submit'+this.blog);
     195            };
     196            blog.prototype = {
     197                start: function() {
     198                    this.cont = true;
     199                    this.kick();
     200                    this.check();
     201                },
     202                kick: function() {
     203                    ++this.kicks;
     204                    var i = this.blog;
     205                    jQuery.post('admin.php?import=blogger&noheader=true',{blog:this.blog},function(text,result){blogs[i].kickd(text,result)});
     206                },
     207                check: function() {
     208                    ++this.checks;
     209                    var i = this.blog;
     210                    jQuery.post('admin.php?import=blogger&noheader=true&status=true',{blog:this.blog},function(text,result){blogs[i].checkd(text,result)});
     211                },
     212                kickd: function(text, result) {
     213                    if ( result == 'error' ) {
     214                        // TODO: exception handling
     215                        if ( this.cont )
     216                            setTimeout('blogs['+this.blog+'].kick()', 1000);
     217                    } else {
     218                        if ( text == 'done' ) {
     219                            this.stop();
     220                            this.done();
     221                        } else if ( text == 'nothing' ) {
     222                            this.stop();
     223                            this.nothing();
     224                        } else if ( text == 'continue' ) {
     225                            this.kick();
     226                        } else if ( this.mode = 'stopped' )
     227                            jQuery(this.button).attr('value', strings.cont);
     228                    }
     229                    --this.kicks;
     230                },
     231                checkd: function(text, result) {
     232                    if ( result == 'error' ) {
     233                        // TODO: exception handling
     234                    } else {
     235                        eval('this.status='+text);
     236                        jQuery('#pstat'+this.blog).empty().append(this.status.p1+'/'+this.status.p2);
     237                        jQuery('#cstat'+this.blog).empty().append(this.status.c1+'/'+this.status.c2);
     238                        this.update();
     239                        if ( this.cont || this.kicks > 0 )
     240                            setTimeout('blogs['+this.blog+'].check()', $interval);
     241                    }
     242                    --this.checks;
     243                },
     244                update: function() {
     245                    jQuery('#pind'+this.blog).width(((this.status.p1>0&&this.status.p2>0)?(this.status.p1/this.status.p2*jQuery('#pind'+this.blog).parent().width()):1)+'px');
     246                    jQuery('#cind'+this.blog).width(((this.status.c1>0&&this.status.c2>0)?(this.status.c1/this.status.c2*jQuery('#cind'+this.blog).parent().width()):1)+'px');
     247                },
     248                stop: function() {
     249                    this.cont = false;
     250                },
     251                done: function() {
     252                    this.mode = 'authors';
     253                    jQuery(this.button).attr('value', strings.authors);
     254                },
     255                nothing: function() {
     256                    this.mode = 'nothing';
     257                    jQuery(this.button).remove();
     258                    alert(strings.nothing);
     259                },
     260                getauthors: function() {
     261                    if ( jQuery('div.wrap').length > 1 )
     262                        jQuery('div.wrap').gt(0).remove();
     263                    jQuery('div.wrap').empty().append('<h2>$authhead</h2><h3>' + this.title + '</h3>');
     264                    jQuery('div.wrap').append('<p id=\"auth\">$loadauth</p>');
     265                    jQuery('p#auth').load('index.php?import=blogger&noheader=true&authors=1',{blog:this.blog});
     266                },
     267                init: function() {
     268                    this.update();
     269                    var i = this.blog;
     270                    jQuery(this.button).bind('click', function(){return blogs[i].click();});
     271                    this.kicks = 0;
     272                    this.checks = 0;
     273                },
     274                click: function() {
     275                    if ( this.mode == 'init' || this.mode == 'stopped' || this.mode == 'posts' || this.mode == 'comments' ) {
     276                        this.mode = 'started';
     277                        this.start();
     278                        jQuery(this.button).attr('value', strings.stop);
     279                    } else if ( this.mode == 'started' ) {
     280                        return false; // let it run...
     281                        this.mode = 'stopped';
     282                        this.stop();
     283                        if ( this.checks > 0 || this.kicks > 0 ) {
     284                            this.mode = 'stopping';
     285                            jQuery(this.button).attr('value', strings.stopping);
     286                        } else {
     287                            jQuery(this.button).attr('value', strings.cont);
     288                        }
     289                    } else if ( this.mode == 'authors' ) {
     290                        document.location = 'index.php?import=blogger&authors=1&blog='+this.blog;
     291                        //this.mode = 'authors2';
     292                        //this.getauthors();
     293                    }
     294                    return false;
     295                }
     296            };
     297            $init
     298            jQuery.each(blogs, function(i, me){me.init();});
     299        </script>\n";
     300    }
     301
     302    // Handy function for stopping the script after a number of seconds.
     303    function have_time() {
     304        global $importer_started;
     305        if ( time() - $importer_started > MAX_EXECUTION_TIME )
     306            die('continue');
     307        return true;
     308    }
     309
     310    function get_total_results($type, $host) {
     311        $headers = array(
     312            "GET /feeds/$type/default?max-results=1&start-index=2 HTTP/1.0",
     313            "Host: $host",
     314            "Authorization: AuthSub token=\"$this->token\""
     315        );
     316        $request = join( "\r\n", $headers ) . "\r\n\r\n";
     317        $sock = $this->_get_blogger_sock( $host );
     318        if ( ! $sock ) return;
     319        $response = $this->_txrx( $sock, $request );
     320        $response = $this->parse_response( $response );
     321        $parser = xml_parser_create();
     322        xml_parse_into_struct($parser, $response['body'], $struct, $index);
     323        xml_parser_free($parser);
     324        $total_results = $struct[$index['OPENSEARCH:TOTALRESULTS'][0]]['value'];
     325        return (int) $total_results;
     326    }
     327
     328    function import_blog($blogID) {
     329        global $importing_blog;
     330        $importing_blog = $blogID;
     331
     332        if ( isset($_GET['authors']) )
     333            return print($this->get_author_form());
     334
     335        header('Content-Type: text/plain');
     336
     337        if ( isset($_GET['status']) )
     338            die($this->get_js_status());
     339
     340        if ( isset($_GET['saveauthors']) )
     341            die($this->save_authors());
     342
     343        $blog = $this->blogs[$blogID];
     344        $total_results = $this->get_total_results('posts', $blog['host']);
     345        $this->blogs[$importing_blog]['total_posts'] = $total_results;
     346
     347        $start_index = $total_results - MAX_RESULTS + 1;
     348
     349        if ( isset( $this->blogs[$importing_blog]['posts_start_index'] ) )
     350            $start_index = (int) $this->blogs[$importing_blog]['posts_start_index'];
     351        elseif ( $total_results > MAX_RESULTS )
     352            $start_index = $total_results - MAX_RESULTS + 1;
    21353        else
    22             echo "<p>$incompat</p>";
    23         echo "</div>\n";
    24     }
    25 
    26     // Deletes saved data and redirect.
     354            $start_index = 1;
     355
     356        // This will be positive until we have finished importing posts
     357        if ( $start_index > 0 ) {
     358            // Grab all the posts
     359            $this->blogs[$importing_blog]['mode'] = 'posts';
     360            $query = "start-index=$start_index&max-results=" . MAX_RESULTS;
     361            do {
     362                $index = $struct = $entries = array();
     363                $headers = array(
     364                    "GET /feeds/posts/default?$query HTTP/1.0",
     365                    "Host: {$blog['host']}",
     366                    "Authorization: AuthSub token=\"$this->token\""
     367                );
     368                $request = join( "\r\n", $headers ) . "\r\n\r\n";
     369                $sock = $this->_get_blogger_sock( $blog['host'] );
     370                if ( ! $sock ) return; // TODO: Error handling
     371                $response = $this->_txrx( $sock, $request );
     372
     373                $response = $this->parse_response( $response );
     374
     375                // Extract the entries and send for insertion
     376                preg_match_all( '/<entry[^>]*>.*?<\/entry>/s', $response['body'], $matches );
     377                if ( count( $matches[0] ) ) {
     378                    $entries = array_reverse($matches[0]);
     379                    foreach ( $entries as $entry ) {
     380                        $entry = "<feed>$entry</feed>";
     381                        $AtomParser = new AtomParser();
     382                        $AtomParser->parse( $entry );
     383                        $this->import_post($AtomParser->entry);
     384                        unset($AtomParser);
     385                    }
     386                } else break;
     387
     388                // Get the 'previous' query string which we'll use on the next iteration
     389                $query = '';
     390                $links = preg_match_all('/<link([^>]*)>/', $response['body'], $matches);
     391                if ( count( $matches[1] ) )
     392                    foreach ( $matches[1] as $match )
     393                        if ( preg_match('/rel=.previous./', $match) )
     394                            $query = html_entity_decode( preg_replace('/^.*href=[\'"].*\?(.+)[\'"].*$/', '$1', $match) );
     395
     396                if ( $query ) {
     397                    parse_str($query, $q);
     398                    $this->blogs[$importing_blog]['posts_start_index'] = (int) $q['start-index'];
     399                } else
     400                    $this->blogs[$importing_blog]['posts_start_index'] = 0;
     401                $this->save_vars();
     402            } while ( !empty( $query ) && $this->have_time() );
     403        }
     404
     405        $total_results = $this->get_total_results( 'comments', $blog['host'] );
     406        $this->blogs[$importing_blog]['total_comments'] = $total_results;
     407
     408        if ( isset( $this->blogs[$importing_blog]['comments_start_index'] ) )
     409            $start_index = (int) $this->blogs[$importing_blog]['comments_start_index'];
     410        elseif ( $total_results > MAX_RESULTS )
     411            $start_index = $total_results - MAX_RESULTS + 1;
     412        else
     413            $start_index = 1;
     414
     415        if ( $start_index > 0 ) {
     416            // Grab all the comments
     417            $this->blogs[$importing_blog]['mode'] = 'comments';
     418            $query = "start-index=$start_index&max-results=" . MAX_RESULTS;
     419            do {
     420                $index = $struct = $entries = array();
     421                $headers = array(
     422                    "GET /feeds/comments/default?$query HTTP/1.0",
     423                    "Host: {$blog['host']}",
     424                    "Authorization: AuthSub token=\"$this->token\""
     425                );
     426                $request = join( "\r\n", $headers ) . "\r\n\r\n";
     427                $sock = $this->_get_blogger_sock( $blog['host'] );
     428                if ( ! $sock ) return; // TODO: Error handling
     429                $response = $this->_txrx( $sock, $request );
     430
     431                $response = $this->parse_response( $response );
     432
     433                // Extract the comments and send for insertion
     434                preg_match_all( '/<entry[^>]*>.*?<\/entry>/s', $response['body'], $matches );
     435                if ( count( $matches[0] ) ) {
     436                    $entries = array_reverse( $matches[0] );
     437                    foreach ( $entries as $entry ) {
     438                        $entry = "<feed>$entry</feed>";
     439                        $AtomParser = new AtomParser();
     440                        $AtomParser->parse( $entry );
     441                        $this->import_comment($AtomParser->entry);
     442                        unset($AtomParser);
     443                    }
     444                }
     445
     446                // Get the 'previous' query string which we'll use on the next iteration
     447                $query = '';
     448                $links = preg_match_all('/<link([^>]*)>/', $response['body'], $matches);
     449                if ( count( $matches[1] ) )
     450                    foreach ( $matches[1] as $match )
     451                        if ( preg_match('/rel=.previous./', $match) )
     452                            $query = html_entity_decode( preg_replace('/^.*href=[\'"].*\?(.+)[\'"].*$/', '$1', $match) );
     453
     454                parse_str($query, $q);
     455
     456                $this->blogs[$importing_blog]['comments_start_index'] = (int) $q['start-index'];
     457                $this->save_vars();
     458            } while ( !empty( $query ) && $this->have_time() );
     459        }
     460        $this->blogs[$importing_blog]['mode'] = 'authors';
     461        $this->save_vars();
     462        if ( !$this->blogs[$importing_blog]['posts_done'] && !$this->blogs[$importing_blog]['comments_done'] )
     463            die('nothing');
     464        do_action('import_done', 'blogger');
     465        die('done');
     466    }
     467
     468    function convert_date( $date ) {
     469        preg_match('#([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(?:\.[0-9]+)?(Z|[\+|\-][0-9]{2,4}){0,1}#', $date, $date_bits);
     470        $offset = iso8601_timezone_to_offset( $date_bits[7] );
     471        $timestamp = gmmktime($date_bits[4], $date_bits[5], $date_bits[6], $date_bits[2], $date_bits[3], $date_bits[1]);
     472        $timestamp -= $offset; // Convert from Blogger local time to GMT
     473        $timestamp += get_option('gmt_offset') * 3600; // Convert from GMT to WP local time
     474        return gmdate('Y-m-d H:i:s', $timestamp);
     475    }
     476
     477    function no_apos( $string ) {
     478        return str_replace( '&apos;', "'", $string);
     479    }
     480
     481    function min_whitespace( $string ) {
     482        return preg_replace( '|\s+|', ' ', $string );
     483    }
     484
     485    function import_post( $entry ) {
     486        global $wpdb, $importing_blog;
     487
     488        // The old permalink is all Blogger gives us to link comments to their posts.
     489        if ( isset( $entry->draft ) )
     490            $rel = 'self';
     491        else
     492            $rel = 'alternate';
     493        foreach ( $entry->links as $link ) {
     494            if ( $link['rel'] == $rel ) {
     495                $parts = parse_url( $link['href'] );
     496                $entry->old_permalink = $parts['path'];
     497                break;
     498            }
     499        }
     500
     501        $post_date    = $this->convert_date( $entry->published );
     502        $post_content = trim( addslashes( $this->no_apos( html_entity_decode( $entry->content ) ) ) );
     503        $post_title   = trim( addslashes( $this->no_apos( $this->min_whitespace( $entry->title ) ) ) );
     504        $post_status  = isset( $entry->draft ) ? 'draft' : 'publish';
     505
     506        // Clean up content
     507        $post_content = preg_replace('|<(/?[A-Z]+)|e', "'<' . strtolower('$1')", $post_content);
     508        $post_content = str_replace('<br>', '<br />', $post_content);
     509        $post_content = str_replace('<hr>', '<hr />', $post_content);
     510
     511        // Checks for duplicates
     512        if (
     513            isset( $this->blogs[$importing_blog]['posts'][$entry->old_permalink] ) ||
     514            post_exists( $post_title, $post_content, $post_date )
     515        ) {
     516            ++$this->blogs[$importing_blog]['posts_skipped'];
     517        } else {
     518            $post = compact('post_date', 'post_content', 'post_title', 'post_status');
     519
     520            $post_id = wp_insert_post($post);
     521
     522            wp_create_categories( array_map( 'addslashes', $entry->categories ), $post_id );
     523
     524            $author = $this->no_apos( strip_tags( $entry->author ) );
     525
     526            add_post_meta( $post_id, 'blogger_blog', $this->blogs[$importing_blog]['host'], true );
     527            add_post_meta( $post_id, 'blogger_author', $author, true );
     528            add_post_meta( $post_id, 'blogger_permalink', $entry->old_permalink, true );
     529
     530            $this->blogs[$importing_blog]['posts'][$entry->old_permalink] = $post_id;
     531            ++$this->blogs[$importing_blog]['posts_done'];
     532        }
     533        $this->save_vars();
     534    }
     535
     536    function import_comment( $entry ) {
     537        global $importing_blog;
     538
     539        // Drop the #fragment and we have the comment's old post permalink.
     540        foreach ( $entry->links as $link ) {
     541            if ( $link['rel'] == 'alternate' ) {
     542                $parts = parse_url( $link['href'] );
     543                $entry->old_permalink = $parts['fragment'];
     544                $entry->old_post_permalink = $parts['path'];
     545                break;
     546            }
     547        }
     548
     549        $comment_post_ID = (int) $this->blogs[$importing_blog]['posts'][$entry->old_post_permalink];
     550        preg_match('#<name>(.+?)</name>.*(?:\<uri>(.+?)</uri>)?#', $entry->author, $matches);
     551        $comment_author  = addslashes( $this->no_apos( strip_tags( (string) $matches[1] ) ) );
     552        $comment_author_url = addslashes( $this->no_apos( strip_tags( (string) $matches[2] ) ) );
     553        $comment_date    = $this->convert_date( $entry->updated );
     554        $comment_content = addslashes( $this->no_apos( html_entity_decode( $entry->content ) ) );
     555
     556        // Clean up content
     557        $comment_content = preg_replace('|<(/?[A-Z]+)|e', "'<' . strtolower('$1')", $comment_content);
     558        $comment_content = str_replace('<br>', '<br />', $comment_content);
     559        $comment_content = str_replace('<hr>', '<hr />', $comment_content);
     560
     561        // Checks for duplicates
     562        if (
     563            isset( $this->blogs[$importing_blog]['comments'][$entry->old_permalink] ) ||
     564            comment_exists( $comment_author, $comment_date )
     565        ) {
     566            ++$this->blogs[$importing_blog]['comments_skipped'];
     567        } else {
     568            $comment = compact('comment_post_ID', 'comment_author', 'comment_author_url', 'comment_date', 'comment_content');
     569
     570            $comment_id = wp_insert_comment($comment);
     571
     572            $this->blogs[$importing_blog]['comments'][$entry->old_permalink] = $comment_id;
     573
     574            ++$this->blogs[$importing_blog]['comments_done'];
     575        }
     576        $this->save_vars();
     577    }
     578
     579    function get_js_status($blog = false) {
     580        global $importing_blog;
     581        if ( $blog === false )
     582            $blog = $this->blogs[$importing_blog];
     583        else
     584            $blog = $this->blogs[$blog];
     585        $p1 = isset( $blog['posts_done'] ) ? (int) $blog['posts_done'] : 0;
     586        $p2 = isset( $blog['total_posts'] ) ? (int) $blog['total_posts'] : 0;
     587        $c1 = isset( $blog['comments_done'] ) ? (int) $blog['comments_done'] : 0;
     588        $c2 = isset( $blog['total_comments'] ) ? (int) $blog['total_comments'] : 0;
     589        return "{p1:$p1,p2:$p2,c1:$c1,c2:$c2}";
     590    }
     591
     592    function get_author_form($blog = false) {
     593        global $importing_blog, $wpdb, $current_user;
     594        if ( $blog === false )
     595            $blog = & $this->blogs[$importing_blog];
     596        else
     597            $blog = & $this->blogs[$blog];
     598
     599        if ( !isset( $blog['authors'] ) ) {
     600            $post_ids = array_values($blog['posts']);
     601            $authors = (array) $wpdb->get_col("SELECT DISTINCT meta_value FROM $wpdb->postmeta WHERE meta_key = 'blogger_author' AND post_id IN (" . join( ',', $post_ids ) . ")");
     602            $blog['authors'] = array_map(null, $authors, array_fill(0, count($authors), $current_user->ID));
     603            $this->save_vars();
     604        }
     605
     606        $directions = __('All posts were imported with the current user as author. Use this form to move each Blogger user\'s posts to a different WordPress user. You may <a href="users.php">add users</a> and then return to this page and complete the user mapping. This form may be used as many times as you like until you activate the "Restart" function below.');
     607        $heading = __('Author mapping');
     608        $blogtitle = "{$blog['title']} ({$blog['host']})";
     609        $mapthis = __('Blogger username');
     610        $tothis = __('WordPress login');
     611        $submit = js_escape( __('Save Changes &raquo;') );
     612
     613        foreach ( $blog['authors'] as $i => $author )
     614            $rows .= "<tr><td><label for='authors[$i]'>{$author[0]}</label></td><td><select name='authors[$i]' id='authors[$i]'>" . $this->get_user_options($author[1]) . "</select></td></tr>";
     615
     616        return "<div class='wrap'><h2>$heading</h2><h3>$blogtitle</h3><p>$directions</p><form action='index.php?import=blogger&noheader=true&saveauthors=1' method='post'><input type='hidden' name='blog' value='$importing_blog' /><table cellpadding='5'><thead><td>$mapthis</td><td>$tothis</td></thead>$rows<tr><td></td><td class='submit'><input type='submit' class='authorsubmit' value='$submit' /></td></tr></table></form></div>";
     617    }
     618
     619    function get_user_options($current) {
     620        global $wpdb, $importer_users;
     621        if ( ! isset( $importer_users ) )
     622            $importer_users = (array) get_users_of_blog();
     623
     624        foreach ( $importer_users as $user ) {
     625            $sel = ( $user->user_id == $current ) ? " selected='selected'" : '';
     626            $options .= "<option value='$user->user_id'$sel>$user->display_name</option>";
     627        }
     628
     629        return $options;
     630    }
     631
     632    function save_authors() {
     633        global $importing_blog, $wpdb;
     634        $authors = (array) $_POST['authors'];
     635
     636        $host = $this->blogs[$importing_blog]['host'];
     637
     638        // Get an array of posts => authors
     639        $post_ids = (array) $wpdb->get_col("SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'blogger_blog' AND meta_value = '$host'");
     640        $post_ids = join( ',', $post_ids );
     641        $results = (array) $wpdb->get_results("SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = 'blogger_author' AND post_id IN ($post_ids)");
     642        foreach ( $results as $row )
     643            $authors_posts[$row->post_id] = $row->meta_value;
     644
     645        foreach ( $authors as $author => $user_id ) {
     646            $user_id = (int) $user_id;
     647
     648            // Skip authors that haven't been changed
     649            if ( $user_id == $this->blogs[$importing_blog]['authors'][$author][1] )
     650                continue;
     651
     652            // Get a list of the selected author's posts
     653            $post_ids = (array) array_keys( $authors_posts, $this->blogs[$importing_blog]['authors'][$author][0] );
     654            $post_ids = join( ',', $post_ids);
     655
     656            $wpdb->query("UPDATE $wpdb->posts SET post_author = $user_id WHERE id IN ($post_ids)");
     657            $this->blogs[$importing_blog]['authors'][$author][1] = $user_id;
     658        }
     659        $this->save_vars();
     660
     661        wp_redirect('edit.php');
     662    }
     663
     664    function _get_auth_sock() {
     665        // Connect to https://www.google.com
     666        if ( !$sock = @ fsockopen('ssl://www.google.com', 443, $errno, $errstr) ) {
     667            $this->uh_oh(
     668                __('Could not connect to https://www.google.com'),
     669                __('There was a problem opening a secure connection to Google. This is what went wrong:'),
     670                "$errstr ($errno)"
     671            );
     672            return false;
     673        }
     674        return $sock;
     675    }
     676
     677    function _get_blogger_sock($host = 'www2.blogger.com') {
     678        if ( !$sock = @ fsockopen($host, 80, $errno, $errstr) ) {
     679            $this->uh_oh(
     680                sprintf( __('Could not connect to %s'), $host ),
     681                __('There was a problem opening a connection to Blogger. This is what went wrong:'),
     682                "$errstr ($errno)"
     683            );
     684            return false;
     685        }
     686        return $sock;
     687    }
     688
     689    function _txrx( $sock, $request ) {
     690        fwrite( $sock, $request );
     691        while ( ! feof( $sock ) )
     692            $response .= @ fread ( $sock, 8192 );
     693        fclose( $sock );
     694        return $response;
     695    }
     696
     697    function revoke($token) {
     698        $headers = array(
     699            "GET /accounts/AuthSubRevokeToken HTTP/1.0",
     700            "Authorization: AuthSub token=\"$token\""
     701        );
     702        $request = join( "\r\n", $headers ) . "\r\n\r\n";
     703        $sock = $this->_get_auth_sock( );
     704        if ( ! $sock ) return false;
     705        $this->_txrx( $sock, $request );
     706    }
     707
    27708    function restart() {
    28         delete_option('import-blogger');
    29         wp_redirect("admin.php?import=blogger");
    30         die();
    31     }
    32 
    33     // Generates a string that will make the page reload in a specified interval.
    34     function refresher($msec) {
    35         if ( $msec )
    36             return "<html><head><script type='text/javascript'>window.onload=setTimeout('window.location.reload()', $msec);</script>\n</head>\n<body>\n";
    37         else
    38             return "<html><head><script type='text/javascript'>window.onload=window.location.reload();</script>\n</head>\n<body>\n";
     709        global $wpdb;
     710        $options = get_option( 'blogger_importer' );
     711
     712        if ( isset( $options['token'] ) )
     713            $this->revoke( $options['token'] );
     714
     715        delete_option('blogger_importer');
     716        $wpdb->query("DELETE FROM $wpdb->postmeta WHERE meta_key = 'blogger_author'");
     717        wp_redirect('?import=blogger');
    39718    }
    40719
     
    63742    }
    64743
    65     // Prints a form for the user to enter Blogger creds.
    66     function login_form($text='') {
    67         echo '<h1>' . __('Log in to Blogger') . "</h1>\n$text\n";
    68         echo '<form method="post" action="admin.php?import=blogger&amp;noheader=true&amp;step=0"><table><tr><td>' . __('Username') . ':</td><td><input type="text" name="user" /></td></tr><tr><td>' . __('Password') . ':</td><td><input type="password" name="pass" /></td><td><input type="submit" value="' . __('Start') . '" /></td></tr></table></form>';
    69         die;
    70     }
    71 
    72     // Sends creds to Blogger, returns the session cookies an array of headers.
    73     function login_blogger($user, $pass) {
    74         $_url = 'http://www.blogger.com/login.do';
    75         $params = "username=$user&password=$pass";
    76         $ch = curl_init();
    77         curl_setopt($ch, CURLOPT_POST,1);
    78         curl_setopt($ch, CURLOPT_POSTFIELDS,$params);
    79         curl_setopt($ch, CURLOPT_URL,$_url);
    80         curl_setopt($ch, CURLOPT_USERAGENT, 'Blogger Exporter');
    81         curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
    82         curl_setopt($ch, CURLOPT_HEADER,1);
    83         curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
    84         $response = curl_exec ($ch);
    85 
    86         $response = $this->parse_response($response);
    87 
    88         sleep(1);
    89 
    90         return $response['cookies'];
    91     }
    92 
    93     // Requests page from Blogger, returns the response array.
    94     function get_blogger($url, $header = '', $user=false, $pass=false) {
    95         $ch = curl_init();
    96         if ($user && $pass) curl_setopt($ch, CURLOPT_USERPWD,"{$user}:{$pass}");
    97         curl_setopt($ch, CURLOPT_URL,$url);
    98         curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    99         curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    100         curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    101         curl_setopt($ch, CURLOPT_USERAGENT, 'Blogger Exporter');
    102         curl_setopt($ch, CURLOPT_HEADER,1);
    103         if (is_array($header)) curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    104         $response = curl_exec ($ch);
    105 
    106         $response = $this->parse_response($response);
    107         $response['url'] = $url;
    108 
    109         if (curl_errno($ch)) {
    110             print curl_error($ch);
    111         } else {
    112             curl_close($ch);
    113         }
    114 
    115         return $response;
    116     }
    117 
    118     // Posts data to Blogger, returns response array.
    119     function post_blogger($url, $header = false, $paramary = false, $parse=true) {
    120         $params = '';
    121         if ( is_array($paramary) ) {
    122             foreach($paramary as $key=>$value)
    123                 if($key && $value != '')
    124                     $params.=$key."=".urlencode(stripslashes($value))."&";
    125         }
    126         if ($user && $pass) $params .= "username=$user&password=$pass";
    127         $params = trim($params,'&');
    128         $ch = curl_init();
    129         curl_setopt($ch, CURLOPT_POST,1);
    130         curl_setopt($ch, CURLOPT_POSTFIELDS,$params);
    131         if ($user && $pass) curl_setopt($ch, CURLOPT_USERPWD,"{$user}:{$pass}");
    132         curl_setopt($ch, CURLOPT_URL,$url);
    133         curl_setopt($ch, CURLOPT_USERAGENT, 'Blogger Exporter');
    134         curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    135         curl_setopt($ch, CURLOPT_HEADER,$parse);
    136         curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
    137         if ($header) curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    138         $response = curl_exec ($ch);
    139 
    140         if ($parse) {
    141             $response = $this->parse_response($response);
    142             $response['url'] = $url;
    143             return $response;
    144         }
    145 
    146         return $response;
    147     }
    148 
    149     // Prints the list of blogs for import.
    150     function show_blogs() {
    151         global $import;
    152         echo '<h1>' . __('Selecting a Blog') . "</h1>\n<ul>";
    153         foreach ( $this->import['blogs'] as $blog ) {
    154             if (9 == $blog['nextstep']) $status = "100%";
    155             elseif (8 == $blog['nextstep']) $status = "90%";
    156             elseif (7 == $blog['nextstep']) $status = "82.5%";
    157             elseif (6 == $blog['nextstep']) $status = "75%";
    158             elseif (5 == $blog['nextstep']) $status = "57%";
    159             elseif (4 == $blog['nextstep']) $status = "28%";
    160             elseif (3 == $blog['nextstep']) $status = "14%";
    161             else $status = "0%";
    162             echo "\t<li><a href='admin.php?import=blogger&amp;noheader=true&amp;blog={$blog['id']}'>{$blog['title']}</a> $status</li>\n";
    163         }
    164         die("</ul>\n");
    165     }
    166 
    167     // Publishes.
    168     function publish_blogger($i, $text) {
    169         $head = $this->refresher(2000) . "<h1>$text</h1>\n";
    170         if ( ! strstr($this->import['blogs'][$_GET['blog']]['publish'][$i], 'http') ) {
    171             // First call. Start the publish process with a fresh set of cookies.
    172             $this->import['cookies'] = $this->login_blogger($this->import['user'], $this->import['pass']);
    173             update_option('import-blogger', $this->import);
    174             $paramary = array('blogID' => $_GET['blog'], 'all' => '1', 'republishAll' => 'Republish Entire Blog', 'publish' => '1', 'redirectUrl' => "/publish.do?blogID={$_GET['blog']}&inprogress=true");
    175 
    176             $response = $this->post_blogger("http://www.blogger.com/publish.do?blogID={$_GET['blog']}", $this->import['cookies'], $paramary);
    177             if ( $response['code'] == '302' ) {
    178                 $url = str_replace('publish.g', 'publish-body.g', $response['header']['Location']);
    179                 $this->import['blogs'][$_GET['blog']]['publish'][$i] = $url;
    180                 update_option('import-blogger', $this->import);
    181                 $response = $this->get_blogger($url, $this->import['cookies']);
    182                 preg_match('#<p class="progressIndicator">.*</p>#U', $response['body'], $matches);
    183                 $progress = $matches[0];
    184                 die($head . $progress);
    185             } else {
    186                 $this->import['blogs'][$_GET['blog']]['publish'][$i] = false;
    187                 update_option('import-blogger', $this->import);
    188                 die($head);
    189             }
    190         } else {
    191             // Subsequent call. Keep checking status until Blogger reports publish complete.
    192             $url = $this->import['blogs'][$_GET['blog']]['publish'][$i];
    193             $response = $this->get_blogger($url, $this->import['cookies']);
    194             if ( preg_match('#<p class="progressIndicator">.*</p>#U', $response['body'], $matches) ) {
    195                 $progress = $matches[0];
    196                 if ( strstr($progress, '100%') ) {
    197                     $this->set_next_step($i);
    198                     $progress .= '<p>'.__('Moving on...').'</p>';
    199                 }
    200                 die($head . $progress);
    201             } else {
    202                 $this->import['blogs'][$_GET['blog']]['publish'][$i] = false;
    203                 update_option('import-blogger', $this->import);
    204                 die("$head<p>" . __('Trying again...') . '</p>');
    205             }
    206         }
    207     }
    208 
    209     // Sets next step, saves options
    210     function set_next_step($step) {
    211         $this->import['blogs'][$_GET['blog']]['nextstep'] = $step;
    212         update_option('import-blogger', $this->import);
    213     }
    214 
    215     // Redirects to next step
    216     function do_next_step() {
    217         wp_redirect("admin.php?import=blogger&noheader=true&blog={$_GET['blog']}");
    218         die();
    219     }
    220 
    221     // Step 0: Do Blogger login, get blogid/title pairs.
    222     function do_login() {
    223         if ( ( ! $this->import['user'] && ! is_array($this->import['cookies']) ) ) {
    224             // The user must provide a Blogger username and password.
    225             if ( ! ( $_POST['user'] && $_POST['pass'] ) ) {
    226                 $this->login_form(__('The script will log into your Blogger account, change some settings so it can read your blog, and restore the original settings when it\'s done. Here\'s what you do:').'</p><ol><li>'.__('Back up your Blogger template.').'</li><li>'.__('Back up any other Blogger settings you might need later.').'</li><li>'.__('Log out of Blogger').'</li><li>'.__('Log in <em>here</em> with your Blogger username and password.').'</li><li>'.__('On the next screen, click one of your Blogger blogs.').'</li><li>'.__('Do not close this window or navigate away until the process is complete.').'</li></ol>');
    227             }
    228 
    229             // Try logging in. If we get an array of cookies back, we at least connected.
    230             $this->import['cookies'] = $this->login_blogger($_POST['user'], $_POST['pass']);
    231             if ( !is_array( $this->import['cookies'] ) ) {
    232                 $this->login_form(__('Login failed. Please enter your credentials again.'));
    233             }
    234 
    235             // Save the password so we can log the browser in when it's time to publish.
    236             $this->import['pass'] = $_POST['pass'];
    237             $this->import['user'] = $_POST['user'];
    238 
    239             // Get the Blogger welcome page and scrape the blog numbers and names from it
    240             $response = $this->get_blogger('http://www.blogger.com/home', $this->import['cookies']);
    241             if (! stristr($response['body'], 'signed in as') ) $this->login_form(__('Login failed. Please re-enter your username and password.'));
    242             $blogsary = array();
    243             preg_match_all('#posts\.g\?blogID=(\d+)">([^<]+)</a>#U', $response['body'], $blogsary);
    244             if ( ! count( $blogsary[1] < 1 ) )
    245                 wp_die(__('No blogs found for this user.'));
    246             $this->import['blogs'] = array();
    247             $template = '<MainPage><br /><br /><br /><p>'.__('Are you looking for %title%? It is temporarily out of service. Please try again in a few minutes. Meanwhile, discover <a href="http://wordpress.org/">a better blogging tool</a>.').'</p><BloggerArchives><a class="archive" href="<$BlogArchiveURL$>"><$BlogArchiveName$></a><br /></BloggerArchives></MainPage><ArchivePage><Blogger><wordpresspost><$BlogItemDateTime$>|W|P|<$BlogItemAuthorNickname$>|W|P|<$BlogItemBody$>|W|P|<$BlogItemNumber$>|W|P|<$BlogItemTitle$>|W|P|<$BlogItemAuthorEmail$><BlogItemCommentsEnabled><BlogItemComments><wordpresscomment><$BlogCommentDateTime$>|W|P|<$BlogCommentAuthor$>|W|P|<$BlogCommentBody$></BlogItemComments></BlogItemCommentsEnabled></Blogger></ArchivePage>';
    248             foreach ( $blogsary[1] as $key => $id ) {
    249                 // Define the required Blogger options.
    250                 $blog_opts = array(
    251                     'blog-options-basic' => false,
    252                     'blog-options-archiving' => array('archiveFrequency' => 'm'),
    253                     'blog-publishing' => array('publishMode'=>'0', 'blogID' => "$id", 'subdomain' => mt_rand().mt_rand(), 'pingWeblogs' => 'false'),
    254                     'blog-formatting' => array('timeStampFormat' => '0', 'encoding'=>'UTF-8', 'convertLineBreaks'=>'false', 'floatAlignment'=>'false'),
    255                     'blog-comments' => array('commentsTimeStampFormat' => '0'),
    256                     'template-edit' => array( 'templateText' =>  str_replace('%title%', trim($blogsary[2][$key]), $template) )
    257                 );
    258 
    259                 // Build the blog options array template
    260                 foreach ($blog_opts as $blog_opt => $modify)
    261                     $new_opts["$blog_opt"] = array('backup'=>false, 'modify' => $modify, 'error'=>false);
    262 
    263                 $this->import['blogs']["$id"] = array(
    264                     'id' => $id,
    265                     'title' => trim($blogsary[2][$key]),
    266                     'options' => $new_opts,
    267                     'url' => false,
    268                     'publish_cookies' => false,
    269                     'published' => false,
    270                     'archives' => false,
    271                     'lump_authors' => false,
    272                     'newusers' => array(),
    273                     'nextstep' => 2
    274                 );
    275             }
    276             update_option('import-blogger', $this->import);
    277             wp_redirect("admin.php?import=blogger&noheader=true&step=1");
    278         }
    279         die();
    280     }
    281 
    282     // Step 1: Select one of the blogs belonging to the user logged in.
    283     function select_blog() {
    284         if ( is_array($this->import['blogs']) ) {
    285             $this->show_blogs();
    286             die();
    287         } else {
    288             $this->restart();
    289         }
    290     }
    291 
    292     // Step 2: Backup the Blogger options pages, updating some of them.
    293     function backup_settings() {
    294         $output.= '<h1>'.__('Backing up Blogger options')."</h1>\n";
    295         $form = false;
    296         foreach ($this->import['blogs'][$_GET['blog']]['options'] as $blog_opt => $optary) {
    297             if ( $blog_opt == $_GET['form'] ) {
    298                 // Save the posted form data
    299                 $this->import['blogs'][$_GET['blog']]['options']["$blog_opt"]['backup'] = $_POST;
    300                 update_option('import-blogger',$this->import);
    301 
    302                 // Post the modified form data to Blogger
    303                 if ( $optary['modify'] ) {
    304                     $posturl = "http://www.blogger.com/{$blog_opt}.do";
    305                     $headers = array_merge($this->import['blogs'][$_GET['blog']]['options']["$blog_opt"]['cookies'], $this->import['cookies']);
    306                     if ( 'blog-publishing' == $blog_opt ) {
    307                         if ( $_POST['publishMode'] > 0 ) {
    308                             $response = $this->get_blogger("http://www.blogger.com/blog-publishing.g?blogID={$_GET['blog']}&publishMode=0", $headers);
    309                             if ( $response['code'] >= 400 )
    310                                 wp_die('<h2>'.__('Failed attempt to change publish mode from FTP to BlogSpot.').'</h2><pre>' . addslashes(print_r($headers, 1)) . addslashes(print_r($response, 1)) . '</pre>');
    311                             $this->import['blogs'][$_GET['blog']]['url'] = 'http://' . $optary['modify']['subdomain'] . '.blogspot.com/';
    312                             sleep(2);
    313                         } else {
    314                             $this->import['blogs'][$_GET['blog']]['url'] = 'http://' . $_POST['subdomain'] . '.blogspot.com/';
    315                             update_option('import-blogger', $this->import);
    316                             $output .= "<del><p>$blog_opt</p></del>\n";
    317                             continue;
    318                         }
    319                         $paramary = $optary['modify'];
    320                     } else {
    321                         $paramary = array_merge($_POST, $optary['modify']);
    322                     }
    323                     $response = $this->post_blogger($posturl, $headers, $paramary);
    324                     if ( $response['code'] >= 400 || strstr($response['body'], 'There are errors on this form') )
    325                         wp_die('<p>'.__('Error on form submission. Retry or reset the importer.').'</p>' . addslashes(print_r($response, 1)));
    326                 }
    327                 $output .= "<del><p>$blog_opt</p></del>\n";
    328             } elseif ( is_array($this->import['blogs'][$_GET['blog']]['options']["$blog_opt"]['backup']) ) {
    329                 // This option set has already been backed up.
    330                 $output .= "<del><p>$blog_opt</p></del>\n";
    331             } elseif ( ! $form ) {
    332                 // This option page needs to be downloaded and given to the browser for submission back to this script.
    333                 $response = $this->get_blogger("http://www.blogger.com/{$blog_opt}.g?blogID={$_GET['blog']}", $this->import['cookies']);
    334                 $this->import['blogs'][$_GET['blog']]['options']["$blog_opt"]['cookies'] = $response['cookies'];
    335                 update_option('import-blogger',$this->import);
    336                 $body = $response['body'];
    337                 $body = preg_replace("|\<!DOCTYPE.*\<body[^>]*>|ms","",$body);
    338                 $body = preg_replace("|/?{$blog_opt}.do|","admin.php?import=blogger&amp;noheader=true&amp;step=2&amp;blog={$_GET['blog']}&amp;form={$blog_opt}",$body);
    339                 $body = str_replace("name='submit'","name='supermit'",$body);
    340                 $body = str_replace('name="submit"','name="supermit"',$body);
    341                 $body = str_replace('</body>','',str_replace('</html>','',$body));
    342                 $form = "<div style='height:0px;width:0px;overflow:hidden;'>";
    343                 $form.= $body;
    344                 $form.= "</div><script type='text/javascript'>forms=document.getElementsByTagName('form');for(i=0;i<forms.length;i++){if(forms[i].action.search('{$blog_opt}')){forms[i].submit();break;}}</script>";
    345                 $output.= '<p>'.sprintf(__('<strong>%s</strong> in progress, please wait...'), $blog_opt)."</p>\n";
    346             } else {
    347                 $output.= "<p>$blog_opt</p>\n";
    348             }
    349         }
    350         if ( $form )
    351             die($output . $form);
    352 
    353         $this->set_next_step(4);
    354         $this->do_next_step();
    355     }
    356 
    357     // Step 3: Cancelled :-)
    358 
    359     // Step 4: Publish with the new template and settings.
    360     function publish_blog() {
    361         $this->publish_blogger(5, __('Publishing with new template and options'));
    362     }
    363 
    364     // Step 5: Get the archive URLs from the new blog.
    365     function get_archive_urls() {
    366         $bloghtml = $this->get_blogger($this->import['blogs'][$_GET['blog']]['url']);
    367         if (! strstr($bloghtml['body'], '<a class="archive"') )
    368             wp_die(__('Your Blogger blog did not take the new template or did not respond.'));
    369         preg_match_all('#<a class="archive" href="([^"]*)"#', $bloghtml['body'], $archives);
    370         foreach ($archives[1] as $archive) {
    371             $this->import['blogs'][$_GET['blog']]['archives'][$archive] = false;
    372         }
    373         $this->set_next_step(6);
    374         $this->do_next_step();
    375     }
    376 
    377     // Step 6: Get each monthly archive, import it, mark it done.
    378     function get_archive() {
    379         global $wpdb;
    380         $output = '<h2>'.__('Importing Blogger archives into WordPress').'</h2>';
    381         $did_one = false;
    382         $post_array = $posts = array();
    383         foreach ( $this->import['blogs'][$_GET['blog']]['archives'] as $url => $status ) {
    384             $archivename = substr(basename($url),0,7);
    385             if ( $status || $did_one ) {
    386                 $foo = 'bar';
    387                 // Do nothing.
    388             } else {
    389                 // Import the selected month
    390                 $postcount = 0;
    391                 $skippedpostcount = 0;
    392                 $commentcount = 0;
    393                 $skippedcommentcount = 0;
    394                 $status = __('in progress...');
    395                 $this->import['blogs'][$_GET['blog']]['archives']["$url"] = $status;
    396                 update_option('import-blogger', $import);
    397                 $archive = $this->get_blogger($url);
    398                 if ( $archive['code'] > 200 )
    399                     continue;
    400                 $posts = explode('<wordpresspost>', $archive['body']);
    401                 for ($i = 1; $i < count($posts); $i = $i + 1) {
    402                     $postparts = explode('<wordpresscomment>', $posts[$i]);
    403                     $postinfo = explode('|W|P|', $postparts[0]);
    404                     $post_date = $postinfo[0];
    405                     $post_content = $postinfo[2];
    406                     // Don't try to re-use the original numbers
    407                     // because the new, longer numbers are too
    408                     // big to handle as ints.
    409                     //$post_number = $postinfo[3];
    410                     $post_title = ( $postinfo[4] != '' ) ? $postinfo[4] : $postinfo[3];
    411                     $post_author_name = $wpdb->escape(trim($postinfo[1]));
    412                     $post_author_email = $postinfo[5] ? $postinfo[5] : 'user@wordpress.org';
    413 
    414                     if ( $this->lump_authors ) {
    415                         // Ignore Blogger authors. Use the current user_ID for all posts imported.
    416                         $post_author = $GLOBALS['user_ID'];
    417                     } else {
    418                         // Add a user for each new author encountered.
    419                         if (! username_exists($post_author_name) ) {
    420                             $user_login = $wpdb->escape($post_author_name);
    421                             $user_email = $wpdb->escape($post_author_email);
    422                             $user_password = substr(md5(uniqid(microtime())), 0, 6);
    423                             $result = wp_create_user( $user_login, $user_password, $user_email );
    424                             $status.= sprintf(__('Registered user <strong>%s</strong>.'), $user_login);
    425                             $this->import['blogs'][$_GET['blog']]['newusers'][] = $user_login;
    426                         }
    427                         $userdata = get_userdatabylogin( $post_author_name );
    428                         $post_author = $userdata->ID;
    429                     }
    430                     $post_date = explode(' ', $post_date);
    431                     $post_date_Ymd = explode('/', $post_date[0]);
    432                     $postyear = $post_date_Ymd[2];
    433                     $postmonth = zeroise($post_date_Ymd[0], 2);
    434                     $postday = zeroise($post_date_Ymd[1], 2);
    435                     $post_date_His = explode(':', $post_date[1]);
    436                     $posthour = zeroise($post_date_His[0], 2);
    437                     $postminute = zeroise($post_date_His[1], 2);
    438                     $postsecond = zeroise($post_date_His[2], 2);
    439 
    440                     if (($post_date[2] == 'PM') && ($posthour != '12'))
    441                         $posthour = $posthour + 12;
    442                     else if (($post_date[2] == 'AM') && ($posthour == '12'))
    443                         $posthour = '00';
    444 
    445                     $post_date = "$postyear-$postmonth-$postday $posthour:$postminute:$postsecond";
    446 
    447                     $post_content = addslashes($post_content);
    448                     $post_content = str_replace(array('<br>','<BR>','<br/>','<BR/>','<br />','<BR />'), "\n", $post_content); // the XHTML touch... ;)
    449 
    450                     $post_title = addslashes($post_title);
    451 
    452                     $post_status = 'publish';
    453 
    454                     if ( $ID = post_exists($post_title, '', $post_date) ) {
    455                         $post_array[$i]['ID'] = $ID;
    456                         $skippedpostcount++;
    457                     } else {
    458                         $post_array[$i]['post'] = compact('post_author', 'post_content', 'post_title', 'post_category', 'post_author', 'post_date', 'post_status');
    459                         $post_array[$i]['comments'] = false;
    460                     }
    461 
    462                     // Import any comments attached to this post.
    463                     if ($postparts[1]) :
    464                     for ($j = 1; $j < count($postparts); $j = $j + 1) {
    465                         $commentinfo = explode('|W|P|', $postparts[$j]);
    466                         $comment_date = explode(' ', $commentinfo[0]);
    467                         $comment_date_Ymd = explode('/', $comment_date[0]);
    468                         $commentyear = $comment_date_Ymd[2];
    469                         $commentmonth = zeroise($comment_date_Ymd[0], 2);
    470                         $commentday = zeroise($comment_date_Ymd[1], 2);
    471                         $comment_date_His = explode(':', $comment_date[1]);
    472                         $commenthour = zeroise($comment_date_His[0], 2);
    473                         $commentminute = zeroise($comment_date_His[1], 2);
    474                         $commentsecond = '00';
    475                         if (($comment_date[2] == 'PM') && ($commenthour != '12'))
    476                             $commenthour = $commenthour + 12;
    477                         else if (($comment_date[2] == 'AM') && ($commenthour == '12'))
    478                             $commenthour = '00';
    479                         $comment_date = "$commentyear-$commentmonth-$commentday $commenthour:$commentminute:$commentsecond";
    480                         $comment_author = addslashes(strip_tags($commentinfo[1]));
    481                         if ( strpos($commentinfo[1], 'a href') ) {
    482                             $comment_author_parts = explode('&quot;', htmlentities($commentinfo[1]));
    483                             $comment_author_url = $comment_author_parts[1];
    484                         } else $comment_author_url = '';
    485                         $comment_content = $commentinfo[2];
    486                         $comment_content = str_replace(array('<br>','<BR>','<br/>','<BR/>','<br />','<BR />'), "\n", $comment_content);
    487                         $comment_approved = 1;
    488                         if ( comment_exists($comment_author, $comment_date) ) {
    489                             $skippedcommentcount++;
    490                         } else {
    491                             $comment = compact('comment_author', 'comment_author_url', 'comment_date', 'comment_content', 'comment_approved');
    492                             $post_array[$i]['comments'][$j] = wp_filter_comment($comment);
    493                         }
    494                         $commentcount++;
    495                     }
    496                     endif;
    497                     $postcount++;
    498                 }
    499                 if ( count($post_array) ) {
    500                     krsort($post_array);
    501                     foreach($post_array as $post) {
    502                         if ( ! $comment_post_ID = $post['ID'] )
    503                             $comment_post_ID = wp_insert_post($post['post']);
    504                         if ( $post['comments'] ) {
    505                             foreach ( $post['comments'] as $comment ) {
    506                                 $comment['comment_post_ID'] = $comment_post_ID;
    507                                 wp_insert_comment($comment);
    508                             }
    509                         }
    510                     }
    511                 }
    512                 $status = sprintf(__('%s post(s) parsed, %s skipped...'), $postcount,  $skippedpostcount).' '.
    513                     sprintf(__('%s comment(s) parsed, %s skipped...'), $commentcount, $skippedcommentcount).' '.
    514                     ' <strong>'.__('Done').'</strong>';
    515                 $import = $this->import;
    516                 $import['blogs'][$_GET['blog']]['archives']["$url"] = $status;
    517                 update_option('import-blogger', $import);
    518                 $did_one = true;
    519             }
    520             $output.= "<p>$archivename $status</p>\n";
    521         }
    522         if ( ! $did_one )
    523             $this->set_next_step(7);
    524         die( $this->refresher(1000) . $output );
    525     }
    526 
    527     // Step 7: Restore the backed-up settings to Blogger
    528     function restore_settings() {
    529         $output = '<h1>'.__('Restoring your Blogger options')."</h1>\n";
    530         $did_one = false;
    531         // Restore options in reverse order.
    532         if ( ! $this->import['reversed'] ) {
    533             $this->import['blogs'][$_GET['blog']]['options'] = array_reverse($this->import['blogs'][$_GET['blog']]['options'], true);
    534             $this->import['reversed'] = true;
    535             update_option('import-blogger', $this->import);
    536         }
    537         foreach ( $this->import['blogs'][$_GET['blog']]['options'] as $blog_opt => $optary ) {
    538             if ( $did_one ) {
    539                 $output .= "<p>$blog_opt</p>\n";
    540             } elseif ( $optary['restored'] || ! $optary['modify'] ) {
    541                 $output .= "<p><del>$blog_opt</del></p>\n";
    542             } else {
    543                 $posturl = "http://www.blogger.com/{$blog_opt}.do";
    544                 $headers = array_merge($this->import['blogs'][$_GET['blog']]['options']["$blog_opt"]['cookies'], $this->import['cookies']);
    545                 if ( 'blog-publishing' == $blog_opt) {
    546                     if ( $optary['backup']['publishMode'] > 0 ) {
    547                         $response = $this->get_blogger("http://www.blogger.com/blog-publishing.g?blogID={$_GET['blog']}&publishMode={$optary['backup']['publishMode']}", $headers);
    548                         sleep(2);
    549                         if ( $response['code'] >= 400 )
    550                             wp_die('<h1>'.__('Error restoring publishMode').'</h1><p>'.__('Please tell the devs.').'</p>' . addslashes(print_r($response, 1)) );
    551                     }
    552                 }
    553                 if ( $optary['backup'] != $optary['modify'] ) {
    554                     $response = $this->post_blogger($posturl, $headers, $optary['backup']);
    555                     if ( $response['code'] >= 400 || strstr($response['body'], 'There are errors on this form') ) {
    556                         $this->import['blogs'][$_GET['blog']]['options']["$blog_opt"]['error'] = true;
    557                         update_option('import-blogger', $this->import);
    558                         $output .= sprintf(__('%s failed. Trying again.'), "<p><strong>$blog_opt</strong> ").'</p>';
    559                     } else {
    560                         $this->import['blogs'][$_GET['blog']]['options']["$blog_opt"]['restored'] = true;
    561                         update_option('import-blogger', $this->import);
    562                         $output .= sprintf(__('%s restored.'), "<p><strong>$blog_opt</strong> ").'</p>';
    563                     }
    564                 }
    565                 $did_one = true;
    566             }
    567         }
    568 
    569         if ( $did_one ) {
    570             die( $this->refresher(1000) . $output );
    571         } elseif ( $this->import['blogs'][$_GET['blog']]['options']['blog-publishing']['backup']['publishMode'] > 0 ) {
    572             $this->set_next_step(9);
    573         } else {
    574             $this->set_next_step(8);
    575         }
    576 
    577         $this->do_next_step();
    578     }
    579 
    580     // Step 8: Republish, all back to normal
    581     function republish_blog() {
    582         $this->publish_blogger(9, __('Publishing with original template and options'));
    583     }
    584 
    585744    // Step 9: Congratulate the user
    586745    function congrats() {
     746        $blog = (int) $_GET['blog'];
    587747        echo '<h1>'.__('Congratulations!').'</h1><p>'.__('Now that you have imported your Blogger blog into WordPress, what are you going to do? Here are some suggestions:').'</p><ul><li>'.__('That was hard work! Take a break.').'</li>';
    588748        if ( count($this->import['blogs']) > 1 )
    589749            echo '<li>'.__('In case you haven\'t done it already, you can import the posts from your other blogs:'). $this->show_blogs() . '</li>';
    590         if ( $n = count($this->import['blogs'][$_GET['blog']]['newusers']) )
     750        if ( $n = count($this->import['blogs'][$blog]['newusers']) )
    591751            echo '<li>'.sprintf(__('Go to <a href="%s" target="%s">Authors &amp; Users</a>, where you can modify the new user(s) or delete them. If you want to make all of the imported posts yours, you will be given that option when you delete the new authors.'), 'users.php', '_parent').'</li>';
    592         echo '<li>'.__('For security, click the link below to reset this importer. That will clear your Blogger credentials and options from the database.').'</li>';
     752        echo '<li>'.__('For security, click the link below to reset this importer.').'</li>';
    593753        echo '</ul>';
    594754    }
     
    596756    // Figures out what to do, then does it.
    597757    function start() {
    598         if ( $_GET['restart'] == 'true' ) {
     758        if ( isset($_POST['restart']) )
    599759            $this->restart();
    600         }
    601 
    602         if ( isset($_GET['noheader']) ) {
    603             header('Content-Type: text/html; charset=utf-8');
    604 
    605             $this->import = get_option('import-blogger');
    606 
    607             if ( false === $this->import ) {
    608                 $step = 0;
    609             } elseif ( isset($_GET['step']) ) {
    610                 $step = (int) $_GET['step'];
    611             } elseif ( isset($_GET['blog']) && isset($this->import['blogs'][$_GET['blog']]['nextstep']) ) {
    612                 $step = $this->import['blogs'][$_GET['blog']]['nextstep'];
    613             } elseif ( is_array($this->import['blogs']) ) {
    614                 $step = 1;
     760
     761        $options = get_option('blogger_importer');
     762
     763        if ( is_array($options) )
     764            foreach ( $options as $key => $value )
     765                $this->$key = $value;
     766
     767        if ( isset( $_REQUEST['blog'] ) ) {
     768            $blog = is_array($_REQUEST['blog']) ? array_shift( array_keys( $_REQUEST['blog'] ) ) : $_REQUEST['blog'];
     769            $blog = (int) $blog;
     770            $this->import_blog( $blog );
     771        } elseif ( isset($_GET['token']) )
     772            $this->auth();
     773        elseif ( $this->token && $this->token_is_valid() )
     774            $this->show_blogs();
     775        else
     776            $this->greet();
     777
     778        $saved = $this->save_vars();
     779
     780        if ( $saved && !isset($_GET['noheader']) ) {
     781            $restart = __('Restart');
     782            $message = __('We have saved some information about your Blogger account in your WordPress database. Clearing this information will allow you to start over. Restarting will not affect any posts you have already imported. If you attempt to re-import a blog, duplicate posts and comments will be skipped.');
     783            $submit = __('Clear account information');
     784            echo "<div class='wrap'><h2>$restart</h2><p>$message</p><form method='post' action='?import=blogger&noheader=true'><p class='submit' style='text-align:left;'><input type='submit' value='$submit' name='restart' /></p></form></div>";
     785        }
     786    }
     787
     788    function save_vars() {
     789        $vars = get_object_vars($this);
     790        update_option( 'blogger_importer', $vars );
     791
     792        return !empty($vars);
     793    }
     794
     795    function admin_head() {
     796?>
     797<style type="text/css">
     798td { text-align: center; line-height: 2em;}
     799thead td { font-weight: bold; }
     800.bar {
     801    width: 200px;
     802    text-align: left;
     803    line-height: 2em;
     804    padding: 0px;
     805}
     806.ind {
     807    position: absolute;
     808    background-color: #83B4D8;
     809    width: 1px;
     810    z-index: 9;
     811}
     812.stat {
     813    z-index: 10;
     814    position: relative;
     815    text-align: center;
     816}
     817.submit {
     818    text-align: center !important;
     819}
     820</style>
     821<?php
     822    }
     823
     824    function Blogger_Import() {
     825        global $importer_started;
     826        $importer_started = time();
     827        if ( isset( $_GET['import'] ) && $_GET['import'] == 'blogger' ) {
     828            wp_enqueue_script('jquery');
     829            add_action('admin_head', array(&$this, 'admin_head'));
     830        }
     831    }
     832}
     833
     834$blogger_import = new Blogger_Import();
     835
     836register_importer('blogger', __('Blogger'), __('Import posts, comments, and users from a Blogger blog'), array ($blogger_import, 'start'));
     837
     838class AtomEntry {
     839    var $links = array();
     840    var $categories = array();
     841}
     842
     843class AtomParser {
     844
     845    var $ATOM_CONTENT_ELEMENTS = array('content','summary','title','subtitle','rights');
     846    var $ATOM_SIMPLE_ELEMENTS = array('id','updated','published','draft','author');
     847
     848    var $depth = 0;
     849    var $indent = 2;
     850    var $in_content;
     851    var $ns_contexts = array();
     852    var $ns_decls = array();
     853    var $is_xhtml = false;
     854    var $skipped_div = false;
     855
     856    var $entry;
     857
     858    function AtomParser() {
     859
     860        $this->entry = new AtomEntry();
     861        $this->map_attrs_func = create_function('$k,$v', 'return "$k=\"$v\"";');
     862        $this->map_xmlns_func = create_function('$p,$n', '$xd = "xmlns"; if(strlen($n[0])>0) $xd .= ":{$n[0]}"; return "{$xd}=\"{$n[1]}\"";');
     863    }
     864
     865    function parse($xml) {
     866
     867        global $app_logging;
     868        array_unshift($this->ns_contexts, array());
     869
     870        $parser = xml_parser_create_ns();
     871        xml_set_object($parser, $this);
     872        xml_set_element_handler($parser, "start_element", "end_element");
     873        xml_parser_set_option($parser,XML_OPTION_CASE_FOLDING,0);
     874        xml_parser_set_option($parser,XML_OPTION_SKIP_WHITE,0);
     875        xml_set_character_data_handler($parser, "cdata");
     876        xml_set_default_handler($parser, "_default");
     877        xml_set_start_namespace_decl_handler($parser, "start_ns");
     878        xml_set_end_namespace_decl_handler($parser, "end_ns");
     879
     880        $contents = "";
     881
     882        xml_parse($parser, $xml);
     883
     884        xml_parser_free($parser);
     885
     886        return true;
     887    }
     888
     889    function start_element($parser, $name, $attrs) {
     890
     891        $tag = array_pop(split(":", $name));
     892
     893        array_unshift($this->ns_contexts, $this->ns_decls);
     894
     895        $this->depth++;
     896
     897        if(!empty($this->in_content)) {
     898            $attrs_prefix = array();
     899
     900            // resolve prefixes for attributes
     901            foreach($attrs as $key => $value) {
     902                $attrs_prefix[$this->ns_to_prefix($key)] = $this->xml_escape($value);
     903            }
     904            $attrs_str = join(' ', array_map($this->map_attrs_func, array_keys($attrs_prefix), array_values($attrs_prefix)));
     905            if(strlen($attrs_str) > 0) {
     906                $attrs_str = " " . $attrs_str;
     907            }
     908
     909            $xmlns_str = join(' ', array_map($this->map_xmlns_func, array_keys($this->ns_contexts[0]), array_values($this->ns_contexts[0])));
     910            if(strlen($xmlns_str) > 0) {
     911                $xmlns_str = " " . $xmlns_str;
     912            }
     913
     914            // handle self-closing tags (case: a new child found right-away, no text node)
     915            if(count($this->in_content) == 2) {
     916                array_push($this->in_content, ">");
     917            }
     918         
     919            array_push($this->in_content, "<". $this->ns_to_prefix($name) ."{$xmlns_str}{$attrs_str}");
     920        } else if(in_array($tag, $this->ATOM_CONTENT_ELEMENTS) || in_array($tag, $this->ATOM_SIMPLE_ELEMENTS)) {
     921            $this->in_content = array();
     922            $this->is_xhtml = $attrs['type'] == 'xhtml';
     923            array_push($this->in_content, array($tag,$this->depth));
     924        } else if($tag == 'link') {
     925            array_push($this->entry->links, $attrs);
     926        } else if($tag == 'category') {
     927            array_push($this->entry->categories, $attrs['term']);
     928        }
     929
     930        $this->ns_decls = array();
     931    }
     932
     933    function end_element($parser, $name) {
     934
     935        $tag = array_pop(split(":", $name));
     936
     937        if(!empty($this->in_content)) {
     938            if($this->in_content[0][0] == $tag &&
     939            $this->in_content[0][1] == $this->depth) {
     940                array_shift($this->in_content);
     941                if($this->is_xhtml) {
     942                    $this->in_content = array_slice($this->in_content, 2, count($this->in_content)-3);
     943                }
     944                $this->entry->$tag = join('',$this->in_content);
     945                $this->in_content = array();
    615946            } else {
    616                 $step = 0;
    617             }
    618 //echo "Step $step.";
    619 //wp_die('<pre>'.print_r($this->import,1).'</pre');
    620             switch ($step) {
    621                 case 0 :
    622                     $this->do_login();
    623                     break;
    624                 case 1 :
    625                     $this->select_blog();
    626                     break;
    627                 case 2 :
    628                     $this->backup_settings();
    629                     break;
    630                 case 3 :
    631                     $this->wait_for_blogger();
    632                     break;
    633                 case 4 :
    634                     $this->publish_blog();
    635                     break;
    636                 case 5 :
    637                     $this->get_archive_urls();
    638                     break;
    639                 case 6 :
    640                     $this->get_archive();
    641                     break;
    642                 case 7 :
    643                     $this->restore_settings();
    644                     break;
    645                 case 8 :
    646                     $this->republish_blog();
    647                     break;
    648                 case 9 :
    649                     $this->congrats();
    650                     break;
    651             }
    652             die;
    653 
    654         } else {
    655             $this->greet();
    656         }
    657     }
    658 
    659     function Blogger_Import() {
    660         // This space intentionally left blank.
     947                $endtag = $this->ns_to_prefix($name);
     948                if (strpos($this->in_content[count($this->in_content)-1], '<' . $endtag) !== false) {
     949                    array_push($this->in_content, "/>");
     950                } else {
     951                    array_push($this->in_content, "</$endtag>");
     952                }
     953            }
     954        }
     955
     956        array_shift($this->ns_contexts);
     957
     958        #print str_repeat(" ", $this->depth * $this->indent) . "end_element('$name')" ."\n";
     959
     960        $this->depth--;
     961    }
     962
     963    function start_ns($parser, $prefix, $uri) {
     964        #print str_repeat(" ", $this->depth * $this->indent) . "starting: " . $prefix . ":" . $uri . "\n";
     965        array_push($this->ns_decls, array($prefix,$uri));
     966    }
     967
     968    function end_ns($parser, $prefix) {
     969        #print str_repeat(" ", $this->depth * $this->indent) . "ending: #" . $prefix . "#\n";
     970    }
     971
     972    function cdata($parser, $data) {
     973        #print str_repeat(" ", $this->depth * $this->indent) . "data: #" . $data . "#\n";
     974        if(!empty($this->in_content)) {
     975            // handle self-closing tags (case: text node found, need to close element started)
     976            if (strpos($this->in_content[count($this->in_content)-1], '<') !== false) {
     977                array_push($this->in_content, ">");
     978            }
     979            array_push($this->in_content, $this->xml_escape($data));
     980        }
     981    }
     982
     983    function _default($parser, $data) {
     984        # when does this gets called?
     985    }
     986
     987
     988    function ns_to_prefix($qname) {
     989        $components = split(":", $qname);
     990        $name = array_pop($components);
     991
     992        if(!empty($components)) {
     993            $ns = join(":",$components);
     994            foreach($this->ns_contexts as $context) {
     995                foreach($context as $mapping) {
     996                    if($mapping[1] == $ns && strlen($mapping[0]) > 0) {
     997                        return "$mapping[0]:$name";
     998                    }
     999                }
     1000            }
     1001        }
     1002        return $name;
     1003    }
     1004
     1005    function xml_escape($string)
     1006    {
     1007             return str_replace(array('&','"',"'",'<','>'),
     1008                array('&amp;','&quot;','&apos;','&lt;','&gt;'),
     1009                $string );
    6611010    }
    6621011}
    6631012
    664 $blogger_import = new Blogger_Import();
    665 
    666 register_importer('blogger', __('Old Blogger'), __('Import posts, comments, and users from an Old Blogger blog'), array ($blogger_import, 'start'));
    667 
    6681013?>
Note: See TracChangeset for help on using the changeset viewer.