PHP Cross Reference of WordPress Subversion HEAD

[ Index ]     [ Classes ]     [ Functions ]     [ Variables ]     [ Constants ]

title

Body

[close]

/ -> xmlrpc.php (source)

   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  // A bug in PHP < 5.2.2 makes $HTTP_RAW_POST_DATA not set by default,
   9  // but we can do it ourself.
  10  if ( !isset( $HTTP_RAW_POST_DATA ) ) {
  11      $HTTP_RAW_POST_DATA = file_get_contents( 'php://input' );
  12  }
  13  
  14  # fix for mozBlog and other cases where '<?xml' isn't on the very first line
  15  if ( isset($HTTP_RAW_POST_DATA) )
  16      $HTTP_RAW_POST_DATA = trim($HTTP_RAW_POST_DATA);
  17  
  18  include('./wp-config.php');
  19  
  20  if ( isset( $_GET['rsd'] ) ) { // http://archipelago.phrasewise.com/rsd
  21  header('Content-Type: text/xml; charset=' . get_option('blog_charset'), true);
  22  ?>
  23  <?php echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>'; ?>
  24  <rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd">
  25    <service>
  26      <engineName>WordPress</engineName>
  27      <engineLink>http://wordpress.org/</engineLink>
  28      <homePageLink><?php bloginfo_rss('url') ?></homePageLink>
  29      <apis>
  30        <api name="WordPress" blogID="1" preferred="true" apiLink="<?php bloginfo_rss('wpurl') ?>/xmlrpc.php" />
  31        <api name="Movable Type" blogID="1" preferred="false" apiLink="<?php bloginfo_rss('wpurl') ?>/xmlrpc.php" />
  32        <api name="MetaWeblog" blogID="1" preferred="false" apiLink="<?php bloginfo_rss('wpurl') ?>/xmlrpc.php" />
  33        <api name="Blogger" blogID="1" preferred="false" apiLink="<?php bloginfo_rss('wpurl') ?>/xmlrpc.php" />
  34        <api name="Atom" blogID="" preferred="false" apiLink="<?php echo apply_filters('atom_service_url', (get_bloginfo('url')."/wp-app.php/service"))?>" /> 
  35      </apis>
  36    </service>
  37  </rsd>
  38  <?php
  39  exit;
  40  }
  41  
  42  include_once (ABSPATH . 'wp-admin/includes/admin.php');
  43  include_once (ABSPATH . WPINC . '/class-IXR.php');
  44  
  45  // Turn off all warnings and errors.
  46  // error_reporting(0);
  47  
  48  $post_default_title = ""; // posts submitted via the xmlrpc interface get that title
  49  
  50  $xmlrpc_logging = 0;
  51  
  52  function logIO($io,$msg) {
  53      global $xmlrpc_logging;
  54      if ($xmlrpc_logging) {
  55          $fp = fopen("../xmlrpc.log","a+");
  56          $date = gmdate("Y-m-d H:i:s ");
  57          $iot = ($io == "I") ? " Input: " : " Output: ";
  58          fwrite($fp, "\n\n".$date.$iot.$msg);
  59          fclose($fp);
  60      }
  61      return true;
  62      }
  63  
  64  function starify($string) {
  65      $i = strlen($string);
  66      return str_repeat('*', $i);
  67  }
  68  
  69  if ( isset($HTTP_RAW_POST_DATA) )
  70    logIO("I", $HTTP_RAW_POST_DATA);
  71  
  72  
  73  class wp_xmlrpc_server extends IXR_Server {
  74  
  75  	function wp_xmlrpc_server() {
  76          $this->methods = array(
  77              // WordPress API
  78              'wp.getPage'            => 'this:wp_getPage',
  79              'wp.getPages'            => 'this:wp_getPages',
  80              'wp.newPage'            => 'this:wp_newPage',
  81              'wp.deletePage'            => 'this:wp_deletePage',
  82              'wp.editPage'            => 'this:wp_editPage',
  83              'wp.getPageList'        => 'this:wp_getPageList',
  84              'wp.getAuthors'            => 'this:wp_getAuthors',
  85              'wp.getCategories'        => 'this:mw_getCategories',        // Alias
  86              'wp.newCategory'        => 'this:wp_newCategory',
  87              'wp.suggestCategories'    => 'this:wp_suggestCategories',
  88              'wp.uploadFile'            => 'this:mw_newMediaObject',    // Alias
  89  
  90              // Blogger API
  91              'blogger.getUsersBlogs' => 'this:blogger_getUsersBlogs',
  92              'blogger.getUserInfo' => 'this:blogger_getUserInfo',
  93              'blogger.getPost' => 'this:blogger_getPost',
  94              'blogger.getRecentPosts' => 'this:blogger_getRecentPosts',
  95              'blogger.getTemplate' => 'this:blogger_getTemplate',
  96              'blogger.setTemplate' => 'this:blogger_setTemplate',
  97              'blogger.newPost' => 'this:blogger_newPost',
  98              'blogger.editPost' => 'this:blogger_editPost',
  99              'blogger.deletePost' => 'this:blogger_deletePost',
 100  
 101              // MetaWeblog API (with MT extensions to structs)
 102              'metaWeblog.newPost' => 'this:mw_newPost',
 103              'metaWeblog.editPost' => 'this:mw_editPost',
 104              'metaWeblog.getPost' => 'this:mw_getPost',
 105              'metaWeblog.getRecentPosts' => 'this:mw_getRecentPosts',
 106              'metaWeblog.getCategories' => 'this:mw_getCategories',
 107              'metaWeblog.newMediaObject' => 'this:mw_newMediaObject',
 108  
 109              // MetaWeblog API aliases for Blogger API
 110              // see http://www.xmlrpc.com/stories/storyReader$2460
 111              'metaWeblog.deletePost' => 'this:blogger_deletePost',
 112              'metaWeblog.getTemplate' => 'this:blogger_getTemplate',
 113              'metaWeblog.setTemplate' => 'this:blogger_setTemplate',
 114              'metaWeblog.getUsersBlogs' => 'this:blogger_getUsersBlogs',
 115  
 116              // MovableType API
 117              'mt.getCategoryList' => 'this:mt_getCategoryList',
 118              'mt.getRecentPostTitles' => 'this:mt_getRecentPostTitles',
 119              'mt.getPostCategories' => 'this:mt_getPostCategories',
 120              'mt.setPostCategories' => 'this:mt_setPostCategories',
 121              'mt.supportedMethods' => 'this:mt_supportedMethods',
 122              'mt.supportedTextFilters' => 'this:mt_supportedTextFilters',
 123              'mt.getTrackbackPings' => 'this:mt_getTrackbackPings',
 124              'mt.publishPost' => 'this:mt_publishPost',
 125  
 126              // PingBack
 127              'pingback.ping' => 'this:pingback_ping',
 128              'pingback.extensions.getPingbacks' => 'this:pingback_extensions_getPingbacks',
 129  
 130              'demo.sayHello' => 'this:sayHello',
 131              'demo.addTwoNumbers' => 'this:addTwoNumbers'
 132          );
 133          $this->methods = apply_filters('xmlrpc_methods', $this->methods);
 134          $this->IXR_Server($this->methods);
 135      }
 136  
 137  	function sayHello($args) {
 138          return 'Hello!';
 139      }
 140  
 141  	function addTwoNumbers($args) {
 142          $number1 = $args[0];
 143          $number2 = $args[1];
 144          return $number1 + $number2;
 145      }
 146  
 147  	function login_pass_ok($user_login, $user_pass) {
 148          if (!user_pass_ok($user_login, $user_pass)) {
 149              $this->error = new IXR_Error(403, __('Bad login/pass combination.'));
 150              return false;
 151          }
 152          return true;
 153      }
 154  
 155  	function escape(&$array) {
 156          global $wpdb;
 157  
 158          if(!is_array($array)) {
 159              return($wpdb->escape($array));
 160          }
 161          else {
 162              foreach ( (array) $array as $k => $v ) {
 163                  if (is_array($v)) {
 164                      $this->escape($array[$k]);
 165                  } else if (is_object($v)) {
 166                      //skip
 167                  } else {
 168                      $array[$k] = $wpdb->escape($v);
 169                  }
 170              }
 171          }
 172      }
 173  
 174      /**
 175       * WordPress XML-RPC API
 176       * wp_getPage
 177       */
 178  	function wp_getPage($args) {
 179          $this->escape($args);
 180  
 181          $blog_id    = (int) $args[0];
 182          $page_id    = (int) $args[1];
 183          $username    = $args[2];
 184          $password    = $args[3];
 185  
 186          if(!$this->login_pass_ok($username, $password)) {
 187              return($this->error);
 188          }
 189  
 190          // Lookup page info.
 191          $page = get_page($page_id);
 192  
 193          // If we found the page then format the data.
 194          if($page->ID && ($page->post_type == "page")) {
 195              // Get all of the page content and link.
 196              $full_page = get_extended($page->post_content);
 197              $link = post_permalink($page->ID);
 198  
 199              // Get info the page parent if there is one.
 200              $parent_title = "";
 201              if(!empty($page->post_parent)) {
 202                  $parent = get_page($page->post_parent);
 203                  $parent_title = $parent->post_title;
 204              }
 205  
 206              // Determine comment and ping settings.
 207              $allow_comments = ("open" == $page->comment_status) ? 1 : 0;
 208              $allow_pings = ("open" == $page->ping_status) ? 1 : 0;
 209  
 210              // Format page date.
 211              $page_date = mysql2date("Ymd\TH:i:s", $page->post_date);
 212              $page_date_gmt = mysql2date("Ymd\TH:i:s", $page->post_date_gmt);
 213  
 214              // Pull the categories info together.
 215              $categories = array();
 216              foreach(wp_get_post_categories($page->ID) as $cat_id) {
 217                  $categories[] = get_cat_name($cat_id);
 218              }
 219  
 220              // Get the author info.
 221              $author = get_userdata($page->post_author);
 222  
 223              $page_struct = array(
 224                  "dateCreated"            => new IXR_Date($page_date),
 225                  "userid"                => $page->post_author,
 226                  "page_id"                => $page->ID,
 227                  "page_status"            => $page->post_status,
 228                  "description"            => $full_page["main"],
 229                  "title"                    => $page->post_title,
 230                  "link"                    => $link,
 231                  "permaLink"                => $link,
 232                  "categories"            => $categories,
 233                  "excerpt"                => $page->post_excerpt,
 234                  "text_more"                => $full_page["extended"],
 235                  "mt_allow_comments"        => $allow_comments,
 236                  "mt_allow_pings"        => $allow_pings,
 237                  "wp_slug"                => $page->post_name,
 238                  "wp_password"            => $page->post_password,
 239                  "wp_author"                => $author->display_name,
 240                  "wp_page_parent_id"        => $page->post_parent,
 241                  "wp_page_parent_title"    => $parent_title,
 242                  "wp_page_order"            => $page->menu_order,
 243                  "wp_author_id"            => $author->ID,
 244                  "wp_author_display_name"    => $author->display_name,
 245                  "date_created_gmt"        => new IXR_Date($page_date_gmt)
 246              );
 247  
 248              return($page_struct);
 249          }
 250          // If the page doesn't exist indicate that.
 251          else {
 252              return(new IXR_Error(404, __("Sorry, no such page.")));
 253          }
 254      }
 255  
 256      /**
 257       * WordPress XML-RPC API
 258        * wp_getPages
 259       */
 260  	function wp_getPages($args) {
 261          $this->escape($args);
 262  
 263          $blog_id    = (int) $args[0];
 264          $username    = $args[1];
 265          $password    = $args[2];
 266  
 267          if(!$this->login_pass_ok($username, $password)) {
 268              return($this->error);
 269          }
 270  
 271          // Lookup info on pages.
 272          $pages = get_pages();
 273          $num_pages = count($pages);
 274  
 275          // If we have pages, put together their info.
 276          if($num_pages >= 1) {
 277              $pages_struct = array();
 278  
 279              for($i = 0; $i < $num_pages; $i++) {
 280                  $page = wp_xmlrpc_server::wp_getPage(array(
 281                      $blog_id, $pages[$i]->ID, $username, $password
 282                  ));
 283                  $pages_struct[] = $page;
 284              }
 285  
 286              return($pages_struct);
 287          }
 288          // If no pages were found return an error.
 289          else {
 290              return(array());
 291          }
 292      }
 293  
 294      /**
 295       * WordPress XML-RPC API
 296        * wp_newPage
 297       */
 298  	function wp_newPage($args) {
 299          // Items not escaped here will be escaped in newPost.
 300          $username    = $this->escape($args[1]);
 301          $password    = $this->escape($args[2]);
 302          $page        = $args[3];
 303          $publish    = $args[4];
 304  
 305          if(!$this->login_pass_ok($username, $password)) {
 306              return($this->error);
 307          }
 308  
 309          // Set the user context and check if they are allowed
 310          // to add new pages.
 311          $user = set_current_user(0, $username);
 312          if(!current_user_can("publish_pages")) {
 313              return(new IXR_Error(401, __("Sorry, you can not add new pages.")));
 314          }
 315  
 316          // Mark this as content for a page.
 317          $args[3]["post_type"] = "page";
 318  
 319          // Let mw_newPost do all of the heavy lifting.
 320          return($this->mw_newPost($args));
 321      }
 322  
 323      /**
 324       * WordPress XML-RPC API
 325       * wp_deletePage
 326       */
 327  	function wp_deletePage($args) {
 328          $this->escape($args);
 329  
 330          $blog_id    = (int) $args[0];
 331          $username    = $args[1];
 332          $password    = $args[2];
 333          $page_id    = (int) $args[3];
 334  
 335          if(!$this->login_pass_ok($username, $password)) {
 336              return($this->error);
 337          }
 338  
 339          // Get the current page based on the page_id and
 340          // make sure it is a page and not a post.
 341          $actual_page = wp_get_single_post($page_id, ARRAY_A);
 342          if(
 343              !$actual_page
 344              || ($actual_page["post_type"] != "page")
 345          ) {
 346              return(new IXR_Error(404, __("Sorry, no such page.")));
 347          }
 348  
 349          // Set the user context and make sure they can delete pages.
 350          set_current_user(0, $username);
 351          if(!current_user_can("delete_page", $page_id)) {
 352              return(new IXR_Error(401, __("Sorry, you do not have the right to delete this page.")));
 353          }
 354  
 355          // Attempt to delete the page.
 356          $result = wp_delete_post($page_id);
 357          if(!$result) {
 358              return(new IXR_Error(500, __("Failed to delete the page.")));
 359          }
 360  
 361          return(true);
 362      }
 363  
 364      /**
 365       * WordPress XML-RPC API
 366       * wp_editPage
 367       */
 368  	function wp_editPage($args) {
 369          // Items not escaped here will be escaped in editPost.
 370          $blog_id    = (int) $args[0];
 371          $page_id    = (int) $this->escape($args[1]);
 372          $username    = $this->escape($args[2]);
 373          $password    = $this->escape($args[3]);
 374          $content    = $args[4];
 375          $publish    = $args[5];
 376  
 377          if(!$this->login_pass_ok($username, $password)) {
 378              return($this->error);
 379          }
 380  
 381          // Get the page data and make sure it is a page.
 382          $actual_page = wp_get_single_post($page_id, ARRAY_A);
 383          if(
 384              !$actual_page
 385              || ($actual_page["post_type"] != "page")
 386          ) {
 387              return(new IXR_Error(404, __("Sorry, no such page.")));
 388          }
 389  
 390          // Set the user context and make sure they are allowed to edit pages.
 391          set_current_user(0, $username);
 392          if(!current_user_can("edit_page", $page_id)) {
 393              return(new IXR_Error(401, __("Sorry, you do not have the right to edit this page.")));
 394          }
 395  
 396          // Mark this as content for a page.
 397          $content["post_type"] = "page";
 398  
 399          // Arrange args in the way mw_editPost understands.
 400          $args = array(
 401              $page_id,
 402              $username,
 403              $password,
 404              $content,
 405              $publish
 406          );
 407  
 408          // Let mw_editPost do all of the heavy lifting.
 409          return($this->mw_editPost($args));
 410      }
 411  
 412      /**
 413       * WordPress XML-RPC API
 414       * wp_getPageList
 415       */
 416  	function wp_getPageList($args) {
 417          global $wpdb;
 418  
 419          $this->escape($args);
 420  
 421          $blog_id                = (int) $args[0];
 422          $username                = $args[1];
 423          $password                = $args[2];
 424  
 425          if(!$this->login_pass_ok($username, $password)) {
 426              return($this->error);
 427          }
 428  
 429          // Get list of pages ids and titles
 430          $page_list = $wpdb->get_results("
 431              SELECT ID page_id,
 432                  post_title page_title,
 433                  post_parent page_parent_id,
 434                  post_date_gmt,
 435                  post_date
 436              FROM {$wpdb->posts}
 437              WHERE post_type = 'page'
 438              ORDER BY ID
 439          ");
 440  
 441          // The date needs to be formated properly.
 442          $num_pages = count($page_list);
 443          for($i = 0; $i < $num_pages; $i++) {
 444              $post_date = mysql2date("Ymd\TH:i:s", $page_list[$i]->post_date);
 445              $post_date_gmt = mysql2date("Ymd\TH:i:s", $page_list[$i]->post_date_gmt);
 446  
 447              $page_list[$i]->dateCreated = new IXR_Date($post_date);
 448              $page_list[$i]->date_created_gmt = new IXR_Date($post_date_gmt);
 449  
 450              unset($page_list[$i]->post_date_gmt);
 451              unset($page_list[$i]->post_date);
 452          }
 453  
 454          return($page_list);
 455      }
 456  
 457      /**
 458       * WordPress XML-RPC API
 459       * wp_getAuthors
 460       */
 461  	function wp_getAuthors($args) {
 462          global $wpdb;
 463  
 464          $this->escape($args);
 465  
 466          $blog_id    = (int) $args[0];
 467          $username    = $args[1];
 468          $password    = $args[2];
 469  
 470          if(!$this->login_pass_ok($username, $password)) {
 471              return($this->error);
 472          }
 473  
 474          return(get_users_of_blog());
 475      }
 476  
 477      /**
 478       * WordPress XML-RPC API
 479       * wp_newCategory
 480       */
 481  	function wp_newCategory($args) {
 482          $this->escape($args);
 483  
 484          $blog_id                = (int) $args[0];
 485          $username                = $args[1];
 486          $password                = $args[2];
 487          $category                = $args[3];
 488  
 489          if(!$this->login_pass_ok($username, $password)) {
 490              return($this->error);
 491          }
 492  
 493          // Set the user context and make sure they are
 494          // allowed to add a category.
 495          set_current_user(0, $username);
 496          if(!current_user_can("manage_categories", $page_id)) {
 497              return(new IXR_Error(401, __("Sorry, you do not have the right to add a category.")));
 498          }
 499  
 500          // If no slug was provided make it empty so that
 501          // WordPress will generate one.
 502          if(empty($category["slug"])) {
 503              $category["slug"] = "";
 504          }
 505  
 506          // If no parent_id was provided make it empty
 507          // so that it will be a top level page (no parent).
 508          if ( !isset($category["parent_id"]) )
 509              $category["parent_id"] = "";
 510  
 511          // If no description was provided make it empty.
 512          if(empty($category["description"])) {
 513              $category["description"] = "";
 514          }
 515  
 516          $new_category = array(
 517              "cat_name"                => $category["name"],
 518              "category_nicename"        => $category["slug"],
 519              "category_parent"        => $category["parent_id"],
 520              "category_description"    => $category["description"]
 521          );
 522  
 523          $cat_id = wp_insert_category($new_category);
 524          if(!$cat_id) {
 525              return(new IXR_Error(500, __("Sorry, the new category failed.")));
 526          }
 527  
 528          return($cat_id);
 529      }
 530  
 531      /**
 532       * WordPress XML-RPC API
 533       * wp_suggestCategories
 534       */
 535  	function wp_suggestCategories($args) {
 536          global $wpdb;
 537  
 538          $this->escape($args);
 539  
 540          $blog_id                = (int) $args[0];
 541          $username                = $args[1];
 542          $password                = $args[2];
 543          $category                = $args[3];
 544          $max_results            = (int) $args[4];
 545  
 546          if(!$this->login_pass_ok($username, $password)) {
 547              return($this->error);
 548          }
 549  
 550          $args = array('get' => 'all', 'number' => $max_results, 'name__like' => $category);
 551          $category_suggestions = get_categories($args);
 552  
 553          return($category_suggestions);
 554      }
 555  
 556  
 557      /* Blogger API functions
 558       * specs on http://plant.blogger.com/api and http://groups.yahoo.com/group/bloggerDev/
 559       */
 560  
 561  
 562      /* blogger.getUsersBlogs will make more sense once we support multiple blogs */
 563  	function blogger_getUsersBlogs($args) {
 564  
 565          $this->escape($args);
 566  
 567          $user_login = $args[1];
 568          $user_pass  = $args[2];
 569  
 570          if (!$this->login_pass_ok(