root/branches/2.0/wp-admin/import/blogger.php

Revision 4680, 28.5 kB (checked in by markjaquith, 2 years ago)

Change wording for Blogger import to note that it only works with OLD Blogger accounts. Props foolswisdom. fixes #3490

  • Property svn:eol-style set to native
Line 
1 <?php
2
3 class Blogger_Import {
4
5     var $lump_authors = false;
6     var $import = array();
7
8     // Shows the welcome screen and the magic iframe.
9     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 = __('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 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>";
21         else
22             echo "<p>$incompat</p>";
23         echo "</div>\n";
24     }
25
26     // Deletes saved data and redirect.
27     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";
39     }
40
41     // Returns associative array of code, header, cookies, body. Based on code from php.net.
42     function parse_response($this_response) {
43         // Split response into header and body sections
44         list($response_headers, $response_body) = explode("\r\n\r\n", $this_response, 2);
45         $response_header_lines = explode("\r\n", $response_headers);
46
47         // First line of headers is the HTTP response code
48         $http_response_line = array_shift($response_header_lines);
49         if(preg_match('@^HTTP/[0-9]\.[0-9] ([0-9]{3})@',$http_response_line, $matches)) { $response_code = $matches[1]; }
50
51         // put the rest of the headers in an array
52         $response_header_array = array();
53         foreach($response_header_lines as $header_line) {
54             list($header,$value) = explode(': ', $header_line, 2);
55             $response_header_array[$header] .= $value."\n";
56         }
57
58         $cookie_array = array();
59         $cookies = explode("\n", $response_header_array["Set-Cookie"]);
60         foreach($cookies as $this_cookie) { array_push($cookie_array, "Cookie: ".$this_cookie); }
61
62         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                 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                                 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                         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(