PHP Cross Reference of WordPress Latest 2.0 Branch |
| [ Index ] [ Classes ] [ Functions ] [ Variables ] [ Constants ] |
[Summary view] [Print] [Text view]
1 <?php 2 3 define('XMLRPC_REQUEST', true); 4 5 // Some browser-embedded clients send cookies. We don't want them. 6 $_COOKIE = array(); 7 8 # fix for mozBlog and other cases where '<?xml' isn't on the very first line 9 if ( isset($HTTP_RAW_POST_DATA) ) 10 $HTTP_RAW_POST_DATA = trim($HTTP_RAW_POST_DATA); 11 12 include('./wp-config.php'); 13 14 if ( isset( $_GET['rsd'] ) ) { // http://archipelago.phrasewise.com/rsd 15 header('Content-type: text/xml; charset=' . get_settings('blog_charset'), true); 16 17 ?> 18 <?php echo '<?xml version="1.0" encoding="'.get_settings('blog_charset').'"?'.'>'; ?> 19 <rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd"> 20 <service> 21 <engineName>WordPress</engineName> 22 <engineLink>http://wordpress.org/</engineLink> 23 <homePageLink><?php bloginfo_rss('url') ?></homePageLink> 24 <apis> 25 <api name="Movable Type" blogID="1" preferred="true" apiLink="<?php bloginfo_rss('url') ?>/xmlrpc.php" /> 26 <api name="MetaWeblog" blogID="1" preferred="false" apiLink="<?php bloginfo_rss('url') ?>/xmlrpc.php" /> 27 <api name="Blogger" blogID="1" preferred="false" apiLink="<?php bloginfo_rss('url') ?>/xmlrpc.php" /> 28 </apis> 29 </service> 30 </rsd> 31 <?php 32 exit; 33 } 34 35 include_once(ABSPATH . WPINC . '/class-IXR.php'); 36 37 // Turn off all warnings and errors. 38 // error_reporting(0); 39 40 $post_default_title = ""; // posts submitted via the xmlrpc interface get that title 41 42 $xmlrpc_logging = 0; 43 44 function logIO($io,$msg) { 45 global $xmlrpc_logging; 46 if ($xmlrpc_logging) { 47 $fp = fopen("../xmlrpc.log","a+"); 48 $date = gmdate("Y-m-d H:i:s "); 49 $iot = ($io == "I") ? " Input: " : " Output: "; 50 fwrite($fp, "\n\n".$date.$iot.$msg); 51 fclose($fp); 52 } 53 return true; 54 } 55 56 function starify($string) { 57 $i = strlen($string); 58 return str_repeat('*', $i); 59 } 60 61 if ( isset($HTTP_RAW_POST_DATA) ) 62 logIO("I", $HTTP_RAW_POST_DATA); 63 64 65 class wp_xmlrpc_server extends IXR_Server { 66 67 function wp_xmlrpc_server() { 68 $this->methods = array( 69 // Blogger API 70 'blogger.getUsersBlogs' => 'this:blogger_getUsersBlogs', 71 'blogger.getUserInfo' => 'this:blogger_getUserInfo', 72 'blogger.getPost' => 'this:blogger_getPost', 73 'blogger.getRecentPosts' => 'this:blogger_getRecentPosts', 74 'blogger.getTemplate' => 'this:blogger_getTemplate', 75 'blogger.setTemplate' => 'this:blogger_setTemplate', 76 'blogger.newPost' => 'this:blogger_newPost', 77 'blogger.editPost' => 'this:blogger_editPost', 78 'blogger.deletePost' => 'this:blogger_deletePost', 79 80 // MetaWeblog API (with MT extensions to structs) 81 'metaWeblog.newPost' => 'this:mw_newPost', 82 'metaWeblog.editPost' => 'this:mw_editPost', 83 'metaWeblog.getPost' => 'this:mw_getPost', 84 'metaWeblog.getRecentPosts' => 'this:mw_getRecentPosts', 85 'metaWeblog.getCategories' => 'this:mw_getCategories', 86 'metaWeblog.newMediaObject' => 'this:mw_newMediaObject', 87 88 // MetaWeblog API aliases for Blogger API 89 // see http://www.xmlrpc.com/stories/storyReader$2460 90 'metaWeblog.deletePost' => 'this:blogger_deletePost', 91 'metaWeblog.getTemplate' => 'this:blogger_getTemplate', 92 'metaWeblog.setTemplate' => 'this:blogger_setTemplate', 93 'metaWeblog.getUsersBlogs' => 'this:blogger_getUsersBlogs', 94 95 // MovableType API 96 'mt.getCategoryList' => 'this:mt_getCategoryList', 97 'mt.getRecentPostTitles' => 'this:mt_getRecentPostTitles', 98 'mt.getPostCategories' => 'this:mt_getPostCategories', 99 'mt.setPostCategories' => 'this:mt_setPostCategories', 100 'mt.supportedMethods' => 'this:mt_supportedMethods', 101 'mt.supportedTextFilters' => 'this:mt_supportedTextFilters', 102 'mt.getTrackbackPings' => 'this:mt_getTrackbackPings', 103 'mt.publishPost' => 'this:mt_publishPost', 104 105 // PingBack 106 'pingback.ping' => 'this:pingback_ping', 107 'pingback.extensions.getPingbacks' => 'this:pingback_extensions_getPingbacks', 108 109 'demo.sayHello' => 'this:sayHello', 110 'demo.addTwoNumbers' => 'this:addTwoNumbers' 111 ); 112 $this->methods = apply_filters('xmlrpc_methods', $this->methods); 113 $this->IXR_Server($this->methods); 114 } 115 116 function sayHello($args) { 117 return 'Hello!'; 118 } 119 120 function addTwoNumbers($args) { 121 $number1 = $args[0]; 122 $number2 = $args[1]; 123 return $number1 + $number2; 124 } 125 126 function login_pass_ok($user_login, $user_pass) { 127 if (!user_pass_ok($user_login, $user_pass)) { 128 $this->error = new IXR_Error(403, 'Bad login/pass combination.'); 129 return false; 130 } 131 return true; 132 } 133 134 function escape(&$array) { 135 global $wpdb; 136 137 foreach ( (array) $array as $k => $v ) { 138 if (is_array($v)) { 139 $this->escape($array[$k]); 140 } else if (is_object($v)) { 141 //skip 142 } else { 143 $array[$k] = $wpdb->escape($v); 144 } 145 } 146 } 147 148 /* Blogger API functions 149 * specs on http://plant.blogger.com/api and http://groups.yahoo.com/group/bloggerDev/ 150 */ 151 152 153 /* blogger.getUsersBlogs will make more sense once we support multiple blogs */ 154 function blogger_getUsersBlogs($args) { 155 156 $this->escape($args); 157 158 $user_login = $args[1]; 159 $user_pass = $args[2]; 160 161 if (!$this->login_pass_ok($user_login, $user_pass)) { 162 return $this->error; 163 } 164 165 set_current_user(0, $user_login); 166 $is_admin = current_user_can('level_8'); 167 168 $struct = array( 169 'isAdmin' => $is_admin, 170 'url' => get_settings('home') . '/', 171 'blogid' => '1', 172 'blogName' => get_settings('blogname') 173 ); 174 175 return array($struct); 176 } 177 178 179 /* blogger.getUsersInfo gives your client some info about you, so you don't have to */ 180 function blogger_getUserInfo($args) { 181 182 $this->escape($args); 183 184 $user_login = $args[1]; 185 $user_pass = $args[2]; 186 187 if (!$this->login_pass_ok($user_login, $user_pass)) { 188 return $this->error; 189 } 190 191 $user_data = get_userdatabylogin($user_login); 192 193 $struct = array( 194 'nickname' => $user_data->nickname, 195 'userid' => $user_data->ID, 196 'url' => $user_data->user_url, 197 'email' => $user_data->user_email, 198 'lastname' => $user_data->last_name, 199 'firstname' => $user_data->first_name 200 ); 201 202 return $struct; 203 } 204 205 206 /* blogger.getPost ...gets a post */ 207 function blogger_getPost($args) { 208 209 $this->escape($args); 210 211 $post_ID = (int) $args[1]; 212 $user_login = $args[2]; 213 $user_pass = $args[3]; 214 215 if (!$this->login_pass_ok($user_login, $user_pass)) { 216 return $this->error; 217 } 218 219 $user_data = get_userdatabylogin($user_login); 220 $post_data = wp_get_single_post($post_ID, ARRAY_A); 221 222 $categories = implode(',', wp_get_post_cats(1, $post_ID)); 223 224 $content = '<title>'.stripslashes($post_data['post_title']).'</title>'; 225 $content .= '<category>'.$categories.'</category>'; 226 $content .= stripslashes($post_data['post_content']); 227 228 $struct = array( 229 'userid' => $post_data['post_author'], 230 'dateCreated' => new IXR_Date(mysql2date('Ymd\TH:i:s', $post_data['post_date'])), 231 'content' => $content, 232 'postid' => $post_data['ID'] 233 ); 234 235 return $struct; 236 } 237 238 239 /* blogger.getRecentPosts ...gets recent posts */ 240 function blogger_getRecentPosts($args) { 241 242 global $wpdb; 243 244 $this->escape($args); 245 246 $blog_ID = (int) $args[1]; /* though we don't use it yet */ 247 $user_login = $args[2]; 248 $user_pass = $args[3]; 249 $num_posts = $args[4]; 250 251 if (!$this->login_pass_ok($user_login, $user_pass)) { 252 return $this->error; 253 } 254 255 $posts_list = wp_get_recent_posts($num_posts); 256 257 if (!$posts_list) { 258 $this->error = new IXR_Error(500, 'Either there are no posts, or something went wrong.'); 259 return $this->error; 260 } 261 262 foreach ($posts_list as $entry) { 263 264 $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date']); 265 $categories = implode(',', wp_get_post_cats(1, $entry['ID'])); 266 267 $content = '<title>'.stripslashes($entry['post_title']).'</title>'; 268 $content .= '<category>'.$categories.'</category>'; 269 $content .= stripslashes($entry['post_content']); 270 271 $struct[] = array( 272 'userid' => $entry['post_author'], 273 'dateCreated' => new IXR_Date($post_date), 274 'content' => $content, 275 'postid' => $entry['ID'], 276 ); 277 278 } 279 280 $recent_posts = array(); 281 for ($j=0; $j<count($struct); $j++) { 282 array_push($recent_posts, $struct[$j]); 283 } 284 285 return $recent_posts; 286 } 287 288 289 /* blogger.getTemplate returns your blog_filename */ 290 function blogger_getTemplate($args) { 291 292 $this->escape($args); 293 294 $blog_ID = (int) $args[1]; 295 $user_login = $args[2]; 296 $user_pass = $args[3]; 297 $template = $args[4]; /* could be 'main' or 'archiveIndex', but we don't use it */ 298 299 if (!$this->login_pass_ok($user_login, $user_pass)) { 300 return $this->error; 301 } 302 303 set_current_user(0, $user_login); 304 if ( !current_user_can('edit_themes') ) { 305 return new IXR_Error(401, 'Sorry, this user can not edit the template.'); 306 } 307 308 /* warning: here we make the assumption that the weblog's URI is on the same server */ 309 $filename = get_settings('home') . '/'; 310 $filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename); 311 312 $f = fopen($filename, 'r'); 313 $content = fread($f, filesize($filename)); 314 fclose($f); 315 316 /* so it is actually editable with a windows/mac client */ 317 // FIXME: (or delete me) do we really want to cater to bad clients at the expense of good ones by BEEPing up their line breaks? commented. $content = str_replace("\n", "\r\n", $content); 318 319 return $content; 320 } 321 322 323 /* blogger.setTemplate updates the content of blog_filename */ 324 function blogger_setTemplate($args) { 325 326 $this->escape($args); 327 328 $blog_ID = (int) $args[1]; 329 $user_login = $args[2]; 330 $user_pass = $args[3]; 331 $content = $args[4]; 332 $template = $args[5]; /* could be 'main' or 'archiveIndex', but we don't use it */ 333 334 if (!$this->login_pass_ok($user_login, $user_pass)) { 335 return $this->error; 336 } 337 338 set_current_user(0, $user_login); 339 if ( !current_user_can('edit_themes') ) { 340 return new IXR_Error(401, 'Sorry, this user can not edit the template.'); 341 } 342 343 /* warning: here we make the assumption that the weblog's URI is on the same server */ 344 $filename = get_settings('home') . '/'; 345 $filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename); 346 347 if ($f = fopen($filename, 'w+')) { 348 fwrite($f, $content); 349 fclose($f); 350 } else { 351 return new IXR_Error(500, 'Either the file is not writable, or something wrong happened. The file has not been updated.'); 352 } 353 354 return true; 355 } 356 357 358 /* blogger.newPost ...creates a new post */ 359 function blogger_newPost($args) { 360 361 global $wpdb; 362 363 $this->escape($args); 364 365 $blog_ID = (int) $args[1]; /* though we don't use it yet */ 366 $user_login = $args[2]; 367 $user_pass = $args[3]; 368 $content = $args[4]; 369 $publish = $args[5]; 370 371 if (!$this->login_pass_ok($user_login, $user_pass)) { 372 return $this->error; 373 } 374 375 $cap = ($publish) ? 'publish_posts' : 'edit_posts'; 376 $user = set_current_user(0, $user_login); 377 if ( !current_user_can($cap) ) 378 return new IXR_Error(401, 'Sorry, you can not post on this weblog or category.'); 379 380 $post_status = ($publish) ? 'publish' : 'draft'; 381 382 $post_author = $user->ID; 383 384 $post_title = xmlrpc_getposttitle($content); 385 $post_category = xmlrpc_getpostcategory($content); 386 $post_content = xmlrpc_removepostdata($content); 387 388 $post_date = current_time('mysql'); 389 $post_date_gmt = current_time('mysql', 1); 390 391 $post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status'); 392 393 $post_ID = wp_insert_post($post_data); 394 395 if (!$post_ID) { 396 return new IXR_Error(500, 'Sorry, your entry could not be posted. Something wrong happened.'); 397 } 398 399 logIO('O', "Posted ! ID: $post_ID"); 400 401 return $post_ID; 402 } 403 404 405 /* blogger.editPost ...edits a post */ 406 function blogger_editPost($args) { 407 408 global $wpdb; 409 410 $this->escape($args); 411 412 $post_ID = (int) $args[1]; 413 $user_login = $args[2]; 414 $user_pass = $args[3]; 415 $content = $args[4]; 416 $publish = $args[5]; 417 418 if (!$this->login_pass_ok($user_login, $user_pass)) { 419 return $this->error; 420 } 421 422 $actual_post = wp_get_single_post($post_ID,ARRAY_A); 423 424 if (!$actual_post) { 425 return new IXR_Error(404, 'Sorry, no such post.'); 426 } 427 428 $this->escape($actual_post); 429 430 set_current_user(0, $user_login); 431 if ( !current_user_can('edit_post', $post_ID) ) 432 return new IXR_Error(401, 'Sorry, you do not have the right to edit this post.'); 433 434 extract($actual_post, EXTR_SKIP); 435 436 if ( ('publish' == $post_status) && !current_user_can('publish_posts') ) 437 return new IXR_Error(401, 'Sorry, you do not have the right to publish this post.'); 438 439 $post_title = xmlrpc_getposttitle($content); 440 $post_category = xmlrpc_getpostcategory($content); 441 $post_content = xmlrpc_removepostdata($content); 442 443 $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt'); 444 445 $result = wp_update_post($postdata); 446 447 if (!$result) { 448 return new IXR_Error(500, 'For some strange yet very annoying reason, this post could not be edited.'); 449 } 450 451 return true; 452 } 453 454 455 /* blogger.deletePost ...deletes a post */ 456 function blogger_deletePost($args) { 457 458 global $wpdb; 459 460 $this->escape($args); 461 462 $post_ID = (int) $args[1]; 463 $user_login = $args[2]; 464 $user_pass = $args[3]; 465 $publish = $args[4]; 466 467 if (!$this->login_pass_ok($user_login, $user_pass)) { 468 return $this->error; 469 } 470 471 $actual_post = wp_get_single_post($post_ID,ARRAY_A); 472 473 if (!$actual_post) { 474 return new IXR_Error(404, 'Sorry, no such post.'); 475 } 476 477 set_current_user(0, $user_login); 478 if ( !current_user_can('edit_post', $post_ID) ) 479 return new IXR_Error(401, 'Sorry, you do not have the right to delete this post.'); 480 481 $result = wp_delete_post($post_ID); 482 483 if (!$result) { 484 return new IXR_Error(500, 'For some strange yet very annoying reason, this post could not be deleted.'); 485 } 486 487 return true; 488 } 489 490 491 492 /* MetaWeblog API functions 493 * specs on wherever Dave Winer wants them to be 494 */ 495 496 /* metaweblog.newPost creates a post */ 497 function mw_newPost($args) { 498 499 global $wpdb, $post_default_category; 500 501 $this->escape($args); 502 503 $blog_ID = (int) $args[0]; // we will support this in the near future 504 $user_login = $args[1]; 505 $user_pass = $args[2]; 506 $content_struct = $args[3]; 507 $publish = $args[4]; 508 509 if (!$this->login_pass_ok($user_login, $user_pass)) { 510 return $this->error; 511 } 512 513 $user = set_current_user(0, $user_login); 514 if ( !current_user_can('publish_posts') ) 515 return new IXR_Error(401, 'Sorry, you can not post on this weblog or category.'); 516 517 $post_author = $user->ID; 518 519 $post_title = $content_struct['title']; 520 $post_content = apply_filters( 'content_save_pre', $content_struct['description'] ); 521 $post_status = $publish ? 'publish' : 'draft'; 522 523 $post_excerpt = $content_struct['mt_excerpt']; 524 $post_more = $content_struct['mt_text_more']; 525 526 $comment_status = (empty($content_struct['mt_allow_comments'])) ? 527 get_settings('default_comment_status') 528 : $content_struct['mt_allow_comments']; 529 530 $ping_status = (empty($content_struct['mt_allow_pings'])) ? 531 get_settings('default_ping_status') 532 : $content_struct['mt_allow_pings']; 533 534 if ($post_more) { 535 $post_content = $post_content . "\n<!--more-->\n" . $post_more; 536 } 537 538 $to_ping = $content_struct['mt_tb_ping_urls']; 539 if ( is_array($to_ping) ) 540 $to_ping = implode(' ', $to_ping); 541 542 // Do some timestamp voodoo 543 $dateCreatedd = $content_struct['dateCreated']; 544 if (!empty($dateCreatedd)) { 545 $dateCreated = $dateCreatedd->getIso(); 546 $post_date = get_date_from_gmt(iso8601_to_datetime($dateCreated)); 547 $post_date_gmt = iso8601_to_datetime($dateCreated, GMT); 548 } else {