PHP Cross Reference of WordPress Latest 2.0 Branch

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