[ 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          $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('&amp;', '&', $pagelinkedfrom);
1109          $pagelinkedto   = preg_replace('#&([^amp\;])#is', '&amp;$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', '&amp;$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  ?>

Your comment here...

Name: Location:
Comments:


List: Classes | Functions | Variables | Constants | Tables

Generated: Sat Jul 15 11:57:04 2006 Courtesy of Taragana