[ Index ]

WordPress Source Cross Reference

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  # 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