WordPress.org

Make WordPress Core


Ignore:
Timestamp:
02/20/2007 07:46:40 AM (15 years ago)
Author:
ryan
Message:

Update blogger importer.

File:
1 edited

Legend:

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

    r4679 r4896  
    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: www.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 = $this->blogs[$importing_blog]['posts'][$entry->old_post_permalink];
     550        $comment_author  = addslashes( $this->no_apos( strip_tags( $entry->author ) ) );
     551        $comment_date    = $this->convert_date( $entry->updated );
     552        $comment_content = addslashes( $this->no_apos( html_entity_decode( $entry->content ) ) );
     553
     554        // Clean up content
     555        $comment_content = preg_replace('|<(/?[A-Z]+)|e', "'<' . strtolower('$1')", $comment_content);
     556        $comment_content = str_replace('<br>', '<br />', $comment_content);
     557        $comment_content = str_replace('<hr>', '<hr />', $comment_content);
     558
     559        // Checks for duplicates
     560        if (
     561            isset( $this->blogs[$importing_blog]['comments'][$entry->old_permalink] ) ||
     562            comment_exists( $comment_author, $comment_date )
     563        ) {
     564            ++$this->blogs[$importing_blog]['comments_skipped'];
     565        } else {
     566            $comment = compact('comment_post_ID', 'comment_author', 'comment_date', 'comment_content');
     567
     568            $comment_id = wp_insert_comment($comment);
     569
     570            $this->blogs[$importing_blog]['comments'][$entry->old_permalink] = $comment_id;
     571
     572            ++$this->blogs[$importing_blog]['comments_done'];
     573        }
     574        $this->save_vars();
     575    }
     576
     577    function get_js_status($blog = false) {
     578        global $importing_blog;
     579        if ( $blog === false )
     580            $blog = $this->blogs[$importing_blog];
     581        else
     582            $blog = $this->blogs[$blog];
     583        $p1 = isset( $blog['posts_done'] ) ? (int) $blog['posts_done'] : 0;
     584        $p2 = isset( $blog['total_posts'] ) ? (int) $blog['total_posts'] : 0;
     585        $c1 = isset( $blog['comments_done'] ) ? (int) $blog['comments_done'] : 0;
     586        $c2 = isset( $blog['total_comments'] ) ? (int) $blog['total_comments'] : 0;
     587        return "{p1:$p1,p2:$p2,c1:$c1,c2:$c2}";
     588    }
     589
     590    function get_author_form($blog = false) {
     591        global $importing_blog, $wpdb, $current_user;
     592        if ( $blog === false )
     593            $blog = & $this->blogs[$importing_blog];
     594        else
     595            $blog = & $this->blogs[$blog];
     596
     597        if ( !isset( $blog['authors'] ) ) {
     598            $post_ids = array_values($blog['posts']);
     599            $authors = (array) $wpdb->get_col("SELECT DISTINCT meta_value FROM $wpdb->postmeta WHERE meta_key = 'blogger_author' AND post_id IN (" . join( ',', $post_ids ) . ")");
     600            $blog['authors'] = array_map(null, $authors, array_fill(0, count($authors), $current_user->ID));
     601            $this->save_vars();
     602        }
     603
     604        $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.');
     605        $heading = __('Author mapping');
     606        $blogtitle = "{$blog['title']} ({$blog['host']})";
     607        $mapthis = __('Blogger username');
     608        $tothis = __('WordPress login');
     609        $submit = js_escape( __('Save Changes &raquo;') );
     610
     611        foreach ( $blog['authors'] as $i => $author )
     612            $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>";
     613
     614        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>";
     615    }
     616
     617    function get_user_options($current) {
     618        global $wpdb, $importer_users;
     619        if ( ! isset( $importer_users ) )
     620            $importer_users = (array) get_users_of_blog();
     621
     622        foreach ( $importer_users as $user ) {
     623            $sel = ( $user->user_id == $current ) ? " selected='selected'" : '';
     624            $options .= "<option value='$user->user_id'$sel>$user->display_name</option>";
     625        }
     626       
     627        return $options;
     628    }
     629
     630    function save_authors() {
     631        global $importing_blog, $wpdb;
     632        $authors = (array) $_POST['authors'];
     633
     634        $host = $this->blogs[$importing_blog]['host'];
     635
     636        // Get an array of posts => authors
     637        $post_ids = (array) $wpdb->get_col("SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'blogger_blog' AND meta_value = '$host'");
     638        $post_ids = join( ',', $post_ids );
     639        $results = (array) $wpdb->get_results("SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = 'blogger_author' AND post_id IN ($post_ids)");
     640        foreach ( $results as $row )
     641            $authors_posts[$row->post_id] = $row->meta_value;
     642
     643        foreach ( $authors as $author => $user_id ) {
     644            $user_id = (int) $user_id;
     645
     646            // Skip authors that haven't been changed
     647            if ( $user_id == $this->blogs[$importing_blog]['authors'][$author][1] )
     648                continue;
     649
     650            // Get a list of the selected author's posts
     651            $post_ids = (array) array_keys( $authors_posts, $this->blogs[$importing_blog]['authors'][$author][0] );
     652            $post_ids = join( ',', $post_ids);
     653
     654            $wpdb->query("UPDATE $wpdb->posts SET post_author = $user_id WHERE id IN ($post_ids)");
     655            $this->blogs[$importing_blog]['authors'][$author][1] = $user_id;
     656        }
     657        $this->save_vars();
     658
     659        wp_redirect('edit.php');
     660    }
     661
     662    function _get_auth_sock() {
     663        // Connect to https://www.google.com
     664        if ( !$sock = @ fsockopen('ssl://www.google.com', 443, $errno, $errstr) ) {
     665            $this->uh_oh(
     666                __('Could not connect to https://www.google.com'),
     667                __('There was a problem opening a secure connection to Google. This is what went wrong:'),
     668                "$errstr ($errno)"
     669            );
     670            return false;
     671        }
     672        return $sock;
     673    }
     674
     675    function _get_blogger_sock($host = 'www.blogger.com') {
     676        if ( !$sock = @ fsockopen($host, 80, $errno, $errstr) ) {
     677            $this->uh_oh(
     678                sprintf( __('Could not connect to %s'), $host ),
     679                __('There was a problem opening a connection to Blogger. This is what went wrong:'),
     680                "$errstr ($errno)"
     681            );
     682            return false;
     683        }
     684        return $sock;
     685    }
     686
     687    function _txrx( $sock, $request ) {
     688        fwrite( $sock, $request );
     689        while ( ! feof( $sock ) )
     690            $response .= @ fread ( $sock, 8192 );
     691        fclose( $sock );
     692        return $response;
     693    }
     694
     695    function revoke($token) {
     696        $headers = array(
     697            "GET /accounts/AuthSubRevokeToken HTTP/1.0",
     698            "Authorization: AuthSub token=\"$token\""
     699        );
     700        $request = join( "\r\n", $headers ) . "\r\n\r\n";
     701        $sock = $this->_get_auth_sock( );
     702        if ( ! $sock ) return false;
     703        $this->_txrx( $sock, $request );
     704    }
     705
    27706    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";
     707        global $wpdb;
     708        $options = get_option( 'blogger_importer' );
     709       
     710        if ( isset( $options['token'] ) )
     711            $this->revoke( $options['token'] );
     712
     713        delete_option('blogger_importer');
     714        $wpdb->query("DELETE FROM $wpdb->postmeta WHERE meta_key = 'blogger_author'");
     715        wp_redirect('?import=blogger');
    39716    }
    40717
     
    61738
    62739        return array("code" => $response_code, "header" => $response_header_array, "cookies" => $cookie_array, "body" => $response_body);
    63     }
    64 
    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'));
    583740    }
    584741
     
    590747        if ( $n = count($this->import['blogs'][$_GET['blog']]['newusers']) )
    591748            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>';
     749        echo '<li>'.__('For security, click the link below to reset this importer.').'</li>';
    593750        echo '</ul>';
    594751    }
     
    596753    // Figures out what to do, then does it.
    597754    function start() {
    598         if ( $_GET['restart'] == 'true' ) {
     755        if ( isset($_POST['restart']) )
    599756            $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;
     757
     758        $options = get_option('blogger_importer');
     759
     760        if ( is_array($options) )
     761            foreach ( $options as $key => $value )
     762                $this->$key = $value;
     763
     764        if ( isset( $_REQUEST['blog'] ) ) {
     765            $blog = is_array($_REQUEST['blog']) ? array_shift( array_keys( $_REQUEST['blog'] ) ) : $_REQUEST['blog'];
     766            $this->import_blog( $blog );
     767        } elseif ( isset($_GET['token']) )
     768            $this->auth();
     769        elseif ( $this->token && $this->token_is_valid() )
     770            $this->show_blogs();
     771        else
     772            $this->greet();
     773
     774        $saved = $this->save_vars();
     775
     776        if ( $saved && !isset($_GET['noheader']) ) {
     777            $restart = __('Restart');
     778            $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.');
     779            $submit = __('Clear account information');
     780            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>";
     781        }
     782    }
     783
     784    function save_vars() {
     785        $vars = get_object_vars($this);
     786        update_option( 'blogger_importer', $vars );
     787
     788        return !empty($vars);
     789    }
     790
     791    function admin_head() {
     792?>
     793<style type="text/css">
     794td { text-align: center; line-height: 2em;}
     795thead td { font-weight: bold; }
     796.bar {
     797    width: 200px;
     798    text-align: left;
     799    line-height: 2em;
     800    padding: 0px;
     801}
     802.ind {
     803    position: absolute;
     804    background-color: #83B4D8;
     805    width: 1px;
     806    z-index: 9;
     807}
     808.stat {
     809    z-index: 10;
     810    position: relative;
     811    text-align: center;
     812}
     813.submit {
     814    text-align: center !important;
     815}
     816</style>
     817<?php
     818    }
     819
     820    function Blogger_Import() {
     821        global $importer_started;
     822        $importer_started = time();
     823        if ( isset( $_GET['import'] ) && $_GET['import'] == 'blogger' ) {
     824            wp_enqueue_script('jquery');
     825            add_action('admin_head', array(&$this, 'admin_head'));
     826        }
     827    }
     828}
     829
     830$blogger_import = new Blogger_Import();
     831
     832register_importer('blogger', __('Blogger'), __('Import posts, comments, and users from a Blogger blog'), array ($blogger_import, 'start'));
     833
     834class AtomEntry {
     835    var $links = array();
     836    var $categories = array();
     837}
     838
     839class AtomParser {
     840
     841    var $ATOM_CONTENT_ELEMENTS = array('content','summary','title','subtitle','rights');
     842    var $ATOM_SIMPLE_ELEMENTS = array('id','updated','published','draft','author');
     843
     844    var $depth = 0;
     845    var $indent = 2;
     846    var $in_content;
     847    var $ns_contexts = array();
     848    var $ns_decls = array();
     849    var $is_xhtml = false;
     850    var $skipped_div = false;
     851
     852    var $entry;
     853
     854    function AtomParser() {
     855
     856        $this->entry = new AtomEntry();
     857        $this->map_attrs_func = create_function('$k,$v', 'return "$k=\"$v\"";');
     858        $this->map_xmlns_func = create_function('$p,$n', '$xd = "xmlns"; if(strlen($n[0])>0) $xd .= ":{$n[0]}"; return "{$xd}=\"{$n[1]}\"";');
     859    }
     860
     861    function parse($xml) {
     862
     863        global $app_logging;
     864        array_unshift($this->ns_contexts, array());
     865
     866        $parser = xml_parser_create_ns();
     867        xml_set_object($parser, $this);
     868        xml_set_element_handler($parser, "start_element", "end_element");
     869        xml_parser_set_option($parser,XML_OPTION_CASE_FOLDING,0);
     870        xml_parser_set_option($parser,XML_OPTION_SKIP_WHITE,0);
     871        xml_set_character_data_handler($parser, "cdata");
     872        xml_set_default_handler($parser, "_default");
     873        xml_set_start_namespace_decl_handler($parser, "start_ns");
     874        xml_set_end_namespace_decl_handler($parser, "end_ns");
     875
     876        $contents = "";
     877
     878        xml_parse($parser, $xml);
     879
     880        xml_parser_free($parser);
     881
     882        return true;
     883    }
     884
     885    function start_element($parser, $name, $attrs) {
     886
     887        $tag = array_pop(split(":", $name));
     888
     889        array_unshift($this->ns_contexts, $this->ns_decls);
     890
     891        $this->depth++;
     892
     893        if(!empty($this->in_content)) {
     894            $attrs_prefix = array();
     895
     896            // resolve prefixes for attributes
     897            foreach($attrs as $key => $value) {
     898                $attrs_prefix[$this->ns_to_prefix($key)] = $this->xml_escape($value);
     899            }
     900            $attrs_str = join(' ', array_map($this->map_attrs_func, array_keys($attrs_prefix), array_values($attrs_prefix)));
     901            if(strlen($attrs_str) > 0) {
     902                $attrs_str = " " . $attrs_str;
     903            }
     904
     905            $xmlns_str = join(' ', array_map($this->map_xmlns_func, array_keys($this->ns_contexts[0]), array_values($this->ns_contexts[0])));
     906            if(strlen($xmlns_str) > 0) {
     907                $xmlns_str = " " . $xmlns_str;
     908            }
     909
     910            // handle self-closing tags (case: a new child found right-away, no text node)
     911            if(count($this->in_content) == 2) {
     912                array_push($this->in_content, ">");
     913            }
     914         
     915            array_push($this->in_content, "<". $this->ns_to_prefix($name) ."{$xmlns_str}{$attrs_str}");
     916        } else if(in_array($tag, $this->ATOM_CONTENT_ELEMENTS) || in_array($tag, $this->ATOM_SIMPLE_ELEMENTS)) {
     917            $this->in_content = array();
     918            $this->is_xhtml = $attrs['type'] == 'xhtml';
     919            array_push($this->in_content, array($tag,$this->depth));
     920        } else if($tag == 'link') {
     921            array_push($this->entry->links, $attrs);
     922        } else if($tag == 'category') {
     923            array_push($this->entry->categories, $attrs['term']);
     924        }
     925       
     926        $this->ns_decls = array();
     927    }
     928
     929    function end_element($parser, $name) {
     930
     931        $tag = array_pop(split(":", $name));
     932
     933        if(!empty($this->in_content)) {
     934            if($this->in_content[0][0] == $tag &&
     935            $this->in_content[0][1] == $this->depth) {
     936                array_shift($this->in_content);
     937                if($this->is_xhtml) {
     938                    $this->in_content = array_slice($this->in_content, 2, count($this->in_content)-3);
     939                }
     940                $this->entry->$tag = join('',$this->in_content);
     941                $this->in_content = array();
    615942            } 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.
     943                $endtag = $this->ns_to_prefix($name);
     944                if(strstr($this->in_content[count($this->in_content)-1], "<$endtag")) {
     945                    array_push($this->in_content, "/>");
     946                } else {
     947                    array_push($this->in_content, "</$endtag>");
     948                }
     949            }
     950        }
     951
     952        array_shift($this->ns_contexts);
     953       
     954        #print str_repeat(" ", $this->depth * $this->indent) . "end_element('$name')" ."\n";
     955
     956        $this->depth--;
     957    }
     958
     959    function start_ns($parser, $prefix, $uri) {
     960        #print str_repeat(" ", $this->depth * $this->indent) . "starting: " . $prefix . ":" . $uri . "\n";
     961        array_push($this->ns_decls, array($prefix,$uri));
     962    }
     963
     964    function end_ns($parser, $prefix) {
     965        #print str_repeat(" ", $this->depth * $this->indent) . "ending: #" . $prefix . "#\n";
     966    }
     967
     968    function cdata($parser, $data) {
     969        #print str_repeat(" ", $this->depth * $this->indent) . "data: #" . $data . "#\n";
     970        if(!empty($this->in_content)) {
     971            // handle self-closing tags (case: text node found, need to close element started)
     972            if(strstr($this->in_content[count($this->in_content)-1], "<")) {
     973                array_push($this->in_content, ">");
     974            }
     975            array_push($this->in_content, $this->xml_escape($data));
     976        }
     977    }
     978
     979    function _default($parser, $data) {
     980        # when does this gets called?
     981    }
     982
     983
     984    function ns_to_prefix($qname) {
     985        $components = split(":", $qname);
     986        $name = array_pop($components);
     987
     988        if(!empty($components)) {
     989            $ns = join(":",$components);
     990            foreach($this->ns_contexts as $context) {
     991                foreach($context as $mapping) {
     992                    if($mapping[1] == $ns && strlen($mapping[0]) > 0) {
     993                        return "$mapping[0]:$name";
     994                    }
     995                }
     996            }
     997        }
     998        return $name;
     999    }
     1000
     1001    function xml_escape($string)
     1002    {
     1003             return str_replace(array('&','"',"'",'<','>'),
     1004                array('&amp;','&quot;','&apos;','&lt;','&gt;'),
     1005                $string );
    6611006    }
    6621007}
    6631008
    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 
    6681009?>
Note: See TracChangeset for help on using the changeset viewer.