[ Index ]

PHP Cross Reference of Wordpress 2.7.1

title

Body

[close]

/wp-admin/import/ -> blogger.php (source)

   1  <?php
   2  /**
   3   * Blogger Importer
   4   *
   5   * @package WordPress
   6   * @subpackage Importer
   7   */
   8  
   9  /**
  10   * How many records per GData query
  11   *
  12   * @package WordPress
  13   * @subpackage Blogger_Import
  14   * @var int
  15   * @since unknown
  16   */
  17  define( 'MAX_RESULTS',        50 );
  18  
  19  /**
  20   * How many seconds to let the script run
  21   *
  22   * @package WordPress
  23   * @subpackage Blogger_Import
  24   * @var int
  25   * @since unknown
  26   */
  27  define( 'MAX_EXECUTION_TIME', 20 );
  28  
  29  /**
  30   * How many seconds between status bar updates
  31   *
  32   * @package WordPress
  33   * @subpackage Blogger_Import
  34   * @var int
  35   * @since unknown
  36   */
  37  define( 'STATUS_INTERVAL',     3 );
  38  
  39  /**
  40   * Blogger Importer class
  41   *
  42   * @since unknown
  43   */
  44  class Blogger_Import {
  45  
  46      // Shows the welcome screen and the magic auth link.
  47  	function greet() {
  48          $next_url = get_option('siteurl') . '/wp-admin/index.php?import=blogger&amp;noheader=true';
  49          $auth_url = "https://www.google.com/accounts/AuthSubRequest";
  50          $title = __('Import Blogger');
  51          $welcome = __('Howdy! This importer allows you to import posts and comments from your Blogger account into your WordPress blog.');
  52          $prereqs = __('To use this importer, you must have a Google account and an upgraded (New, was Beta) blog hosted on blogspot.com or a custom domain (not FTP).');
  53          $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.');
  54          $auth = __('Authorize');
  55  
  56          echo "
  57          <div class='wrap'>
  58          ".screen_icon()."
  59          <h2>$title</h2>
  60          <p>$welcome</p><p>$prereqs</p><p>$stepone</p>
  61              <form action='$auth_url' method='get'>
  62                  <p class='submit' style='text-align:left;'>
  63                      <input type='submit' class='button' value='$auth' />
  64                      <input type='hidden' name='scope' value='http://www.blogger.com/feeds/' />
  65                      <input type='hidden' name='session' value='1' />
  66                      <input type='hidden' name='secure' value='0' />
  67                      <input type='hidden' name='next' value='$next_url' />
  68                  </p>
  69              </form>
  70          </div>\n";
  71      }
  72  
  73  	function uh_oh($title, $message, $info) {
  74          echo "<div class='wrap'>";
  75          screen_icon();
  76          echo "<h2>$title</h2><p>$message</p><pre>$info</pre></div>";
  77      }
  78  
  79  	function auth() {
  80          // We have a single-use token that must be upgraded to a session token.
  81          $token = preg_replace( '/[^-_0-9a-zA-Z]/', '', $_GET['token'] );
  82          $headers = array(
  83              "GET /accounts/AuthSubSessionToken HTTP/1.0",
  84              "Authorization: AuthSub token=\"$token\""
  85          );
  86          $request = join( "\r\n", $headers ) . "\r\n\r\n";
  87          $sock = $this->_get_auth_sock( );
  88          if ( ! $sock ) return false;
  89          $response = $this->_txrx( $sock, $request );
  90          preg_match( '/token=([-_0-9a-z]+)/i', $response, $matches );
  91          if ( empty( $matches[1] ) ) {
  92              $this->uh_oh(
  93                  __( 'Authorization failed' ),
  94                  __( 'Something went wrong. If the problem persists, send this info to support:' ),
  95                  htmlspecialchars($response)
  96              );
  97              return false;
  98          }
  99          $this->token = $matches[1];
 100  
 101          wp_redirect( remove_query_arg( array( 'token', 'noheader' ) ) );
 102      }
 103  
 104  	function get_token_info() {
 105          $headers = array(
 106              "GET /accounts/AuthSubTokenInfo  HTTP/1.0",
 107              "Authorization: AuthSub token=\"$this->token\""
 108          );
 109          $request = join( "\r\n", $headers ) . "\r\n\r\n";
 110          $sock = $this->_get_auth_sock( );
 111          if ( ! $sock ) return;
 112          $response = $this->_txrx( $sock, $request );
 113          return $this->parse_response($response);
 114      }
 115  
 116  	function token_is_valid() {
 117          $info = $this->get_token_info();
 118  
 119          if ( $info['code'] == 200 )
 120              return true;
 121  
 122          return false;
 123      }
 124  
 125  	function show_blogs($iter = 0) {
 126          if ( empty($this->blogs) ) {
 127              $headers = array(
 128                  "GET /feeds/default/blogs HTTP/1.0",
 129                  "Host: www.blogger.com",
 130                  "Authorization: AuthSub token=\"$this->token\""
 131              );
 132              $request = join( "\r\n", $headers ) . "\r\n\r\n";
 133              $sock = $this->_get_blogger_sock( );
 134              if ( ! $sock ) return;
 135              $response = $this->_txrx( $sock, $request );
 136  
 137              // Quick and dirty XML mining.
 138              list( $headers, $xml ) = explode( "\r\n\r\n", $response );
 139              $p = xml_parser_create();
 140              xml_parse_into_struct($p, $xml, $vals, $index);
 141              xml_parser_free($p);
 142  
 143              $this->title = $vals[$index['TITLE'][0]]['value'];
 144  
 145              // Give it a few retries... this step often flakes out the first time.
 146              if ( empty( $index['ENTRY'] ) ) {
 147                  if ( $iter < 3 ) {
 148                      return $this->show_blogs($iter + 1);
 149                  } else {
 150                      $this->uh_oh(
 151                          __('Trouble signing in'),
 152                          __('We were not able to gain access to your account. Try starting over.'),
 153                          ''
 154                      );
 155                      return false;
 156                  }
 157              }
 158  
 159              foreach ( $index['ENTRY'] as $i ) {
 160                  $blog = array();
 161                  while ( ( $tag = $vals[$i] ) && ! ( $tag['tag'] == 'ENTRY' && $tag['type'] == 'close' ) ) {
 162                      if ( $tag['tag'] == 'TITLE' ) {
 163                          $blog['title'] = $tag['value'];
 164                      } elseif ( $tag['tag'] == 'SUMMARY' ) {
 165                          $blog['summary'] == $tag['value'];
 166                      } elseif ( $tag['tag'] == 'LINK' ) {
 167                          if ( $tag['attributes']['REL'] == 'alternate' && $tag['attributes']['TYPE'] == 'text/html' ) {
 168                              $parts = parse_url( $tag['attributes']['HREF'] );
 169                              $blog['host'] = $parts['host'];
 170                          } elseif ( $tag['attributes']['REL'] == 'edit' )
 171                              $blog['gateway'] = $tag['attributes']['HREF'];
 172                      }
 173                      ++$i;
 174                  }
 175                  if ( ! empty ( $blog ) ) {
 176                      $blog['total_posts'] = $this->get_total_results('posts', $blog['host']);
 177                      $blog['total_comments'] = $this->get_total_results('comments', $blog['host']);
 178                      $blog['mode'] = 'init';
 179                      $this->blogs[] = $blog;
 180                  }
 181              }
 182  
 183              if ( empty( $this->blogs ) ) {
 184                  $this->uh_oh(
 185                      __('No blogs found'),
 186                      __('We were able to log in but there were no blogs. Try a different account next time.'),
 187                      ''
 188                  );
 189                  return false;
 190              }
 191          }
 192  //echo '<pre>'.print_r($this,1).'</pre>';
 193          $start    = js_escape( __('Import') );
 194          $continue = js_escape( __('Continue') );
 195          $stop     = js_escape( __('Importing...') );
 196          $authors  = js_escape( __('Set Authors') );
 197          $loadauth = js_escape( __('Preparing author mapping form...') );
 198          $authhead = js_escape( __('Final Step: Author Mapping') );
 199          $nothing  = js_escape( __('Nothing was imported. Had you already imported this blog?') );
 200          $title    = __('Blogger Blogs');
 201          $name     = __('Blog Name');
 202          $url      = __('Blog URL');
 203          $action   = __('The Magic Button');
 204          $posts    = __('Posts');
 205          $comments = __('Comments');
 206          $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.');
 207  
 208          $interval = STATUS_INTERVAL * 1000;
 209  
 210          foreach ( $this->blogs as $i => $blog ) {
 211              if ( $blog['mode'] == 'init' )
 212                  $value = $start;
 213              elseif ( $blog['mode'] == 'posts' || $blog['mode'] == 'comments' )
 214                  $value = $continue;
 215              else
 216                  $value = $authors;
 217              $blogtitle = js_escape( $blog['title'] );
 218              $pdone = isset($blog['posts_done']) ? (int) $blog['posts_done'] : 0;
 219              $cdone = isset($blog['comments_done']) ? (int) $blog['comments_done'] : 0;
 220              $init .= "blogs[$i]=new blog($i,'$blogtitle','{$blog['mode']}'," . $this->get_js_status($i) . ');';
 221              $pstat = "<div class='ind' id='pind$i'>&nbsp;</div><div id='pstat$i' class='stat'>$pdone/{$blog['total_posts']}</div>";
 222              $cstat = "<div class='ind' id='cind$i'>&nbsp;</div><div id='cstat$i' class='stat'>$cdone/{$blog['total_comments']}</div>";
 223              $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' class='button' id='submit$i' value='$value' /><input type='hidden' name='blog' value='$i' /></td></tr>\n";
 224          }
 225  
 226          echo "<div class='wrap'><h2>$title</h2><noscript>$noscript</noscript><table cellpadding='5px'><thead><tr><td>$name</td><td>$url</td><td>$posts</td><td>$comments</td><td>$action</td></tr></thead>\n$rows</table></div>";
 227          echo "
 228          <script type='text/javascript'>
 229          /* <![CDATA[ */
 230              var strings = {cont:'$continue',stop:'$stop',stopping:'$stopping',authors:'$authors',nothing:'$nothing'};
 231              var blogs = {};
 232  			function blog(i, title, mode, status){
 233                  this.blog   = i;
 234                  this.mode   = mode;
 235                  this.title  = title;
 236                  this.status = status;
 237                  this.button = document.getElementById('submit'+this.blog);
 238              };
 239              blog.prototype = {
 240                  start: function() {
 241                      this.cont = true;
 242                      this.kick();
 243                      this.check();
 244                  },
 245                  kick: function() {
 246                      ++this.kicks;
 247                      var i = this.blog;
 248                      jQuery.post('admin.php?import=blogger&noheader=true',{blog:this.blog},function(text,result){blogs[i].kickd(text,result)});
 249                  },
 250                  check: function() {
 251                      ++this.checks;
 252                      var i = this.blog;
 253                      jQuery.post('admin.php?import=blogger&noheader=true&status=true',{blog:this.blog},function(text,result){blogs[i].checkd(text,result)});
 254                  },
 255                  kickd: function(text, result) {
 256                      if ( result == 'error' ) {
 257                          // TODO: exception handling
 258                          if ( this.cont )
 259                              setTimeout('blogs['+this.blog+'].kick()', 1000);
 260                      } else {
 261                          if ( text == 'done' ) {
 262                              this.stop();
 263                              this.done();
 264                          } else if ( text == 'nothing' ) {
 265                              this.stop();
 266                              this.nothing();
 267                          } else if ( text == 'continue' ) {
 268                              this.kick();
 269                          } else if ( this.mode = 'stopped' )
 270                              jQuery(this.button).attr('value', strings.cont);
 271                      }
 272                      --this.kicks;
 273                  },
 274                  checkd: function(text, result) {
 275                      if ( result == 'error' ) {
 276                          // TODO: exception handling
 277                      } else {
 278                          eval('this.status='+text);
 279                          jQuery('#pstat'+this.blog).empty().append(this.status.p1+'/'+this.status.p2);
 280                          jQuery('#cstat'+this.blog).empty().append(this.status.c1+'/'+this.status.c2);
 281                          this.update();
 282                          if ( this.cont || this.kicks > 0 )
 283                              setTimeout('blogs['+this.blog+'].check()', $interval);
 284                      }
 285                      --this.checks;
 286                  },
 287                  update: function() {
 288                      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');
 289                      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');
 290                  },
 291                  stop: function() {
 292                      this.cont = false;
 293                  },
 294                  done: function() {
 295                      this.mode = 'authors';
 296                      jQuery(this.button).attr('value', strings.authors);
 297                  },
 298                  nothing: function() {
 299                      this.mode = 'nothing';
 300                      jQuery(this.button).remove();
 301                      alert(strings.nothing);
 302                  },
 303                  getauthors: function() {
 304                      if ( jQuery('div.wrap').length > 1 )
 305                          jQuery('div.wrap').gt(0).remove();
 306                      jQuery('div.wrap').empty().append('<h2>$authhead</h2><h3>' + this.title + '</h3>');
 307                      jQuery('div.wrap').append('<p id=\"auth\">$loadauth</p>');
 308                      jQuery('p#auth').load('index.php?import=blogger&noheader=true&authors=1',{blog:this.blog});
 309                  },
 310                  init: function() {
 311                      this.update();
 312                      var i = this.blog;
 313                      jQuery(this.button).bind('click', function(){return blogs[i].click();});
 314                      this.kicks = 0;
 315                      this.checks = 0;
 316                  },
 317                  click: function() {
 318                      if ( this.mode == 'init' || this.mode == 'stopped' || this.mode == 'posts' || this.mode == 'comments' ) {
 319                          this.mode = 'started';
 320                          this.start();
 321                          jQuery(this.button).attr('value', strings.stop);
 322                      } else if ( this.mode == 'started' ) {
 323                          return false; // let it run...
 324                          this.mode = 'stopped';
 325                          this.stop();
 326                          if ( this.checks > 0 || this.kicks > 0 ) {
 327                              this.mode = 'stopping';
 328                              jQuery(this.button).attr('value', strings.stopping);
 329                          } else {
 330                              jQuery(this.button).attr('value', strings.cont);
 331                          }
 332                      } else if ( this.mode == 'authors' ) {
 333                          document.location = 'index.php?import=blogger&authors=1&blog='+this.blog;
 334                          //this.mode = 'authors2';
 335                          //this.getauthors();
 336                      }
 337                      return false;
 338                  }
 339              };
 340              $init
 341              jQuery.each(blogs, function(i, me){me.init();});
 342          /* ]]> */
 343          </script>\n";
 344      }
 345  
 346      // Handy function for stopping the script after a number of seconds.
 347  	function have_time() {
 348          global $importer_started;
 349          if ( time() - $importer_started > MAX_EXECUTION_TIME )
 350              die('continue');
 351          return true;
 352      }
 353  
 354  	function get_total_results($type, $host) {
 355          $headers = array(
 356              "GET /feeds/$type/default?max-results=1&start-index=2 HTTP/1.0",
 357              "Host: $host",
 358              "Authorization: AuthSub token=\"$this->token\""
 359          );
 360          $request = join( "\r\n", $headers ) . "\r\n\r\n";
 361          $sock = $this->_get_blogger_sock( $host );
 362          if ( ! $sock ) return;
 363          $response = $this->_txrx( $sock, $request );
 364          $response = $this->parse_response( $response );
 365          $parser = xml_parser_create();
 366          xml_parse_into_struct($parser, $response['body'], $struct, $index);
 367          xml_parser_free($parser);
 368          $total_results = $struct[$index['OPENSEARCH:TOTALRESULTS'][0]]['value'];
 369          return (int) $total_results;
 370      }
 371  
 372  	function import_blog($blogID) {
 373          global $importing_blog;
 374          $importing_blog = $blogID;
 375  
 376          if ( isset($_GET['authors']) )
 377              return print($this->get_author_form());
 378  
 379          header('Content-Type: text/plain');
 380  
 381          if ( isset($_GET['status']) )
 382              die($this->get_js_status());
 383  
 384          if ( isset($_GET['saveauthors']) )
 385              die($this->save_authors());
 386  
 387          $blog = $this->blogs[$blogID];
 388          $total_results = $this->get_total_results('posts', $blog['host']);
 389          $this->blogs[$importing_blog]['total_posts'] = $total_results;
 390  
 391          $start_index = $total_results - MAX_RESULTS + 1;
 392  
 393          if ( isset( $this->blogs[$importing_blog]['posts_start_index'] ) )
 394              $start_index = (int) $this->blogs[$importing_blog]['posts_start_index'];
 395          elseif ( $total_results > MAX_RESULTS )
 396              $start_index = $total_results - MAX_RESULTS + 1;
 397          else
 398              $start_index = 1;
 399  
 400          // This will be positive until we have finished importing posts
 401          if ( $start_index > 0 ) {
 402              // Grab all the posts
 403              $this->blogs[$importing_blog]['mode'] = 'posts';
 404              $query = "start-index=$start_index&max-results=" . MAX_RESULTS;
 405              do {
 406                  $index = $struct = $entries = array();
 407                  $headers = array(
 408                      "GET /feeds/posts/default?$query HTTP/1.0",
 409                      "Host: {$blog['host']}",
 410                      "Authorization: AuthSub token=\"$this->token\""
 411                  );
 412                  $request = join( "\r\n", $headers ) . "\r\n\r\n";
 413                  $sock = $this->_get_blogger_sock( $blog['host'] );
 414                  if ( ! $sock ) return; // TODO: Error handling
 415                  $response = $this->_txrx( $sock, $request );
 416  
 417                  $response = $this->parse_response( $response );
 418  
 419                  // Extract the entries and send for insertion
 420                  preg_match_all( '/<entry[^>]*>.*?<\/entry>/s', $response['body'], $matches );
 421                  if ( count( $matches[0] ) ) {
 422                      $entries = array_reverse($matches[0]);
 423                      foreach ( $entries as $entry ) {
 424                          $entry = "<feed>$entry</feed>";
 425                          $AtomParser = new AtomParser();
 426                          $AtomParser->parse( $entry );
 427                          $result = $this->import_post($AtomParser->entry);
 428                          if ( is_wp_error( $result ) )
 429                              return $result;
 430                          unset($AtomParser);
 431                      }
 432                  } else break;
 433  
 434                  // Get the 'previous' query string which we'll use on the next iteration
 435                  $query = '';
 436                  $links = preg_match_all('/<link([^>]*)>/', $response['body'], $matches);
 437                  if ( count( $matches[1] ) )
 438                      foreach ( $matches[1] as $match )
 439                          if ( preg_match('/rel=.previous./', $match) )
 440                              $query = html_entity_decode( preg_replace('/^.*href=[\'"].*\?(.+)[\'"].*$/', '$1', $match) );
 441  
 442                  if ( $query ) {
 443                      parse_str($query, $q);
 444                      $this->blogs[$importing_blog]['posts_start_index'] = (int) $q['start-index'];
 445                  } else
 446                      $this->blogs[$importing_blog]['posts_start_index'] = 0;
 447                  $this->save_vars();
 448              } while ( !empty( $query ) && $this->have_time() );
 449          }
 450  
 451          $total_results = $this->get_total_results( 'comments', $blog['host'] );
 452          $this->blogs[$importing_blog]['total_comments'] = $total_results;
 453  
 454          if ( isset( $this->blogs[$importing_blog]['comments_start_index'] ) )
 455              $start_index = (int) $this->blogs[$importing_blog]['comments_start_index'];
 456          elseif ( $total_results > MAX_RESULTS )
 457              $start_index = $total_results - MAX_RESULTS + 1;
 458          else
 459              $start_index = 1;
 460  
 461          if ( $start_index > 0 ) {
 462              // Grab all the comments
 463              $this->blogs[$importing_blog]['mode'] = 'comments';
 464              $query = "start-index=$start_index&max-results=" . MAX_RESULTS;
 465              do {
 466                  $index = $struct = $entries = array();
 467                  $headers = array(
 468                      "GET /feeds/comments/default?$query HTTP/1.0",
 469                      "Host: {$blog['host']}",
 470                      "Authorization: AuthSub token=\"$this->token\""
 471                  );
 472                  $request = join( "\r\n", $headers ) . "\r\n\r\n";
 473                  $sock = $this->_get_blogger_sock( $blog['host'] );
 474                  if ( ! $sock ) return; // TODO: Error handling
 475                  $response = $this->_txrx( $sock, $request );
 476  
 477                  $response = $this->parse_response( $response );
 478  
 479                  // Extract the comments and send for insertion
 480                  preg_match_all( '/<entry[^>]*>.*?<\/entry>/s', $response['body'], $matches );
 481                  if ( count( $matches[0] ) ) {
 482                      $entries = array_reverse( $matches[0] );
 483                      foreach ( $entries as $entry ) {
 484                          $entry = "<feed>$entry</feed>";
 485                          $AtomParser = new AtomParser();
 486                          $AtomParser->parse( $entry );
 487                          $this->import_comment($AtomParser->entry);
 488                          unset($AtomParser);
 489                      }
 490                  }
 491  
 492                  // Get the 'previous' query string which we'll use on the next iteration
 493                  $query = '';
 494                  $links = preg_match_all('/<link([^>]*)>/', $response['body'], $matches);
 495                  if ( count( $matches[1] ) )
 496                      foreach ( $matches[1] as $match )
 497                          if ( preg_match('/rel=.previous./', $match) )
 498                              $query = html_entity_decode( preg_replace('/^.*href=[\'"].*\?(.+)[\'"].*$/', '$1', $match) );
 499  
 500                  parse_str($query, $q);
 501  
 502                  $this->blogs[$importing_blog]['comments_start_index'] = (int) $q['start-index'];
 503                  $this->save_vars();
 504              } while ( !empty( $query ) && $this->have_time() );
 505          }
 506          $this->blogs[$importing_blog]['mode'] = 'authors';
 507          $this->save_vars();
 508          if ( !$this->blogs[$importing_blog]['posts_done'] && !$this->blogs[$importing_blog]['comments_done'] )
 509              die('nothing');
 510          do_action('import_done', 'blogger');
 511          die('done');
 512      }
 513  
 514  	function convert_date( $date ) {
 515          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);
 516          $offset = iso8601_timezone_to_offset( $date_bits[7] );
 517          $timestamp = gmmktime($date_bits[4], $date_bits[5], $date_bits[6], $date_bits[2], $date_bits[3], $date_bits[1]);
 518          $timestamp -= $offset; // Convert from Blogger local time to GMT
 519          $timestamp += get_option('gmt_offset') * 3600; // Convert from GMT to WP local time
 520          return gmdate('Y-m-d H:i:s', $timestamp);
 521      }
 522  
 523  	function no_apos( $string ) {
 524          return str_replace( '&apos;', "'", $string);
 525      }
 526  
 527  	function min_whitespace( $string ) {
 528          return preg_replace( '|\s+|', ' ', $string );
 529      }
 530  
 531  	function import_post( $entry ) {
 532          global $importing_blog;
 533  
 534          // The old permalink is all Blogger gives us to link comments to their posts.
 535          if ( isset( $entry->draft ) )
 536              $rel = 'self';
 537          else
 538              $rel = 'alternate';
 539          foreach ( $entry->links as $link ) {
 540              if ( $link['rel'] == $rel ) {
 541                  $parts = parse_url( $link['href'] );
 542                  $entry->old_permalink = $parts['path'];
 543                  break;
 544              }
 545          }
 546  
 547          $post_date    = $this->convert_date( $entry->published );
 548          $post_content = trim( addslashes( $this->no_apos( html_entity_decode( $entry->content ) ) ) );
 549          $post_title   = trim( addslashes( $this->no_apos( $this->min_whitespace( $entry->title ) ) ) );
 550          $post_status  = isset( $entry->draft ) ? 'draft' : 'publish';
 551  
 552          // Clean up content
 553          $post_content = preg_replace_callback('|<(/?[A-Z]+)|', create_function('$match', 'return "<" . strtolower($match[1]);'), $post_content);
 554          $post_content = str_replace('<br>', '<br />', $post_content);
 555          $post_content = str_replace('<hr>', '<hr />', $post_content);
 556  
 557          // Checks for duplicates
 558          if ( isset( $this->blogs[$importing_blog]['posts'][$entry->old_permalink] ) ) {
 559              ++$this->blogs[$importing_blog]['posts_skipped'];
 560          } elseif ( $post_id = post_exists( $post_title, $post_content, $post_date ) ) {
 561              $this->blogs[$importing_blog]['posts'][$entry->old_permalink] = $post_id;
 562              ++$this->blogs[$importing_blog]['posts_skipped'];
 563          } else {
 564              $post = compact('post_date', 'post_content', 'post_title', 'post_status');
 565  
 566              $post_id = wp_insert_post($post);
 567              if ( is_wp_error( $post_id ) )
 568                  return $post_id;
 569  
 570              wp_create_categories( array_map( 'addslashes', $entry->categories ), $post_id );
 571  
 572              $author = $this->no_apos( strip_tags( $entry->author ) );
 573  
 574              add_post_meta( $post_id, 'blogger_blog', $this->blogs[$importing_blog]['host'], true );
 575              add_post_meta( $post_id, 'blogger_author', $author, true );
 576              add_post_meta( $post_id, 'blogger_permalink', $entry->old_permalink, true );
 577  
 578              $this->blogs[$importing_blog]['posts'][$entry->old_permalink] = $post_id;
 579              ++$this->blogs[$importing_blog]['posts_done'];
 580          }
 581          $this->save_vars();
 582          return;
 583      }
 584  
 585  	function import_comment( $entry ) {
 586          global $importing_blog;
 587  
 588          // Drop the #fragment and we have the comment's old post permalink.
 589          foreach ( $entry->links as $link ) {
 590              if ( $link['rel'] == 'alternate' ) {
 591                  $parts = parse_url( $link['href'] );
 592                  $entry->old_permalink = $parts['fragment'];
 593                  $entry->old_post_permalink = $parts['path'];
 594                  break;
 595              }
 596          }
 597  
 598          $comment_post_ID = (int) $this->blogs[$importing_blog]['posts'][$entry->old_post_permalink];
 599          preg_match('#<name>(.+?)</name>.*(?:\<uri>(.+?)</uri>)?#', $entry->author, $matches);
 600          $comment_author  = addslashes( $this->no_apos( strip_tags( (string) $matches[1] ) ) );
 601          $comment_author_url = addslashes( $this->no_apos( strip_tags( (string) $matches[2] ) ) );
 602          $comment_date    = $this->convert_date( $entry->updated );
 603          $comment_content = addslashes( $this->no_apos( html_entity_decode( $entry->content ) ) );
 604  
 605          // Clean up content
 606          $comment_content = preg_replace_callback('|<(/?[A-Z]+)|', create_function('$match', 'return "<" . strtolower($match[1]);'), $comment_content);
 607          $comment_content = str_replace('<br>', '<br />', $comment_content);
 608          $comment_content = str_replace('<hr>', '<hr />', $comment_content);
 609  
 610          // Checks for duplicates
 611          if (
 612              isset( $this->blogs[$importing_blog]['comments'][$entry->old_permalink] ) ||
 613              comment_exists( $comment_author, $comment_date )
 614          ) {
 615              ++$this->blogs[$importing_blog]['comments_skipped'];
 616          } else {
 617              $comment = compact('comment_post_ID', 'comment_author', 'comment_author_url', 'comment_date', 'comment_content');
 618  
 619              $comment_id = wp_insert_comment($comment);
 620  
 621              $this->blogs[$importing_blog]['comments'][$entry->old_permalink] = $comment_id;
 622  
 623              ++$this->blogs[$importing_blog]['comments_done'];
 624          }
 625          $this->save_vars();
 626      }
 627  
 628  	function get_js_status($blog = false) {
 629          global $importing_blog;
 630          if ( $blog === false )
 631              $blog = $this->blogs[$importing_blog];
 632          else
 633              $blog = $this->blogs[$blog];
 634          $p1 = isset( $blog['posts_done'] ) ? (int) $blog['posts_done'] : 0;
 635          $p2 = isset( $blog['total_posts'] ) ? (int) $blog['total_posts'] : 0;
 636          $c1 = isset( $blog['comments_done'] ) ? (int) $blog['comments_done'] : 0;
 637          $c2 = isset( $blog['total_comments'] ) ? (int) $blog['total_comments'] : 0;
 638          return "{p1:$p1,p2:$p2,c1:$c1,c2:$c2}";
 639      }
 640  
 641  	function get_author_form($blog = false) {
 642          global $importing_blog, $wpdb, $current_user;
 643          if ( $blog === false )
 644              $blog = & $this->blogs[$importing_blog];
 645          else
 646              $blog = & $this->blogs[$blog];
 647  
 648          if ( !isset( $blog['authors'] ) ) {
 649              $post_ids = array_values($blog['posts']);
 650              $authors = (array) $wpdb->get_col("SELECT DISTINCT meta_value FROM $wpdb->postmeta WHERE meta_key = 'blogger_author' AND post_id IN (" . join( ',', $post_ids ) . ")");
 651              $blog['authors'] = array_map(null, $authors, array_fill(0, count($authors), $current_user->ID));
 652              $this->save_vars();
 653          }
 654  
 655          $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.');
 656          $heading = __('Author mapping');
 657          $blogtitle = "{$blog['title']} ({$blog['host']})";
 658          $mapthis = __('Blogger username');
 659          $tothis = __('WordPress login');
 660          $submit = js_escape( __('Save Changes') );
 661  
 662          foreach ( $blog['authors'] as $i => $author )
 663              $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>";
 664  
 665          return "<div class='wrap'><h2>$heading</h2><h3>$blogtitle</h3><p>$directions</p><form action='index.php?import=blogger&amp;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='button authorsubmit' value='$submit' /></td></tr></table></form></div>";
 666      }
 667  
 668  	function get_user_options($current) {
 669          global $importer_users;
 670          if ( ! isset( $importer_users ) )
 671              $importer_users = (array) get_users_of_blog();
 672  
 673          foreach ( $importer_users as $user ) {
 674              $sel = ( $user->user_id == $current ) ? " selected='selected'" : '';
 675              $options .= "<option value='$user->user_id'$sel>$user->display_name</option>";
 676          }
 677  
 678          return $options;
 679      }
 680  
 681  	function save_authors() {
 682          global $importing_blog, $wpdb;
 683          $authors = (array) $_POST['authors'];
 684  
 685          $host = $this->blogs[$importing_blog]['host'];
 686  
 687          // Get an array of posts => authors
 688          $post_ids = (array) $wpdb->get_col( $wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'blogger_blog' AND meta_value = %s", $host) );
 689          $post_ids = join( ',', $post_ids );
 690          $results = (array) $wpdb->get_results("SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = 'blogger_author' AND post_id IN ($post_ids)");
 691          foreach ( $results as $row )
 692              $authors_posts[$row->post_id] = $row->meta_value;
 693  
 694          foreach ( $authors as $author => $user_id ) {
 695              $user_id = (int) $user_id;
 696  
 697              // Skip authors that haven't been changed
 698              if ( $user_id == $this->blogs[$importing_blog]['authors'][$author][1] )
 699                  continue;
 700  
 701              // Get a list of the selected author's posts
 702              $post_ids = (array) array_keys( $authors_posts, $this->blogs[$importing_blog]['authors'][$author][0] );
 703              $post_ids = join( ',', $post_ids);
 704  
 705              $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET post_author = %d WHERE id IN ($post_ids)", $user_id) );
 706              $this->blogs[$importing_blog]['authors'][$author][1] = $user_id;
 707          }
 708          $this->save_vars();
 709  
 710          wp_redirect('edit.php');
 711      }
 712  
 713  	function _get_auth_sock() {
 714          // Connect to https://www.google.com
 715          if ( !$sock = @ fsockopen('ssl://www.google.com', 443, $errno, $errstr) ) {
 716              $this->uh_oh(
 717                  __('Could not connect to https://www.google.com'),
 718                  __('There was a problem opening a secure connection to Google. This is what went wrong:'),
 719                  "$errstr ($errno)"
 720              );
 721              return false;
 722          }
 723          return $sock;
 724      }
 725  
 726  	function _get_blogger_sock($host = 'www2.blogger.com') {
 727          if ( !$sock = @ fsockopen($host, 80, $errno, $errstr) ) {
 728              $this->uh_oh(
 729                  sprintf( __('Could not connect to %s'), $host ),
 730                  __('There was a problem opening a connection to Blogger. This is what went wrong:'),
 731                  "$errstr ($errno)"
 732              );
 733              return false;
 734          }
 735          return $sock;
 736      }
 737  
 738  	function _txrx( $sock, $request ) {
 739          fwrite( $sock, $request );
 740          while ( ! feof( $sock ) )
 741              $response .= @ fread ( $sock, 8192 );
 742          fclose( $sock );
 743          return $response;
 744      }
 745  
 746  	function revoke($token) {
 747          $headers = array(
 748              "GET /accounts/AuthSubRevokeToken HTTP/1.0",
 749              "Authorization: AuthSub token=\"$token\""
 750          );
 751          $request = join( "\r\n", $headers ) . "\r\n\r\n";
 752          $sock = $this->_get_auth_sock( );
 753          if ( ! $sock ) return false;
 754          $this->_txrx( $sock, $request );
 755      }
 756  
 757  	function restart() {
 758          global $wpdb;
 759          $options = get_option( 'blogger_importer' );
 760  
 761          if ( isset( $options['token'] ) )
 762              $this->revoke( $options['token'] );
 763  
 764          delete_option('blogger_importer');
 765          $wpdb->query("DELETE FROM $wpdb->postmeta WHERE meta_key = 'blogger_author'");
 766          wp_redirect('?import=blogger');
 767      }
 768  
 769      // Returns associative array of code, header, cookies, body. Based on code from php.net.
 770  	function parse_response($this_response) {
 771          // Split response into header and body sections
 772          list($response_headers, $response_body) = explode("\r\n\r\n", $this_response, 2);
 773          $response_header_lines = explode("\r\n", $response_headers);
 774  
 775          // First line of headers is the HTTP response code
 776          $http_response_line = array_shift($response_header_lines);
 777          if(preg_match('@^HTTP/[0-9]\.[0-9] ([0-9]{3})@',$http_response_line, $matches)) { $response_code = $matches[1]; }
 778  
 779          // put the rest of the headers in an array
 780          $response_header_array = array();
 781          foreach($response_header_lines as $header_line) {
 782              list($header,$value) = explode(': ', $header_line, 2);
 783              $response_header_array[$header] .= $value."\n";
 784          }
 785  
 786          $cookie_array = array();
 787          $cookies = explode("\n", $response_header_array["Set-Cookie"]);
 788          foreach($cookies as $this_cookie) { array_push($cookie_array, "Cookie: ".$this_cookie); }
 789  
 790          return array("code" => $response_code, "header" => $response_header_array, "cookies" => $cookie_array, "body" => $response_body);
 791      }
 792  
 793      // Step 9: Congratulate the user
 794  	function congrats() {
 795          $blog = (int) $_GET['blog'];
 796          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>';
 797          if ( count($this->import['blogs']) > 1 )
 798              echo '<li>'.__('In case you haven\'t done it already, you can import the posts from your other blogs:'). $this->show_blogs() . '</li>';
 799          if ( $n = count($this->import['blogs'][$blog]['newusers']) )
 800              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>';
 801          echo '<li>'.__('For security, click the link below to reset this importer.').'</li>';
 802          echo '</ul>';
 803      }
 804  
 805      // Figures out what to do, then does it.
 806  	function start() {
 807          if ( isset($_POST['restart']) )
 808              $this->restart();
 809  
 810          $options = get_option('blogger_importer');
 811  
 812          if ( is_array($options) )
 813              foreach ( $options as $key => $value )
 814                  $this->$key = $value;
 815  
 816          if ( isset( $_REQUEST['blog'] ) ) {
 817              $blog = is_array($_REQUEST['blog']) ? array_shift( $keys = array_keys( $_REQUEST['blog'] ) ) : $_REQUEST['blog'];
 818              $blog = (int) $blog;
 819              $result = $this->import_blog( $blog );
 820              if ( is_wp_error( $result ) )
 821                  echo $result->get_error_message();
 822          } elseif ( isset($_GET['token']) )
 823              $this->auth();
 824          elseif ( isset($this->token) && $this->token_is_valid() )
 825              $this->show_blogs();
 826          else
 827              $this->greet();
 828  
 829          $saved = $this->save_vars();
 830  
 831          if ( $saved && !isset($_GET['noheader']) ) {
 832              $restart = __('Restart');
 833              $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.');
 834              $submit = __('Clear account information');
 835              echo "<div class='wrap'><h2>$restart</h2><p>$message</p><form method='post' action='?import=blogger&amp;noheader=true'><p class='submit' style='text-align:left;'><input type='submit' class='button' value='$submit' name='restart' /></p></form></div>";
 836          }
 837      }
 838  
 839  	function save_vars() {
 840          $vars = get_object_vars($this);
 841          update_option( 'blogger_importer', $vars );
 842  
 843          return !empty($vars);
 844      }
 845  
 846  	function admin_head() {
 847  ?>
 848  <style type="text/css">
 849  td { text-align: center; line-height: 2em;}
 850  thead td { font-weight: bold; }
 851  .bar {
 852      width: 200px;
 853      text-align: left;
 854      line-height: 2em;
 855      padding: 0px;
 856  }
 857  .ind {
 858      position: absolute;
 859      background-color: #83B4D8;
 860      width: 1px;
 861      z-index: 9;
 862  }
 863  .stat {
 864      z-index: 10;
 865      position: relative;
 866      text-align: center;
 867  }
 868  </style>
 869  <?php
 870      }
 871  
 872  	function Blogger_Import() {
 873          global $importer_started;
 874          $importer_started = time();
 875          if ( isset( $_GET['import'] ) && $_GET['import'] == 'blogger' ) {
 876              wp_enqueue_script('jquery');
 877              add_action('admin_head', array(&$this, 'admin_head'));
 878          }
 879      }
 880  }
 881  
 882  $blogger_import = new Blogger_Import();
 883  
 884  register_importer('blogger', __('Blogger'), __('Import posts, comments, and users from a Blogger blog.'), array ($blogger_import, 'start'));
 885  
 886  class AtomEntry {
 887      var $links = array();
 888      var $categories = array();
 889  }
 890  
 891  class AtomParser {
 892  
 893      var $ATOM_CONTENT_ELEMENTS = array('content','summary','title','subtitle','rights');
 894      var $ATOM_SIMPLE_ELEMENTS = array('id','updated','published','draft','author');
 895  
 896      var $depth = 0;
 897      var $indent = 2;
 898      var $in_content;
 899      var $ns_contexts = array();
 900      var $ns_decls = array();
 901      var $is_xhtml = false;
 902      var $skipped_div = false;
 903  
 904      var $entry;
 905  
 906  	function AtomParser() {
 907  
 908          $this->entry = new AtomEntry();
 909          $this->map_attrs_func = create_function('$k,$v', 'return "$k=\"$v\"";');
 910          $this->map_xmlns_func = create_function('$p,$n', '$xd = "xmlns"; if(strlen($n[0])>0) $xd .= ":{$n[0]}"; return "{$xd}=\"{$n[1]}\"";');
 911      }
 912  
 913  	function parse($xml) {
 914  
 915          global $app_logging;
 916          array_unshift($this->ns_contexts, array());
 917  
 918          $parser = xml_parser_create_ns();
 919          xml_set_object($parser, $this);
 920          xml_set_element_handler($parser, "start_element", "end_element");
 921          xml_parser_set_option($parser,XML_OPTION_CASE_FOLDING,0);
 922          xml_parser_set_option($parser,XML_OPTION_SKIP_WHITE,0);
 923          xml_set_character_data_handler($parser, "cdata");
 924          xml_set_default_handler($parser, "_default");
 925          xml_set_start_namespace_decl_handler($parser, "start_ns");
 926          xml_set_end_namespace_decl_handler($parser, "end_ns");
 927  
 928          $contents = "";
 929  
 930          xml_parse($parser, $xml);
 931  
 932          xml_parser_free($parser);
 933  
 934          return true;
 935      }
 936  
 937  	function start_element($parser, $name, $attrs) {
 938  
 939          $tag = array_pop(split(":", $name));
 940  
 941          array_unshift($this->ns_contexts, $this->ns_decls);
 942  
 943          $this->depth++;
 944  
 945          if(!empty($this->in_content)) {
 946              $attrs_prefix = array();
 947  
 948              // resolve prefixes for attributes
 949              foreach($attrs as $key => $value) {
 950                  $attrs_prefix[$this->ns_to_prefix($key)] = $this->xml_escape($value);
 951              }
 952              $attrs_str = join(' ', array_map($this->map_attrs_func, array_keys($attrs_prefix), array_values($attrs_prefix)));
 953              if(strlen($attrs_str) > 0) {
 954                  $attrs_str = " " . $attrs_str;
 955              }
 956  
 957              $xmlns_str = join(' ', array_map($this->map_xmlns_func, array_keys($this->ns_contexts[0]), array_values($this->ns_contexts[0])));
 958              if(strlen($xmlns_str) > 0) {
 959                  $xmlns_str = " " . $xmlns_str;
 960              }
 961  
 962              // handle self-closing tags (case: a new child found right-away, no text node)
 963              if(count($this->in_content) == 2) {
 964                  array_push($this->in_content, ">");
 965              }
 966  
 967              array_push($this->in_content, "<". $this->ns_to_prefix($name) ."{$xmlns_str}{$attrs_str}");
 968          } else if(in_array($tag, $this->ATOM_CONTENT_ELEMENTS) || in_array($tag, $this->ATOM_SIMPLE_ELEMENTS)) {
 969              $this->in_content = array();
 970              $this->is_xhtml = $attrs['type'] == 'xhtml';
 971              array_push($this->in_content, array($tag,$this->depth));
 972          } else if($tag == 'link') {
 973              array_push($this->entry->links, $attrs);
 974          } else if($tag == 'category') {
 975              array_push($this->entry->categories, $attrs['term']);
 976          }
 977  
 978          $this->ns_decls = array();
 979      }
 980  
 981  	function end_element($parser, $name) {
 982  
 983          $tag = array_pop(split(":", $name));
 984  
 985          if(!empty($this->in_content)) {
 986              if($this->in_content[0][0] == $tag &&
 987              $this->in_content[0][1] == $this->depth) {
 988                  array_shift($this->in_content);
 989                  if($this->is_xhtml) {
 990                      $this->in_content = array_slice($this->in_content, 2, count($this->in_content)-3);
 991                  }
 992                  $this->entry->$tag = join('',$this->in_content);
 993                  $this->in_content = array();
 994              } else {
 995                  $endtag = $this->ns_to_prefix($name);
 996                  if (strpos($this->in_content[count($this->in_content)-1], '<' . $endtag) !== false) {
 997                      array_push($this->in_content, "/>");
 998                  } else {
 999                      array_push($this->in_content, "</$endtag>");
1000                  }
1001              }
1002          }
1003  
1004          array_shift($this->ns_contexts);
1005  
1006          #print str_repeat(" ", $this->depth * $this->indent) . "end_element('$name')" ."\n";
1007  
1008          $this->depth--;
1009      }
1010  
1011  	function start_ns($parser, $prefix, $uri) {
1012          #print str_repeat(" ", $this->depth * $this->indent) . "starting: " . $prefix . ":" . $uri . "\n";
1013          array_push($this->ns_decls, array($prefix,$uri));
1014      }
1015  
1016  	function end_ns($parser, $prefix) {
1017          #print str_repeat(" ", $this->depth * $this->indent) . "ending: #" . $prefix . "#\n";
1018      }
1019  
1020  	function cdata($parser, $data) {
1021          #print str_repeat(" ", $this->depth * $this->indent) . "data: #" . $data . "#\n";
1022          if(!empty($this->in_content)) {
1023              // handle self-closing tags (case: text node found, need to close element started)
1024              if (strpos($this->in_content[count($this->in_content)-1], '<') !== false) {
1025                  array_push($this->in_content, ">");
1026              }
1027              array_push($this->in_content, $this->xml_escape($data));
1028          }
1029      }
1030  
1031  	function _default($parser, $data) {
1032          # when does this gets called?
1033      }
1034  
1035  
1036  	function ns_to_prefix($qname) {
1037          $components = split(":", $qname);
1038          $name = array_pop($components);
1039  
1040          if(!empty($components)) {
1041              $ns = join(":",$components);
1042              foreach($this->ns_contexts as $context) {
1043                  foreach($context as $mapping) {
1044                      if($mapping[1] == $ns && strlen($mapping[0]) > 0) {
1045                          return "$mapping[0]:$name";
1046                      }
1047                  }
1048              }
1049          }
1050          return $name;
1051      }
1052  
1053  	function xml_escape($string)
1054      {
1055               return str_replace(array('&','"',"'",'<','>'),
1056                  array('&amp;','&quot;','&apos;','&lt;','&gt;'),
1057                  $string );
1058      }
1059  }
1060  
1061  ?>


Generated: Mon Mar 23 16:23:02 2009 Cross-referenced by PHPXref 0.7