| [ Index ] |
WordPress Source Cross Reference |
[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 logIO("I", $HTTP_RAW_POST_DATA); 62 63 64 function mkdir_p($target) { 65 // from php.net/mkdir user contributed notes 66 if (file_exists($target)) { 67 if (!is_dir($target)) { 68 return false; 69 } else { 70 return true; 71 } 72 } 73 74 // Attempting to create the directory may clutter up our display. 75 if (@mkdir($target)) { 76 return true; 77 } 78 79 // If the above failed, attempt to create the parent node, then try again. 80 if (mkdir_p(dirname($target))) { 81 return mkdir_p($target); 82 } 83 84 return false; 85 } 86 87 88 class wp_xmlrpc_server extends IXR_Server { 89 90 function wp_xmlrpc_server() { 91 $this->methods = array( 92 // Blogger API 93 'blogger.getUsersBlogs' => 'this:blogger_getUsersBlogs', 94 'blogger.getUserInfo' => 'this:blogger_getUserInfo', 95 'blogger.getPost' => 'this:blogger_getPost', 96 'blogger.getRecentPosts' => 'this:blogger_getRecentPosts', 97 'blogger.getTemplate' => 'this:blogger_getTemplate', 98 'blogger.setTemplate' => 'this:blogger_setTemplate', 99 'blogger.newPost' => 'this:blogger_newPost', 100 'blogger.editPost' => 'this:blogger_editPost', 101 'blogger.deletePost' => 'this:blogger_deletePost', 102 103 // MetaWeblog API (with MT extensions to structs) 104 'metaWeblog.newPost' => 'this:mw_newPost', 105 'metaWeblog.editPost' => 'this:mw_editPost', 106 'metaWeblog.getPost' => 'this:mw_getPost', 107 'metaWeblog.getRecentPosts' => 'this:mw_getRecentPosts', 108 'metaWeblog.getCategories' => 'this:mw_getCategories', 109 'metaWeblog.newMediaObject' => 'this:mw_newMediaObject', 110 111 // MetaWeblog API aliases for Blogger API 112 // see http://www.xmlrpc.com/stories/storyReader$2460 113 'metaWeblog.deletePost' => 'this:blogger_deletePost', 114 'metaWeblog.getTemplate' => 'this:blogger_getTemplate', 115 'metaWeblog.setTemplate' => 'this:blogger_setTemplate', 116 'metaWeblog.getUsersBlogs' => 'this:blogger_getUsersBlogs', 117 118 // MovableType API 119 'mt.getCategoryList' => 'this:mt_getCategoryList', 120 'mt.getRecentPostTitles' => 'this:mt_getRecentPostTitles', 121 'mt.getPostCategories' => 'this:mt_getPostCategories', 122 'mt.setPostCategories' => 'this:mt_setPostCategories', 123 'mt.supportedMethods' => 'this:mt_supportedMethods', 124 'mt.supportedTextFilters' => 'this:mt_supportedTextFilters', 125 'mt.getTrackbackPings' => 'this:mt_getTrackbackPings', 126 'mt.publishPost' => 'this:mt_publishPost', 127 128 // PingBack 129 'pingback.ping' => 'this:pingback_ping', 130 'pingback.extensions.getPingbacks' => 'this:pingback_extensions_getPingbacks', 131 132 'demo.sayHello' => 'this:sayHello', 133 'demo.addTwoNumbers' => 'this:addTwoNumbers' 134 ); 135 $this->methods = apply_filters('xmlrpc_methods', $this->methods); 136 $this->IXR_Server($this->methods); 137 } 138 139 function sayHello($args) { 140 return 'Hello!'; 141 } 142 143 function addTwoNumbers($args) { 144 $number1 = $args[0]; 145 $number2 = $args[1]; 146 return $number1 + $number2; 147 } 148 149 function login_pass_ok($user_login, $user_pass) { 150 if (!user_pass_ok($user_login, $user_pass)) { 151 $this->error = new IXR_Error(403, 'Bad login/pass combination.'); 152 return false; 153 } 154 return true; 155 } 156 157 function escape(&$array) { 158 global $wpdb; 159 160 foreach ($array as $k => $v) { 161 if (is_array($v)) { 162 $this->escape($array[$k]); 163 } else if (is_object($v)) { 164 //skip 165 } else { 166 $array[$k] = $wpdb->escape($v); 167 } 168 } 169 } 170 171 /* Blogger API functions 172 * specs on http://plant.blogger.com/api and http://groups.yahoo.com/group/bloggerDev/ 173 */ 174 175 176 /* blogger.getUsersBlogs will make more sense once we support multiple blogs */ 177 function blogger_getUsersBlogs($args) { 178 179 $this->escape($args); 180 181 $user_login = $args[1]; 182 $user_pass = $args[2]; 183 184 if (!$this->login_pass_ok($user_login, $user_pass)) { 185 return $this->error; 186 } 187 188 set_current_user(0, $user_login); 189 $is_admin = current_user_can('level_8'); 190 191 $struct = array( 192 'isAdmin' => $is_admin, 193 'url' => get_settings('home') . '/', 194 'blogid' => '1', 195 'blogName' => get_settings('blogname') 196 ); 197 198 return array($struct); 199 } 200 201 202 /* blogger.getUsersInfo gives your client some info about you, so you don't have to */ 203 function blogger_getUserInfo($args) { 204 205 $this->escape($args); 206 207 $user_login = $args[1]; 208 $user_pass = $args[2]; 209 210 if (!$this->login_pass_ok($user_login, $user_pass)) { 211 return $this->error; 212 } 213 214 $user_data = get_userdatabylogin($user_login); 215 216 $struct = array( 217 'nickname' => $user_data->nickname, 218 'userid' => $user_data->ID, 219 'url' => $user_data->user_url, 220 'email' => $user_data->user_email, 221 'lastname' => $user_data->last_name, 222 'firstname' => $user_data->first_name 223 ); 224 225 return $struct; 226 } 227 228 229 /* blogger.getPost ...gets a post */ 230 function blogger_getPost($args) { 231 232 $this->escape($args); 233 234 $post_ID = $args[1]; 235 $user_login = $args[2]; 236 $user_pass = $args[3]; 237 238 if (!$this->login_pass_ok($user_login, $user_pass)) { 239 return $this->error; 240 } 241 242 $user_data = get_userdatabylogin($user_login); 243 $post_data = wp_get_single_post($post_ID, ARRAY_A); 244 245 $categories = implode(',', wp_get_post_categories($post_ID)); 246 247 $content = '<title>'.stripslashes($post_data['post_title']).'</title>'; 248 $content .= '<category>'.$categories.'</category>'; 249 $content .= stripslashes($post_data['post_content']); 250 251 $struct = array( 252 'userid' => $post_data['post_author'], 253 'dateCreated' => new IXR_Date(mysql2date('Ymd\TH:i:s', $post_data['post_date'])), 254 'content' => $content, 255 'postid' => $post_data['ID'] 256 ); 257 258 return $struct; 259 } 260 261 262 /* blogger.getRecentPosts ...gets recent posts */ 263 function blogger_getRecentPosts($args) { 264 265 global $wpdb; 266 267 $this->escape($args); 268 269 $blog_ID = $args[1]; /* though we don't use it yet */ 270 $user_login = $args[2]; 271 $user_pass = $args[3]; 272 $num_posts = $args[4]; 273 274 if (!$this->login_pass_ok($user_login, $user_pass)) { 275 return $this->error; 276 } 277 278 $posts_list = wp_get_recent_posts($num_posts); 279 280 if (!$posts_list) { 281 $this->error = new IXR_Error(500, 'Either there are no posts, or something went wrong.'); 282 return $this->error; 283 } 284 285 foreach ($posts_list as $entry) { 286 287 $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date']); 288 $categories = implode(',', wp_get_post_categories($entry['ID'])); 289 290 $content = '<title>'.stripslashes($entry['post_title']).'</title>'; 291 $content .= '<category>'.$categories.'</category>'; 292 $content .= stripslashes($entry['post_content']); 293 294 $struct[] = array( 295 'userid' => $entry['post_author'], 296 'dateCreated' => new IXR_Date($post_date), 297 'content' => $content, 298 'postid' => $entry['ID'], 299 ); 300 301 } 302 303 $recent_posts = array(); 304 for ($j=0; $j<count($struct); $j++) { 305 array_push($recent_posts, $struct[$j]); 306 } 307 308 return $recent_posts; 309 } 310 311 312 /* blogger.getTemplate returns your blog_filename */ 313 function blogger_getTemplate($args) { 314 315 $this->escape($args); 316 317 $blog_ID = $args[1]; 318 $user_login = $args[2]; 319 $user_pass = $args[3]; 320 $template = $args[4]; /* could be 'main' or 'archiveIndex', but we don't use it */ 321 322 if (!$this->login_pass_ok($user_login, $user_pass)) { 323 return $this->error; 324 } 325 326 set_current_user(0, $user_login); 327 if ( !current_user_can('edit_themes') ) { 328 return new IXR_Error(401, 'Sorry, this user can not edit the template.'); 329 } 330 331 /* warning: here we make the assumption that the weblog's URI is on the same server */ 332 $filename = get_settings('home') . '/'; 333 $filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename); 334 335 $f = fopen($filename, 'r'); 336 $content = fread($f, filesize($filename)); 337 fclose($f); 338 339 /* so it is actually editable with a windows/mac client */ 340 // 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); 341 342 return $content; 343 } 344 345 346 /* blogger.setTemplate updates the content of blog_filename */ 347 function blogger_setTemplate($args) { 348 349 $this->escape($args); 350 351 $blog_ID = $args[1]; 352 $user_login = $args[2]; 353 $user_pass = $args[3]; 354 $content = $args[4]; 355 $template = $args[5]; /* could be 'main' or 'archiveIndex', but we don't use it */ 356 357 if (!$this->login_pass_ok($user_login, $user_pass)) { 358 return $this->error; 359 } 360 361 set_current_user(0, $user_login); 362 if ( !current_user_can('edit_themes') ) { 363 return new IXR_Error(401, 'Sorry, this user can not edit the template.'); 364 } 365 366 /* warning: here we make the assumption that the weblog's URI is on the same server */ 367 $filename = get_settings('home') . '/'; 368 $filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename); 369 370 if ($f = fopen($filename, 'w+')) { 371 fwrite($f, $content); 372 fclose($f); 373 } else { 374 return new IXR_Error(500, 'Either the file is not writable, or something wrong happened. The file has not been updated.'); 375 } 376 377 return true; 378 } 379 380 381 /* blogger.newPost ...creates a new post */ 382 function blogger_newPost($args) { 383 384 global $wpdb; 385 386 $this->escape($args); 387 388 $blog_ID = $args[1]; /* though we don't use it yet */ 389 $user_login = $args[2]; 390 $user_pass = $args[3]; 391 $content = $args[4]; 392 $publish = $args[5]; 393 394 if (!$this->login_pass_ok($user_login, $user_pass)) { 395 return $this->error; 396 } 397 398 $cap = ($publish) ? 'publish_posts' : 'edit_posts'; 399 $user = set_current_user(0, $user_login); 400 if ( !current_user_can($cap) ) 401 return new IXR_Error(401, 'Sorry, you can not post on this weblog or category.'); 402 403 $post_status = ($publish) ? 'publish' : 'draft'; 404 405 $post_author = $user->ID; 406 407 $post_title = xmlrpc_getposttitle($content); 408 $post_category = xmlrpc_getpostcategory($content); 409 $post_content = xmlrpc_removepostdata($content); 410 411 $post_date = current_time('mysql'); 412 $post_date_gmt = current_time('mysql', 1); 413 414 $post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status'); 415 416 $post_ID = wp_insert_post($post_data); 417 418 if (!$post_ID) { 419 return new IXR_Error(500, 'Sorry, your entry could not be posted. Something wrong happened.'); 420 } 421 422 logIO('O', "Posted ! ID: $post_ID"); 423 424 return $post_ID; 425 } 426 427 428 /* blogger.editPost ...edits a post */ 429 function blogger_editPost($args) { 430 431 global $wpdb; 432 433 $this->escape($args); 434 435 $post_ID = $args[1]; 436 $user_login = $args[2]; 437 $user_pass = $args[3]; 438 $content = $args[4]; 439 $publish = $args[5]; 440 441 if (!$this->login_pass_ok($user_login, $user_pass)) { 442 return $this->error; 443 } 444 445 $actual_post = wp_get_single_post($post_ID,ARRAY_A); 446 447 if (!$actual_post) { 448 return new IXR_Error(404, 'Sorry, no such post.'); 449 } 450 451 $this->escape($actual_post); 452 453 set_current_user(0, $user_login); 454 if ( !current_user_can('edit_post', $post_ID) ) 455 return new IXR_Error(401, 'Sorry, you do not have the right to edit this post.'); 456 457 extract($actual_post); 458 459 $post_title = xmlrpc_getposttitle($content); 460 $post_category = xmlrpc_getpostcategory($content); 461 $post_content = xmlrpc_removepostdata($content); 462 463 $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt'); 464 465 $result = wp_update_post($postdata); 466 467 if (!$result) { 468 return new IXR_Error(500, 'For some strange yet very annoying reason, this post could not be edited.'); 469 } 470 471 return true; 472 } 473 474 475 /* blogger.deletePost ...deletes a post */ 476 function blogger_deletePost($args) { 477 478 global $wpdb; 479 480 $this->escape($args); 481 482 $post_ID = $args[1]; 483 $user_login = $args[2]; 484 $user_pass = $args[3]; 485 $publish = $args[4]; 486 487 if (!$this->login_pass_ok($user_login, $user_pass)) { 488 return $this->error; 489 } 490 491 $actual_post = wp_get_single_post($post_ID,ARRAY_A); 492 493 if (!$actual_post) { 494 return new IXR_Error(404, 'Sorry, no such post.'); 495 } 496 497 set_current_user(0, $user_login); 498 if ( !current_user_can('edit_post', $post_ID) ) 499 return new IXR_Error(401, 'Sorry, you do not have the right to delete this post.'); 500 501 $result = wp_delete_post($post_ID); 502 503 if (!$result) { 504 return new IXR_Error(500, 'For some strange yet very annoying reason, this post could not be deleted.'); 505 } 506 507 return true; 508 } 509 510 511 512 /* MetaWeblog API functions 513 * specs on wherever Dave Winer wants them to be 514 */ 515 516 /* metaweblog.newPost creates a post */ 517 function mw_newPost($args) { 518 519 global $wpdb, $post_default_category; 520 521 $this->escape($args); 522 523 $blog_ID = $args[0]; // we will support this in the near future 524 $user_login = $args[1]; 525 $user_pass = $args[2]; 526 $content_struct = $args[3]; 527 $publish = $args[4]; 528 529 if (!$this->login_pass_ok($user_login, $user_pass)) { 530 return $this->error; 531 } 532 533 $user = set_current_user(0, $user_login); 534 if ( !current_user_can('publish_posts') ) 535 return new IXR_Error(401, 'Sorry, you can not post on this weblog or category.'); 536 537 $post_author = $user->ID; 538 539 $post_title = $content_struct['title']; 540 $post_content = apply_filters( 'content_save_pre', $content_struct['description'] ); 541 $post_status = $publish ? 'publish' : 'draft'; 542 543 $post_excerpt = $content_struct['mt_excerpt']; 544 $post_more = $content_struct['mt_text_more']; 545 546 $comment_status = (empty($content_struct['mt_allow_comments'])) ? 547 get_settings('default_comment_status') 548 : $content_struct['mt_allow_comments']; 549 550 $ping_status = (empty($content_struct['mt_allow_pings'])) ? 551 get_settings('default_ping_status') 552 : $content_struct['mt_allow_pings']; 553 554 if ($post_more) { 555 $post_content = $post_content . "\n<!--more-->\n" . $post_more; 556 } 557 558 $to_ping = $content_struct['mt_tb_ping_urls']; 559 560 // Do some timestamp voodoo 561 $dateCreatedd = $content_struct['dateCreated']; 562 if (!empty($dateCreatedd)) { 563 $dateCreated = $dateCreatedd->getIso(); 564 $post_date = get_date_from_gmt(iso8601_to_datetime($dateCreated)); 565 $post_date_gmt = iso8601_to_datetime($dateCreated, GMT); 566 } else { 567 $post_date = current_time('mysql'); 568 $post_date_gmt = current_time('mysql', 1); 569 } 570 571 $catnames = $content_struct['categories']; 572 logIO('O', 'Post cats: ' . printr($catnames,true)); 573 $post_category = array(); 574 575 if (is_array($catnames)) { 576 foreach ($catnames as $cat) { 577 $post_category[] = get_cat_ID($cat); 578 } 579 } 580 581 // We've got all the data -- post it: 582 $postdata = compact('post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'comment_status', 'ping_status', 'to_ping'); 583 584 $post_ID = wp_insert_post($postdata); 585 586 if (!$post_ID) { 587 return new IXR_Error(500, 'Sorry, your entry could not be posted. Something wrong happened.'); 588 } 589 590 logIO('O', "Posted ! ID: $post_ID"); 591 592 return strval($post_ID); 593 } 594 595 596 /* metaweblog.editPost ...edits a post */ 597 function mw_editPost($args) { 598 599 global $wpdb, $post_default_category; 600 601 $this->escape($args); 602 603 $post_ID = $args[0]; 604 $user_login = $args[1]; 605 $user_pass = $args[2]; 606 $content_struct = $args[3]; 607 $publish = $args[4]; 608 609 if (!$this->login_pass_ok($user_login, $user_pass)) { 610 return $this->error; 611 } 612 613 set_current_user(0, $user_login); 614 if ( !current_user_can('edit_post', $post_ID) ) 615 return new IXR_Error(401, 'Sorry, you can not edit this post.'); 616 617 $postdata = wp_get_single_post($post_ID, ARRAY_A); 618 extract($postdata); 619 $this->escape($postdata); 620 621 $post_title = $content_struct['title']; 622 $post_content = apply_filters( 'content_save_pre', $content_struct['description'] ); 623 $catnames = $content_struct['categories']; 624 625 $post_category = array(); 626 627 if (is_array($catnames)) { 628 foreach ($catnames as $cat) { 629 $post_category[] = get_cat_ID($cat); 630 } 631 } 632 633 $post_excerpt = $content_struct['mt_excerpt']; 634 $post_more = $content_struct['mt_text_more']; 635 $post_status = $publish ? 'publish' : 'draft'; 636 637 if ($post_more) { 638 $post_content = $post_content . "\n<!--more-->\n" . $post_more; 639 } 640 641 $to_ping = $content_struct['mt_tb_ping_urls']; 642 643 $comment_status = (empty($content_struct['mt_allow_comments'])) ? 644 get_settings('default_comment_status') 645 : $content_struct['mt_allow_comments']; 646 647 $ping_status = (empty($content_struct['mt_allow_pings'])) ? 648 get_settings('default_ping_status') 649 : $content_struct['mt_allow_pings']; 650 651 // Do some timestamp voodoo 652 $dateCreatedd = $content_struct['dateCreated']; 653 if (!empty($dateCreatedd)) { 654 $dateCreated = $dateCreatedd->getIso(); 655 $post_date = get_date_from_gmt(iso8601_to_datetime($dateCreated)); 656 $post_date_gmt = iso8601_to_datetime($dateCreated, GMT); 657 } else { 658 $post_date = $postdata['post_date']; 659 $post_date_gmt = $postdata['post_date_gmt']; 660 } 661 662 // We've got all the data -- post it: 663 $newpost = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'comment_status', 'ping_status', 'post_date', 'post_date_gmt', 'to_ping'); 664 665 $result = wp_update_post($newpost); 666 if (!$result) { 667 return new IXR_Error(500, 'Sorry, your entry could not be edited. Something wrong happened.'); 668 } 669 670 logIO('O',"(MW) Edited ! ID: $post_ID"); 671 672 return true; 673 } 674 675 676 /* metaweblog.getPost ...returns a post */ 677 function mw_getPost($args) { 678 679 global $wpdb; 680 681 $this->escape($args); 682 683 $post_ID = $args[0]; 684 $user_login = $args[1]; 685 $user_pass = $args[2]; 686 687 if (!$this->login_pass_ok($user_login, $user_pass)) { 688 return $this->error; 689 } 690 691 $postdata = wp_get_single_post($post_ID, ARRAY_A); 692 693 if ($postdata['post_date'] != '') { 694 695 $post_date = mysql2date('Ymd\TH:i:s', $postdata['post_date']); 696 697 $categories = array(); 698 $catids = wp_get_post_categories($post_ID); 699 foreach($catids as $catid) { 700 $categories[] = get_cat_name($catid); 701 } 702 703 $post = get_extended($postdata['post_content']); 704 $link = post_permalink($postdata['ID']); 705 706 $allow_comments = ('open' == $postdata['comment_status']) ? 1 : 0; 707 $allow_pings = ('open' == $postdata['ping_status']) ? 1 : 0; 708 709 $resp = array( 710 'dateCreated' => new IXR_Date($post_date), 711 'userid' => $postdata['post_author'], 712 'postid' => $postdata['ID'], 713 'description' => $post['main'], 714 'title' => $postdata['post_title'], 715 'link' => $link, 716 'permaLink' => $link, 717 // commented out because no other tool seems to use this 718 // 'content' => $entry['post_content'], 719 'categories' => $categories, 720 'mt_excerpt' => $postdata['post_excerpt'], 721 'mt_text_more' => $post['extended'], 722 'mt_allow_comments' => $allow_comments, 723 'mt_allow_pings' => $allow_pings 724 ); 725 726 return $resp; 727 } else { 728 return new IXR_Error(404, 'Sorry, no such post.'); 729 } 730 } 731 732 733 /* metaweblog.getRecentPosts ...returns recent posts */ 734 function mw_getRecentPosts($args) { 735 736 $this->escape($args); 737 738 $blog_ID = $args[0]; 739 $user_login = $args[1]; 740 $user_pass = $args[2]; 741 $num_posts = $args[3]; 742 743 if (!$this->login_pass_ok($user_login, $user_pass)) { 744 return $this->error; 745 } 746 747 $posts_list = wp_get_recent_posts($num_posts); 748 749 if (!$posts_list) { 750 $this->error = new IXR_Error(500, 'Either there are no posts, or something went wrong.'); 751 return $this->error; 752 } 753 754 foreach ($posts_list as $entry) { 755 756 $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date']); 757 $categories = array(); 758 $catids = wp_get_post_categories($entry['ID']); 759 foreach($catids as $catid) { 760 $categories[] = get_cat_name($catid); 761 } 762 763 $post = get_extended($entry['post_content']); 764 $link = post_permalink($entry['ID']); 765 766 $allow_comments = ('open' == $entry['comment_status']) ? 1 : 0; 767 $allow_pings = ('open' == $entry['ping_status']) ? 1 : 0; 768 769 $struct[] = array( 770 'dateCreated' => new IXR_Date($post_date), 771 'userid' => $entry['post_author'], 772 'postid' => $entry['ID'], 773 'description' => $post['main'], 774 'title' => $entry['post_title'], 775 'link' => $link, 776 'permaLink' => $link, 777 // commented out because no other tool seems to use this 778 // 'content' => $entry['post_content'], 779 'categories' => $categories, 780 'mt_excerpt' => $entry['post_excerpt'], 781 'mt_text_more' => $post['extended'], 782 'mt_allow_comments' => $allow_comments, 783 'mt_allow_pings' => $allow_pings 784 ); 785 786 } 787 788 $recent_posts = array(); 789 for ($j=0; $j<count($struct); $j++) { 790 array_push($recent_posts, $struct[$j]); 791 } 792 793 return $recent_posts; 794 } 795 796 797 /* metaweblog.getCategories ...returns the list of categories on a given weblog */ 798 function mw_getCategories($args) { 799 800 global $wpdb; 801 802 $this->escape($args); 803 804 $blog_ID = $args[0]; 805 $user_login = $args[1]; 806 $user_pass = $args[2]; 807 808 if (!$this->login_pass_ok($user_login, $user_pass)) { 809 return $this->error; 810 } 811 812 $categories_struct = array(); 813 814 // FIXME: can we avoid using direct SQL there? 815 if ($cats = $wpdb->get_results("SELECT cat_ID,cat_name FROM $wpdb->categories", ARRAY_A)) { 816 foreach ($cats as $cat) { 817 $struct['categoryId'] = $cat['cat_ID']; 818 $struct['description'] = $cat['cat_name']; 819 $struct['categoryName'] = $cat['cat_name']; 820 $struct['htmlUrl'] = wp_specialchars(get_category_link($cat['cat_ID'])); 821 $struct['rssUrl'] = wp_specialchars(get_category_rss_link(false, $cat['cat_ID'], $cat['cat_name'])); 822 823 $categories_struct[] = $struct; 824 } 825 } 826 827 return $categories_struct; 828 } 829 830 831 /* metaweblog.newMediaObject uploads a file, following your settings */ 832 function mw_newMediaObject($args) { 833 // adapted from a patch by Johann Richard 834 // http://mycvs.org/archives/2004/06/30/file-upload-to-wordpress-in-ecto/ 835 836 global $wpdb; 837 838 $blog_ID = $wpdb->escape($args[0]); 839 $user_login = $wpdb->escape($args[1]); 840 $user_pass = $wpdb->escape($args[2]); 841 $data = $args[3]; 842 843 $name = $data['name']; 844 $type = $data['type']; 845 $bits = $data['bits']; 846 847 logIO('O', '(MW) Received '.strlen($bits).' bytes'); 848 849 if ( !$this->login_pass_ok($user_login, $user_pass) ) 850 return $this->error; 851 852 set_current_user(0, $user_login); 853 if ( !current_user_can('upload_files') ) { 854 logIO('O', '(MW) User does not have upload_files capability'); 855 $this->error = new IXR_Error(401, 'You are not allowed to upload files to this site.'); 856 return $this->error; 857 } 858 859 $upload = wp_upload_bits($name, $type, $bits); 860 if ( ! empty($upload['error']) ) { 861 logIO('O', '(MW) Could not write file '.$name); 862 return new IXR_Error(500, 'Could not write file '.$name); 863 } 864 865 return array('url' => $upload['url']); 866 } 867 868 869 /* MovableType API functions 870 * specs on http://www.movabletype.org/docs/mtmanual_programmatic.html 871 */ 872 873 /* mt.getRecentPostTitles ...returns recent posts' titles */ 874 function mt_getRecentPostTitles($args) { 875 876 $this->escape($args); 877 878 $blog_ID = $args[0]; 879 $user_login = $args[1]; 880 $user_pass = $args[2]; 881 $num_posts = $args[3]; 882 883 if (!$this->login_pass_ok($user_login, $user_pass)) { 884 return $this->error; 885 } 886 887 $posts_list = wp_get_recent_posts($num_posts); 888 889 if (!$posts_list) { 890 $this->error = new IXR_Error(500, 'Either there are no posts, or something went wrong.'); 891 return $this->error; 892 } 893 894 foreach ($posts_list as $entry) { 895 896 $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date']); 897 898 $struct[] = array( 899 'dateCreated' => new IXR_Date($post_date), 900 'userid' => $entry['post_author'], 901 'postid' => $entry['ID'], 902 'title' => $entry['post_title'], 903 ); 904 905 } 906 907 $recent_posts = array(); 908 for ($j=0; $j<count($struct); $j++) { 909 array_push($recent_posts, $struct[$j]); 910 } 911 912 return $recent_posts; 913 } 914 915 916 /* mt.getCategoryList ...returns the list of categories on a given weblog */ 917 function mt_getCategoryList($args) { 918 919 global $wpdb; 920 921 $this->escape($args); 922 923 $blog_ID = $args[0]; 924 $user_login = $args[1]; 925 $user_pass = $args[2]; 926 927 if (!$this->login_pass_ok($user_login, $user_pass)) { 928 return $this->error; 929 } 930 931 $categories_struct = array(); 932 933 // FIXME: can we avoid using direct SQL there? 934 if ($cats = $wpdb->get_results("SELECT cat_ID, cat_name FROM $wpdb->categories", ARRAY_A)) { 935 foreach ($cats as $cat) { 936 $struct['categoryId'] = $cat['cat_ID']; 937 $struct['categoryName'] = $cat['cat_name']; 938 939 $categories_struct[] = $struct; 940 } 941 } 942 943 return $categories_struct; 944 } 945 946 947 /* mt.getPostCategories ...returns a post's categories */ 948 function mt_getPostCategories($args) { 949 950 $this->escape($args); 951 952 $post_ID = $args[0]; 953 $user_login = $args[1]; 954 $user_pass = $args[2]; 955 956 if (!$this->login_pass_ok($user_login, $user_pass)) { 957 return $this->error; 958 } 959 960 $categories = array(); 961 $catids = wp_get_post_categories(intval($post_ID)); 962 // first listed category will be the primary category 963 $isPrimary = true; 964 foreach($catids as $catid) { 965 $categories[] = array( 966 'categoryName' => get_cat_name($catid), 967 'categoryId' => $catid, 968 'isPrimary' => $isPrimary 969 ); 970 $isPrimary = false; 971 } 972 973 return $categories; 974 } 975 976 977 /* mt.setPostCategories ...sets a post's categories */ 978 function mt_setPostCategories($args) { 979 980 $this->escape($args); 981 982 $post_ID = $args[0]; 983 $user_login = $args[1]; 984 $user_pass = $args[2]; 985 $categories = $args[3]; 986 987 if (!$this->login_pass_ok($user_login, $user_pass)) { 988 return $this->error; 989 } 990 991 set_current_user(0, $user_login); 992 if ( !current_user_can('edit_post', $post_ID) ) 993 return new IXR_Error(401, 'Sorry, you can not edit this post.'); 994 995 foreach($categories as $cat) { 996 $catids[] = $cat['categoryId']; 997 } 998 999 wp_set_post_categories($post_ID, $catids); 1000 1001 return true; 1002 } 1003 1004 1005 /* mt.supportedMethods ...returns an array of methods supported by this server */ 1006 function mt_supportedMethods($args) { 1007 1008 $supported_methods = array(); 1009 foreach($this->methods as $key=>$value) { 1010 $supported_methods[] = $key; 1011 } 1012 1013 return $supported_methods; 1014 } 1015 1016 1017 /* mt.supportedTextFilters ...returns an empty array because we don't 1018 support per-post text filters yet */ 1019 function mt_supportedTextFilters($args) { 1020 return array(); 1021 } 1022 1023 1024 /* mt.getTrackbackPings ...returns trackbacks sent to a given post */ 1025 function mt_getTrackbackPings($args) { 1026 1027 global $wpdb; 1028 1029 $post_ID = intval($args); 1030 1031 $actual_post = wp_get_single_post($post_ID, ARRAY_A); 1032 1033 if (!$actual_post) { 1034 return new IXR_Error(404, 'Sorry, no such post.'); 1035 } 1036 1037 $comments = $wpdb->get_results("SELECT comment_author_url, comment_content, comment_author_IP, comment_type FROM $wpdb->comments WHERE comment_post_ID = $post_ID"); 1038 1039 if (!$comments) { 1040 return array(); 1041 } 1042 1043 $trackback_pings = array(); 1044 foreach($comments as $comment) { 1045 if ( 'trackback' == $comment->comment_type ) { 1046 $content = $comment->comment_content; 1047 $title = substr($content, 8, (strpos($content, '</strong>') - 8)); 1048 $trackback_pings[] = array( 1049 'pingTitle' => $title, 1050 'pingURL' => $comment->comment_author_url, 1051 'pingIP' => $comment->comment_author_IP 1052 ); 1053 } 1054 } 1055 1056 return $trackback_pings; 1057 } 1058 1059 1060 /* mt.publishPost ...sets a post's publish status to 'publish' */ 1061 function mt_publishPost($args) { 1062 1063 $this->escape($args); 1064 1065 $post_ID = $args[0]; 1066 $user_login = $args[1]; 1067 $user_pass = $args[2]; 1068 1069 if (!$this->login_pass_ok($user_login, $user_pass)) { 1070 return $this->error; 1071 } 1072 1073 set_current_user(0, $user_login); 1074 if ( !current_user_can('edit_post', $post_ID) ) 1075 return new IXR_Error(401, 'Sorry, you can not edit this post.'); 1076 1077 $postdata = wp_get_single_post($post_ID,ARRAY_A); 1078 1079 $postdata['post_status'] = 'publish'; 1080 1081 // retain old cats 1082 $cats = wp_get_post_categories($post_ID); 1083 $postdata['post_category'] = $cats; 1084 $this->escape($postdata); 1085 1086 $result = wp_update_post($postdata); 1087 1088 return $result; 1089 } 1090 1091 1092 1093 /* PingBack functions 1094 * specs on www.hixie.ch/specs/pingback/pingback 1095 */ 1096 1097 /* pingback.ping gets a pingback and registers it */ 1098 function pingback_ping($args) { 1099 global $wpdb, $wp_version; 1100 1101 $this->escape($args); 1102 1103 $pagelinkedfrom = $args[0]; 1104 $pagelinkedto = $args[1]; 1105 1106 $title = ''; 1107 1108 $pagelinkedfrom = str_replace('&', '&', $pagelinkedfrom); 1109 $pagelinkedto = preg_replace('#&([^amp\;])#is', '&$1', $pagelinkedto); 1110 1111 $error_code = -1; 1112 1113 // Check if the page linked to is in our site 1114 $pos1 = strpos($pagelinkedto, str_replace(array('http://www.','http://','https://www.','https://'), '', get_settings('home'))); 1115 if( !$pos1 ) 1116 return new IXR_Error(0, 'Is there no link to us?'); 1117 1118 // let's find which post is linked to 1119 // FIXME: does url_to_postid() cover all these cases already? 1120 // if so, then let's use it and drop the old code. 1121 $urltest = parse_url($pagelinkedto); 1122 if ($post_ID = url_to_postid($pagelinkedto)) { 1123 $way = 'url_to_postid()'; 1124 } elseif (preg_match('#p/[0-9]{1,}#', $urltest['path'], $match)) { 1125 // the path defines the post_ID (archives/p/XXXX) 1126 $blah = explode('/', $match[0]); 1127 $post_ID = $blah[1]; 1128 $way = 'from the path'; 1129 } elseif (preg_match('#p=[0-9]{1,}#', $urltest['query'], $match)) { 1130 // the querystring defines the post_ID (?p=XXXX) 1131 $blah = explode('=', $match[0]); 1132 $post_ID = $blah[1]; 1133 $way = 'from the querystring'; 1134 } elseif (isset($urltest['fragment'])) { 1135 // an #anchor is there, it's either... 1136 if (intval($urltest['fragment'])) { 1137 // ...an integer #XXXX (simpliest case) 1138 $post_ID = $urltest['fragment']; 1139 $way = 'from the fragment (numeric)'; 1140 } elseif (preg_match('/post-[0-9]+/',$urltest['fragment'])) { 1141 // ...a post id in the form 'post-###' 1142 $post_ID = preg_replace('/[^0-9]+/', '', $urltest['fragment']); 1143 $way = 'from the fragment (post-###)'; 1144 } elseif (is_string($urltest['fragment'])) { 1145 // ...or a string #title, a little more complicated 1146 $title = preg_replace('/[^a-z0-9]/i', '.', $urltest['fragment']); 1147 $sql = "SELECT ID FROM $wpdb->posts WHERE post_title RLIKE '$title'"; 1148 if (! ($post_ID = $wpdb->get_var($sql)) ) { 1149 // returning unknown error '0' is better than die()ing 1150 return new IXR_Error(0, ''); 1151 } 1152 $way = 'from the fragment (title)'; 1153 } 1154 } else { 1155 // TODO: Attempt to extract a post ID from the given URL 1156 return new IXR_Error(33, 'The specified target URI cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.'); 1157 } 1158 $post_ID = (int) $post_ID; 1159 1160 1161 logIO("O","(PB) URI='$pagelinkedto' ID='$post_ID' Found='$way'"); 1162 1163 $post = get_post($post_ID); 1164 1165 if ( !$post ) // Post_ID not found 1166 return new IXR_Error(33, 'The specified target URI cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.'); 1167 1168 if ( $post_ID == url_to_postid($pagelinkedfrom) ) 1169 return new IXR_Error(0, 'The source URI and the target URI cannot both point to the same resource.'); 1170 1171 // Check if pings are on 1172 if ( 'closed' == $post->ping_status ) 1173 return new IXR_Error(33, 'The specified target URI cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.'); 1174 1175 // Let's check that the remote site didn't already pingback this entry 1176 $result = $wpdb->get_results("SELECT * FROM $wpdb->comments WHERE comment_post_ID = '$post_ID' AND comment_author_url = '$pagelinkedfrom'"); 1177 1178 if ( $wpdb->num_rows ) // We already have a Pingback from this URL 1179 return new IXR_Error(48, 'The pingback has already been registered.'); 1180 1181 // very stupid, but gives time to the 'from' server to publish ! 1182 sleep(1); 1183 1184 // Let's check the remote site 1185 $linea = wp_remote_fopen( $pagelinkedfrom ); 1186 if ( !$linea ) 1187 return new IXR_Error(16, 'The source URI does not exist.'); 1188 1189 // Work around bug in strip_tags(): 1190 $linea = str_replace('<!DOC', '<DOC', $linea); 1191 $linea = preg_replace( '/[\s\r\n\t]+/', ' ', $linea ); // normalize spaces 1192 $linea = preg_replace( "/ <(h1|h2|h3|h4|h5|h6|p|th|td|li|dt|dd|pre|caption|input|textarea|button|body)[^>]*>/", "\n\n", $linea ); 1193 1194 preg_match('|<title>([^<]*?)</title>|is', $linea, $matchtitle); 1195 $title = $matchtitle[1]; 1196 if ( empty( $title ) ) 1197 return new IXR_Error(32, 'We cannot find a title on that page.'); 1198 1199 $linea = strip_tags( $linea, '<a>' ); // just keep the tag we need 1200 1201 $p = explode( "\n\n", $linea ); 1202 1203 $sem_regexp_pb = "/(\\/|\\\|\*|\?|\+|\.|\^|\\$|\(|\)|\[|\]|\||\{|\})/"; 1204 $sem_regexp_fix = "\\\\$1"; 1205 $link = preg_replace( $sem_regexp_pb, $sem_regexp_fix, $pagelinkedfrom ); 1206 1207 $finished = false; 1208 foreach ( $p as $para ) { 1209 if ( $finished ) 1210 continue; 1211 if ( strstr( $para, $pagelinkedto ) ) { 1212 $context = preg_replace( "/.*<a[^>]+".$link."[^>]*>([^>]+)<\/a>.*/", "$1", $para ); 1213 $excerpt = strip_tags( $para ); 1214 $excerpt = trim( $excerpt ); 1215 $use = preg_quote( $context ); 1216 $excerpt = preg_replace("|.*?\s(.{0,100}$use.{0,100})\s|s", "$1", $excerpt); 1217 $finished = true; 1218 } 1219 } 1220 1221 if ( empty($context) ) // URL pattern not found 1222 return new IXR_Error(17, 'The source URI does not contain a link to the target URI, and so cannot be used as a source.'); 1223 1224 $pagelinkedfrom = preg_replace('#&([^amp\;])#is', '&$1', $pagelinkedfrom); 1225 1226 $context = '[...] ' . wp_specialchars( $excerpt ) . ' [...]'; 1227 $original_pagelinkedfrom = $pagelinkedfrom; 1228 $pagelinkedfrom = $wpdb->escape( $pagelinkedfrom ); 1229 $original_title = $title; 1230 1231 $comment_post_ID = $post_ID; 1232 $comment_author = $title; 1233 $comment_author_url = $pagelinkedfrom; 1234 $comment_content = $context; 1235 $comment_type = 'pingback'; 1236 1237 $commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_url', 'comment_content', 'comment_type'); 1238 1239 wp_new_comment($commentdata); 1240 do_action('pingback_post', $wpdb->insert_id); 1241 1242 return "Pingback from $pagelinkedfrom to $pagelinkedto registered. Keep the web talking! :-)"; 1243 } 1244 1245 1246 /* pingback.extensions.getPingbacks returns an array of URLs 1247 that pingbacked the given URL 1248 specs on http://www.aquarionics.com/misc/archives/blogite/0198.html */ 1249 function pingback_extensions_getPingbacks($args) { 1250 1251 global $wpdb; 1252 1253 $this->escape($args); 1254 1255 $url = $args; 1256 1257 $post_ID = url_to_postid($url); 1258 if (!$post_ID) { 1259 // We aren't sure that the resource is available and/or pingback enabled 1260 return new IXR_Error(33, 'The specified target URI cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.'); 1261 } 1262 1263 $actual_post = wp_get_single_post($post_ID, ARRAY_A); 1264 1265 if (!$actual_post) { 1266 // No such post = resource not found 1267 return new IXR_Error(32, 'The specified target URI does not exist.'); 1268 } 1269 1270 $comments = $wpdb->get_results("SELECT comment_author_url, comment_content, comment_author_IP, comment_type FROM $wpdb->comments WHERE comment_post_ID = $post_ID"); 1271 1272 if (!$comments) { 1273 return array(); 1274 } 1275 1276 $pingbacks = array(); 1277 foreach($comments as $comment) { 1278 if ( 'pingback' == $comment->comment_type ) 1279 $pingbacks[] = $comment->comment_author_url; 1280 } 1281 1282 return $pingbacks; 1283 } 1284 } 1285 1286 1287 $wp_xmlrpc_server = new wp_xmlrpc_server(); 1288 1289 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Sat Jul 15 11:57:04 2006 | Courtesy of Taragana |