[ Index ]

PHP Cross Reference of Textpattern 4.0.8

title

Body

[close]

/rpc/ -> TXP_RPCServer.php (source)

   1  <?php
   2  /*
   3  XML-RPC Server for Textpattern 4.0.x
   4  http://txp.kusor.com/rpc-api
   5  (C)2005-2006 The Textpattern Development Team - http://textpattern.com
   6  @author Pedro Palazón - http://kusor.com
   7  $HeadURL: https://textpattern.googlecode.com/svn/releases/4.0.8/source/rpc/TXP_RPCServer.php $
   8  $LastChangedRevision: 2998 $
   9   */
  10  
  11  if (!defined('txpath')) die('txpath is undefined.');
  12  
  13  require_once txpath.'/lib/txplib_html.php';
  14  
  15  class TXP_RPCServer extends IXR_IntrospectionServer
  16  {
  17  	function TXP_RPCServer()
  18      {
  19          global $enable_xmlrpc_server;
  20  
  21          $this->IXR_IntrospectionServer();
  22          // Add API Methods as callbacks:
  23  
  24          if ($enable_xmlrpc_server)
  25          {
  26              // Blogger API [http://www.blogger.com/developers/api/] - add as server capability
  27              $this->capabilities['bloggerAPI'] = array(
  28                  'specUrl'     => 'http://www.blogger.com/developers/api/',
  29                  'specVersion' => 2
  30              );
  31              $this->addCallback(
  32                  'blogger.newPost',
  33                  'this:blogger_newPost',
  34                  array('int', 'string', 'string', 'string', 'string', 'string', 'boolean'),
  35                                     'makes a new post to a designated blog'
  36              );
  37              $this->addCallback(
  38                  'blogger.editPost',
  39                  'this:blogger_editPost',
  40                  array('boolean', 'string', 'string', 'string', 'string', 'string', 'boolean'),
  41                  'changes the contents of a given post'
  42              );
  43              $this->addCallback(
  44                  'blogger.getUsersBlogs',
  45                  'this:blogger_getUsersBlogs',
  46                  array('struct', 'string', 'string', 'string'),
  47                  'return information about all the blogs a given user is member of'
  48              );
  49              $this->addCallback(
  50                  'blogger.getUserInfo',
  51                  'this:blogger_getUserInfo',
  52                  array('struct', 'string', 'string', 'string'),
  53                  'return information about the current user'
  54              );
  55              $this->addCallback(
  56                  'blogger.getTemplate',
  57                  'this:blogger_getTemplate',
  58                  array('string', 'string', 'string', 'string', 'string', 'string'),
  59                  'return section template - main will return default template, archiveIndex will return section template'
  60              );
  61              $this->addCallback(
  62                  'blogger.setTemplate',
  63                  'this:blogger_setTemplate',
  64                  array('boolean', 'string', 'string', 'string', 'string', 'string', 'string'),
  65                  'updates section template - main=default template, archiveIndex=section template'
  66              );
  67  
  68              // non-official Blogger API methods - supported by XML-RPC clients as BloggerAPI2
  69              // Place all this info on a public URI
  70              $this->addCallback(
  71                  'blogger.getPost',
  72                  'this:blogger_getPost',
  73                  array('struct', 'string', 'string', 'string', 'string'),
  74                  'retrieves contents for the given postid'
  75              );
  76              $this->addCallback(
  77                  'blogger.deletePost',
  78                  'this:blogger_deletePost',
  79                  array('boolean', 'string', 'string', 'string', 'string', 'boolean'),
  80                  'deletes a given post'
  81              );
  82              $this->addCallback(
  83                  'blogger.getRecentPosts',
  84                  'this:blogger_getRecentPosts',
  85                  array('array', 'string', 'string', 'string', 'string', 'int'),
  86                  'retrieves a list of posts (default 10)'
  87              );
  88  
  89              // metaWeblog API[http://www.xmlrpc.com/metaWeblogApi] - add as server capability
  90              $this->capabilities['metaWeblog API'] = array(
  91                  'specUrl'     => 'http://www.xmlrpc.com/metaWeblogApi',
  92                  'specVersion' => 1
  93              );
  94              // Implements also MovableType extension of the API methods
  95              $this->addCallback(
  96                  'metaWeblog.getPost',
  97                  'this:metaWeblog_getPost',
  98                  array('struct', 'string', 'string', 'string'),
  99                  'retrieves contents for the given postid'
 100              );
 101              $this->addCallback(
 102                  'metaWeblog.newPost',
 103                  'this:metaWeblog_newPost',
 104                  array('string', 'string', 'string', 'string', 'struct', 'boolean'),
 105                  'creates a new post'
 106              );
 107              $this->addCallback(
 108                  'metaWeblog.editPost',
 109                  'this:metaWeblog_editPost',
 110                  array('boolean', 'string', 'string', 'string', 'struct', 'boolean'),
 111                  'creates a new post'
 112              );
 113              $this->addCallback(
 114                  'metaWeblog.getCategories',
 115                  'this:metaWeblog_getCategories',
 116                  array('struct', 'string', 'string', 'string'),
 117                  'retrieves a list of categories for the current blog'
 118              );
 119              $this->addCallback(
 120                  'metaWeblog.getRecentPosts',
 121                  'this:metaWeblog_getRecentPosts',
 122                  array('array', 'string', 'string', 'string', 'int'),
 123                  'retrieves a given number of recent posts'
 124              );
 125  #TODO: metaWeblog.newMediaObject (blogid, username, password, struct) returns struct
 126  
 127              // MovableType API[] - add as server capability
 128              $this->capabilities['MovableType API'] = array(
 129                  'specUrl'     => 'http://www.sixapart.com/movabletype/docs/mtmanual_programmatic.html#xmlrpc%20api',
 130                  'specVersion' => 1
 131              );
 132              // Not completelly implemented.
 133              $this->addCallback(
 134                  'mt.getRecentPostTitles',
 135                  'this:mt_getRecentPostTitles',
 136                  array('array', 'string', 'string', 'string', 'id'),
 137                  'returns a bandwidth-friendly list of the most recent posts in the system'
 138              );
 139              $this->addCallback(
 140                  'mt.getCategoryList',
 141                  'this:mt_getCategoryList',
 142                  array('array', 'string', 'string', 'string'),
 143                  'returns a list of all categories defined in the weblog'
 144              );
 145              $this->addCallback(
 146                  'mt.supportedMethods',
 147                  'this:listMethods',
 148                  array('array'),
 149                  'return the XML-RPC Methods supported by the server(Redundant).'
 150              );
 151              $this->addCallback(
 152                  'mt.supportedTextFilters',
 153                  'this:mt_supportedTextFilters',
 154                  array('array'),
 155                  'return the format filters suported by the server.'
 156              );
 157              $this->addCallback(
 158                  'mt.getPostCategories',
 159                  'this:mt_getPostCategories',
 160                  array('array', 'string', 'string', 'string'),
 161                  'returns a list of all categories for the given article'
 162              );
 163              $this->addCallback(
 164                  'mt.setPostCategories',
 165                  'this:mt_setPostCategories',
 166                  array('boolean', 'string', 'string', 'string', 'array'),
 167                  'sets categories for the given article'
 168              );
 169              $this->addCallback(
 170                  'mt.publishPost',
 171                  'this:mt_publishPost',
 172                  array('boolean', 'string', 'string', 'string'),
 173                  'changes the status of the current article to published'
 174              );
 175          }
 176      }
 177  
 178      // Override serve method in order to keep requests logs too
 179      // while dealing with unknown clients
 180  	function serve($data = false)
 181      {
 182          if (!$data)
 183          {
 184              global $HTTP_RAW_POST_DATA;
 185  
 186              if (!$HTTP_RAW_POST_DATA)
 187              {
 188                  // RSD lets them find us via GET requests
 189                  $this->rsd();
 190                  exit;
 191              }
 192  
 193              $rx = '/<?xml.*encoding=[\'"](.*?)[\'"].*?>/m';
 194  
 195              // first, handle the known UAs in order to serve proper content
 196              if (strpos('w.bloggar', $_SERVER['HTTP_USER_AGENT']) !== false)
 197              {
 198                  $encoding = 'iso-8859-1';
 199              }
 200              // find for supplied encoding before to try other things
 201              elseif (preg_match($rx, $HTTP_RAW_POST_DATA, $xml_enc))
 202              {
 203                  $encoding = strtolower($xml_enc[1]);
 204              }
 205              // try utf-8 detect
 206              elseif (preg_match('/^([\x00-\x7f]|[\xc2-\xdf][\x80-\xbf]|\xe0[\xa0-\xbf][\x80-\xbf]|[\xe1-\xec][\x80-\xbf]{2}|\xed[\x80-\x9f][\x80-\xbf]|[\xee-\xef][\x80-\xbf]{2}|f0[\x90-\xbf][\x80-\xbf]{2}|[\xf1-\xf3][\x80-\xbf]{3}|\xf4[\x80-\x8f][\x80-\xbf]{2})*$/', $HTTP_RAW_POST_DATA) === 1)
 207              {
 208                  $encoding = 'utf-8';
 209              }
 210              // otherwise, use iso-8859-1
 211              else
 212              {
 213                  $encoding = 'iso-8859-1';
 214              }
 215  
 216              switch ($encoding)
 217              {
 218                  case 'utf-8':
 219                      $data = $HTTP_RAW_POST_DATA;
 220                      break;
 221  
 222                  case 'iso-8859-1':
 223  #TODO: if utf8 conversion fails, throw: 32701 ---> parse error. unsupported encoding?
 224  #see: http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php
 225                      // this will fail on parser if utf8_encode is unavailiable
 226                      $data = (function_exists('utf8_encode') && is_callable('utf8_encode'))? utf8_encode($HTTP_RAW_POST_DATA) : $HTTP_RAW_POST_DATA;
 227                      break;
 228  
 229                  default:
 230  #TODO: if utf8 conversion fails, throw: 32701 ---> parse error. unsupported encoding?
 231                      // this will fail on parser if mb_convert_encoding is unavailiable
 232                      $data = (function_exists('mb_convert_encoding') && is_callable('mb_convert_encoding'))? mb_convert_encoding($HTTP_RAW_POST_DATA, 'utf-8', $encoding) : $HTTP_RAW_POST_DATA;
 233                      break;
 234              }
 235          }
 236  
 237          $this->message = new IXR_Message($data);
 238  
 239          if (!$this->message->parse())
 240          {
 241              $this->error(-32700, 'parse error. not well formed');
 242          }
 243  
 244          if ($this->message->messageType != 'methodCall')
 245          {
 246              $this->error(-32600, 'server error. invalid xml-rpc. not conforming to spec. Request must be a methodCall');
 247          }
 248  
 249          $result = $this->call($this->message->methodName, $this->message->params);
 250  
 251          // Is the result an error?
 252          if (is_a($result, 'IXR_Error'))
 253          {
 254              $this->error($result);
 255          }
 256  
 257          // Encode the result
 258          $r = new IXR_Value($result);
 259          $resultxml = $r->getXml();
 260  
 261          // Create the XML
 262          $xml = <<<EOD
 263  <methodResponse>
 264      <params>
 265          <param>
 266              <value>
 267                  $resultxml
 268              </value>
 269          </param>
 270      </params>
 271  </methodResponse>
 272  
 273  EOD;
 274  
 275          return $this->output($xml, $encoding);
 276      }
 277  
 278      // Override default utf-8 output, if needed
 279  	function output($xml, $enc = 'utf-8')
 280      {
 281          // Be kind with non-utf-8 capable clients
 282          if ($enc != 'utf-8')
 283          {
 284              if ($enc == 'iso-8859-1' && function_exists('utf8_decode') && is_callable('utf8_decode'))
 285              {
 286                  $xml = utf8_decode($xml);
 287              }
 288              elseif (function_exists('mb_convert_encoding') && is_callable('mb_convert_encoding'))
 289              {
 290                  $xml = mb_convert_encoding($xml, $enc, 'utf-8');
 291              }
 292              else
 293              {
 294  # TODO: shouldn't this throw an error instead of serving non-utf8 content as utf8?
 295                  // if no decoding possible, serve contents as utf-8
 296                  $enc = 'utf-8';
 297              }
 298          }
 299  
 300          $xml = '<?xml version="1.0" encoding="'.$enc.'" ?>'.n.$xml;
 301          $length = strlen($xml);
 302          header('Connection: close');
 303          header('Content-Length: '.$length);
 304          header('Content-Type: text/xml charset='.$enc);
 305          header('Date: '.date('r'));
 306          echo $xml;
 307          exit;
 308      }
 309  
 310  //---------------------------------------------------------
 311  // Really Simple Discoverability 1.0 response
 312  
 313  	function rsd()
 314      {
 315          global $enable_xmlrpc_server;
 316  
 317          if ($enable_xmlrpc_server)
 318          {
 319              $this->output(
 320                  tag(
 321                      n.tag(
 322                          n.tag('Textpattern', 'engineName').
 323                          n.tag('http://textpattern.com/', 'engineLink').
 324                          n.tag(hu, 'homePageLink').
 325                          n.tag(
 326                              n.'<api name="Movable Type" blogID="" preferred="true" apiLink="'.txrpcpath.'" />'.
 327                              n.'<api name="MetaWeblog" blogID="" preferred="false" apiLink="'.txrpcpath.'" />'.
 328                              n.'<api name="Blogger" blogID="" preferred="false" apiLink="'.txrpcpath.'" />'.n,
 329                              'apis').n,
 330                      'service').n,
 331                      'rsd', ' version="1.0" xmlns="http://archipelago.phrasewise.com/rsd"')
 332                  );
 333          }
 334          else
 335          {
 336              header('Status: 501 Not Implemented');
 337              header('HTTP/1.1 501 Not Implemented');
 338              die('Not Implemented');
 339          }
 340      }
 341  
 342  //---------------------------------------------------------
 343  // Blogger API
 344  
 345  	function blogger_newPost($params)
 346      {
 347          list($appkey, $blogid, $username, $password, $content, $publish) = $params;
 348  
 349          $txp = new TXP_Wrapper($username, $password);
 350  
 351          if (!$txp->loggedin)
 352          {
 353              return new IXR_Error(100, gTxt('bad_login'));
 354          }
 355  
 356          $contents = $this->_getBloggerContents($content);
 357  
 358          $contents['Section'] = $blogid;
 359          $contents['Status']  = $publish ? '4' : '1';
 360  
 361          $rs = $txp->newArticle($contents);
 362  
 363          if (false === $rs)
 364          {
 365              return new IXR_Error(201, gTxt('problem_creating_article'));
 366          }
 367  
 368          return intval($rs);
 369      }
 370  
 371  	function blogger_editPost($params)
 372      {
 373          list($appkey, $postid, $username, $password, $content, $publish) = $params;
 374  
 375          $txp = new TXP_Wrapper($username, $password);
 376  
 377          if (!$txp->loggedin)
 378          {
 379              return new IXR_Error(100, gTxt('bad_login'));
 380          }
 381  
 382          $id = $txp->getArticleID($postid, 'ID');
 383  
 384          if (!$id)
 385          {
 386              return new IXR_Error(404, gTxt('invalid_article_id'));
 387          }
 388  
 389          $contents = $this->_getBloggerContents($content);
 390  
 391          $contents['Status'] = $publish ? '4' : '1';
 392  
 393          $rs = $txp->updateArticleID($postid, $contents);
 394  
 395          if (false === $rs)
 396          {
 397              return new IXR_Error(202, gTxt('problem_updating_article'));
 398          }
 399  
 400          return true;
 401      }
 402  
 403  	function blogger_getUsersBlogs($params)
 404      {
 405          list($appkey, $username, $password) = $params;
 406  
 407          global $permlink_mode;
 408  
 409          $txp = new TXP_Wrapper($username, $password);
 410  
 411          if (!$txp->loggedin)
 412          {
 413              return new IXR_Error(100, gTxt('bad_login'));
 414          }
 415  
 416          $rs = $txp->getSectionsList();
 417  
 418          if (false === $rs)
 419          {
 420              return new IXR_Error(203, gTxt('problem_retrieving_sections'));
 421          }
 422  
 423          $sections = array();
 424  
 425          foreach ($rs as $section)
 426          {
 427              $sections[] = array(
 428                  'blogid'   => $section['name'],
 429                  'blogName' => $section['title'],
 430                  'url'      => pagelinkurl(array('s' => $section['name']))
 431              );
 432          }
 433  
 434          return $sections;
 435      }
 436  
 437  	function blogger_getUserInfo($params)
 438      {
 439          list($appkey, $username, $password) = $params;
 440  
 441          $txp = new TXP_Wrapper($username, $password);
 442  
 443          if (!$txp->loggedin)
 444          {
 445              return new IXR_Error(100, gTxt('bad_login'));
 446          }
 447  
 448          $rs = $txp->getUser();
 449  
 450          if (!$rs)
 451          {
 452              return new IXR_Error(204, gTxt('unable_retrieve_user'));
 453          }
 454  
 455          extract($rs);
 456  
 457          if (strpos($RealName, ' ') != 0)
 458          {
 459              list($firstname, $lastname) = split(' ', $RealName);
 460          }
 461          else
 462          {
 463              $firstname = $RealName;
 464              $lastname  = '';
 465          }
 466  
 467          $uinfo = array(
 468              'userid'    => $user_id,
 469              'firstname' => $firstname,
 470              'lastname'  => $lastname,
 471              'nickname'  => $name,
 472              'email'     => $email,
 473              'url'       => hu
 474          );
 475  
 476          return $uinfo;
 477      }
 478  
 479  	function blogger_getTemplate($params)
 480      {
 481          list($appkey, $blogid, $username, $password, $templateType) = $params;
 482  
 483          $txp = new TXP_Wrapper($username, $password);
 484  
 485          if (!$txp->loggedin)
 486          {
 487              return new IXR_Error(100, gTxt('bad_login'));
 488          }
 489  
 490          if ($templateType == 'archiveIndex' && $blogid != 'default')
 491          {
 492              $section = $txp->getSection($blogid);
 493  
 494              if (!$section)
 495              {
 496                  return new IXR_Error(208, gTxt('unable_retrieve_template'));
 497              }
 498  
 499              $name = $section['page'];
 500          }
 501          else
 502          {
 503              $name = 'default';
 504          }
 505  
 506          $rs = $txp->getTemplate($name);
 507  
 508          if (!$rs)
 509          {
 510              return new IXR_Error(208, gTxt('unable_retrieve_template'));
 511          }
 512  
 513          return $rs;
 514      }
 515  
 516  	function blogger_setTemplate($params)
 517      {
 518          list($appkey, $blogid, $username, $password, $template, $templateType) = $params;
 519  
 520          $txp = new TXP_Wrapper($username, $password);
 521  
 522          if (!$txp->loggedin)
 523          {
 524              return new IXR_Error(100, gTxt('bad_login'));
 525          }
 526  
 527          if ($templateType == 'archiveIndex' && $blogid != 'default')
 528          {
 529              $section = $txp->getSection($blogid);
 530  
 531              if (!$section)
 532              {
 533                  return new IXR_Error(209, gTxt('unable_set_template'));
 534              }
 535  
 536              $name = $section['page'];
 537          }
 538          else
 539          {
 540              $name = 'default';
 541          }
 542  
 543          $rs = $txp->setTemplate($name, $template);
 544  
 545          if (!$rs)
 546          {
 547              return new IXR_Error(209, gTxt('unable_set_template'));
 548          }
 549  
 550          return true;
 551      }
 552  
 553  //---------------------------------------------------------
 554  // Blogger 2.0
 555  
 556  	function blogger_getPost($params)
 557      {
 558          list($appkey, $postid, $username, $password) = $params;
 559  
 560          $txp = new TXP_Wrapper($username, $password);
 561  
 562          if (!$txp->loggedin)
 563          {
 564              return new IXR_Error(100, gTxt('bad_login'));
 565          }
 566  
 567          $rs = $txp->getArticleID($postid, 'ID, Body, AuthorId, unix_timestamp(Posted) as uPosted');
 568  
 569          if (!$rs)
 570          {
 571              return new IXR_Error(205, gTxt('problem_retrieving_article'));
 572          }
 573  
 574          $out = array(
 575              'content'     => $rs['Body'],
 576              'userId'      => $rs['AuthorId'],
 577              'postId'      => $rs['ID'],
 578              'dateCreated' => new IXR_Date($rs['uPosted'] + tz_offset())
 579          );
 580  
 581          return $out;
 582      }
 583  
 584  	function blogger_deletePost($params)
 585      {
 586          list($appkey, $postid, $username, $password, $publish) = $params;
 587  
 588          $txp = new TXP_Wrapper($username, $password);
 589  
 590          if (!$txp->loggedin)
 591          {
 592              return new IXR_Error(100, gTxt('bad_login'));
 593          }
 594  
 595          // Always delete, no matter of publish
 596          $rs = $txp->deleteArticleID($postid);
 597  
 598          if (!$rs)
 599          {
 600              return new IXR_Error(206, gTxt('problem_deleting_article'));
 601          }
 602  
 603          return $rs;
 604      }
 605  
 606  	function blogger_getRecentPosts($params)
 607      {
 608          list($appkey, $blogid, $username, $password, $numberOfPosts) = $params;
 609  
 610          $txp = new TXP_Wrapper($username, $password);
 611  
 612          if (!$txp->loggedin)
 613          {
 614              return new IXR_Error(100, gTxt('bad_login'));
 615          }
 616  
 617          $articles = $txp->getArticleList('ID, Body, AuthorId, unix_timestamp(Posted) as uPosted', "Section='".doSlash($blogid)."'", '0', $numberOfPosts, false);
 618  
 619          if (false === $articles)
 620          {
 621              return new IXR_Error(207, gTxt('problem_getting_articles'));
 622          }
 623  
 624          foreach ($articles as $rs)
 625          {
 626              $out[] = array(
 627                  'content'     => $rs['Body'],
 628                  'userId'      => $rs['AuthorId'],
 629                  'postId'      => $rs['ID'],
 630                  'dateCreated' => new IXR_Date($rs['uPosted'] + tz_offset())
 631              );
 632          }
 633          return $out;
 634      }
 635  
 636  //---------------------------------------------------------
 637  // metaWeblog API
 638  
 639  	function metaWeblog_getPost($params)
 640      {
 641          list($postid, $username, $password) = $params;
 642  
 643          $txp = new TXP_Wrapper($username, $password);
 644  
 645          if (!$txp->loggedin)
 646          {
 647              return new IXR_Error(100, gTxt('bad_login'));
 648          }
 649  
 650          $rs = $txp->getArticleID($postid, 'ID, Title, Body, Excerpt, Annotate, Keywords, Section, Category1, Category2, textile_body, url_title, unix_timestamp(Posted) as uPosted');
 651  
 652          if (!$rs)
 653          {
 654              return new IXR_Error(205, gTxt('problem_retrieving_article'));
 655          }
 656  
 657          return $this->_buildMetaWeblogStruct($rs, $txp);
 658      }
 659  
 660  	function metaWeblog_newPost($params)
 661      {
 662          list($blogid, $username, $password, $struct, $publish) = $params;
 663  
 664          $txp = new TXP_Wrapper($username, $password);
 665  
 666          if (!$txp->loggedin)
 667          {
 668              return new IXR_Error(100, gTxt('bad_login'));
 669          }
 670  
 671          $contents = $this->_getMetaWeblogContents($struct, $publish, $txp);
 672  
 673          $contents['Section'] = $blogid;
 674  
 675          $rs = $txp->newArticle($contents);
 676  
 677          if (false === $rs)
 678          {
 679              return new IXR_Error(201, gTxt('problem_creating_article'));
 680          }
 681  
 682  #TODO: why "" quoted $rs?
 683          return "$rs";
 684      }
 685  
 686  	function metaWeblog_editPost($params)
 687      {
 688          list($postid, $username, $password, $struct, $publish) = $params;
 689  
 690          $txp = new TXP_Wrapper($username, $password);
 691  
 692          if (!$txp->loggedin)
 693          {
 694              return new IXR_Error(100, gTxt('bad_login'));
 695          }
 696  
 697          $contents = $this->_getMetaWeblogContents($struct, $publish, $txp);
 698  
 699          $rs = $txp->updateArticleID($postid, $contents);
 700  
 701          if (false === $rs)
 702          {
 703              return new IXR_Error(201, gTxt('problem_updating_article'));
 704          }
 705  
 706          return true;
 707      }
 708  
 709  	function metaWeblog_getCategories($params)
 710      {
 711          list($blogid, $username, $password) = $params;
 712  
 713          global $permlink_mode;
 714  
 715          $txp = new TXP_Wrapper($username, $password);
 716  
 717          if (!$txp->loggedin)
 718          {
 719              return new IXR_Error(100, gTxt('bad_login'));
 720          }
 721  
 722          $rs = $txp->getCategoryList();
 723  
 724          if (false === $rs)
 725          {
 726              return new IXR_Error(210, gTxt('problem_retrieving_categories'));
 727          }
 728  
 729          $cats = array();
 730  
 731          foreach ($rs as $c)
 732          {
 733              $cats[] = array(
 734                  'categoryName' => $c['title'],
 735                  'description'  => $c['title'],
 736                  'htmlUrl'      => pagelinkurl(array('c' => $c['name'])),
 737                  'rssUrl'       => hu.'?rss=1&#38;category='.$c['name']
 738              );
 739          }
 740  
 741          return $cats;
 742      }
 743  
 744  	function metaWeblog_getRecentPosts($params)
 745      {
 746          list($blogid, $username, $password, $numberOfPosts) = $params;
 747  
 748          $txp = new TXP_Wrapper($username, $password);
 749  
 750          if (!$txp->loggedin)
 751          {
 752              return new IXR_Error(100, gTxt('bad_login'));
 753          }
 754  
 755          $articles = $txp->getArticleList('ID, Title, url_title, Body, Excerpt, Annotate, Keywords, Section, Category1, Category2, textile_body, AuthorID, unix_timestamp(Posted) as uPosted',
 756              "Section='".doSlash($blogid)."'", '0', $numberOfPosts, false);
 757  
 758          if (false === $articles)
 759          {
 760              return new IXR_Error(207, gTxt('problem_getting_articles'));
 761          }
 762  
 763          $out = array();
 764  
 765          foreach ($articles as $rs)
 766          {
 767              $out[] = $this->_buildMetaWeblogStruct($rs, $txp);
 768          }
 769  
 770          return $out;
 771      }
 772  
 773  //---------------------------------------------------------
 774  // MovableType API
 775  
 776  	function mt_getRecentPostTitles($params)
 777      {
 778          list($blogid, $username, $password, $numberOfPosts) = $params;
 779  
 780          global $prefs;
 781  
 782          $txp = new TXP_Wrapper($username, $password);
 783  
 784          if (!$txp->loggedin)
 785          {
 786              return new IXR_Error(100, gTxt('bad_login'));
 787          }
 788  
 789          $articles = $txp->getArticleList('ID, Title, AuthorID, unix_timestamp(Posted) as uPosted', "Section='".doSlash($blogid)."'", '0', $numberOfPosts, false);
 790  
 791          if (false === $articles)
 792          {
 793              return new IXR_Error(207, gTxt('problem_getting_articles'));
 794          }
 795  
 796          extract($prefs);
 797  
 798          $out = array();
 799  
 800          foreach ($articles as $rs)
 801          {
 802              $out[] = array(
 803                  'userid'      => $username,
 804                  'postid'      => $rs['ID'],
 805                  'dateCreated' => new IXR_Date($rs['uPosted'] + tz_offset()),
 806                  'title'       => $rs['Title'],
 807              );
 808          }
 809  
 810          return $out;
 811      }
 812  
 813  	function mt_getCategoryList($params)
 814      {
 815          list($blogid, $username, $password) = $params;
 816  
 817          $txp = new TXP_Wrapper($username, $password);
 818  
 819          if (!$txp->loggedin)
 820          {
 821              return new IXR_Error(100, gTxt('bad_login'));
 822          }
 823  
 824          $rs = $txp->getCategoryList();
 825  
 826          if (false === $rs)
 827          {
 828              return new IXR_Error(210, gTxt('problem_retrieving_categories'));
 829          }
 830  
 831          $cats = array();
 832  
 833          foreach ($rs as $c)
 834          {
 835              $cats[] = array(
 836                  'categoryName' => $c['title'],
 837                  'categoryId'   => $c['id'],
 838              );
 839          }
 840  
 841          return $cats;
 842      }
 843  
 844  	function mt_supportedTextFilters($params)
 845      {
 846          $filters = array(
 847              array('key' => '0', 'label' => 'LEAVE_TEXT_UNTOUCHED'),
 848              array('key' => '1', 'label' => 'USE_TEXTILE'),
 849              array('key' => '2', 'label' => 'CONVERT_LINEBREAKS'),
 850          );
 851  
 852          return $filters;
 853      }
 854  
 855  	function mt_getPostCategories($params)
 856      {
 857          list($postid, $username, $password) = $params;
 858  
 859          $txp = new TXP_Wrapper($username, $password);
 860  
 861          if (!$txp->loggedin)
 862          {
 863              return new IXR_Error(100, gTxt('bad_login'));
 864          }
 865  
 866          $post = $txp->getArticleID($postid, 'Category1, Category2');
 867  
 868          if (!$post)
 869          {
 870              return new IXR_Error(211, gTxt('problem_retrieving_article_categories'));
 871          }
 872  
 873          $out = array();
 874          $isPrimary = true;
 875          $cats[] = $post['Category1'];
 876          $cats[] = $post['Category2'];
 877  
 878          foreach ($cats as $category)
 879          {
 880              if (!empty($category))
 881              {
 882                  $rs = $txp->getCategory($category);
 883  
 884  #TODO: remove?
 885                  // if (!$rs) return new IXR_Error(212, gTxt('problem_retrieving_category_info'));
 886  
 887                  $ct['categoryId']   = $rs['id'];
 888                  $ct['categoryName'] = $rs['title'];
 889                  $ct['isPrimary']    = $isPrimary;
 890  
 891                  $out[] = $ct;
 892              }
 893  
 894              if ($isPrimary) $isPrimary = false;
 895          }
 896  
 897          return $out;
 898      }
 899  
 900  #TODO: explain what 'expecific' is ;)
 901      // supported to avoid some client expecific behaviour
 902  	function mt_publishPost($params)
 903      {
 904          list($postid, $username, $password) = $params;
 905  
 906          $txp = new TXP_Wrapper($username, $password);
 907  
 908          if (!$txp->loggedin)
 909          {
 910              return new IXR_Error(100, gTxt('bad_login'));
 911          }
 912  
 913          $published = $txp->updateArticleField($postid, 'Status', '4');
 914  
 915          if (!$published)
 916          {
 917              return new IXR_Error(201, gTxt('problem_updating_article'));
 918          }
 919  
 920          return true;
 921      }
 922  
 923  	function mt_setPostCategories($params)
 924      {
 925          list($postid, $username, $password, $categories) = $params;
 926  
 927          $txp = new TXP_Wrapper($username, $password);
 928  
 929          if (!$txp->loggedin)
 930          {
 931              return new IXR_Error(100, gTxt('bad_login'));
 932          }
 933  
 934          $Category1 = '';
 935          $Category2 = '';
 936  
 937          foreach ($categories as $category)
 938          {
 939              extract($category);
 940  
 941              $rs = $txp->getCategoryId($categoryId);
 942  
 943              if (!$rs)
 944              {
 945                  return new IXR_Error(213, gTxt('trying_to_assign_unexisting_category_to_the_article'));
 946              }
 947  
 948              if (empty($Category1))
 949              {
 950                  $Category1 = $rs['name'];
 951              }
 952              else
 953              {
 954                  $Category2 = $rs['name'];
 955              }
 956          }
 957  
 958          $ct1 = $txp->updateArticleField($postid, 'Category1', $Category1);
 959          $ct2 = $txp->updateArticleField($postid, 'Category2', $Category2);
 960  
 961          if (!$ct1 || !$ct2)
 962          {
 963              return new IXR_Error(214, gTxt('problem_saving_article_categories'));
 964          }
 965  
 966          return true;
 967  
 968      }
 969  
 970  #TODO ???
 971      // MediaObjects
 972      /*
 973       metaWeblog.newMediaObject
 974       Description: Uploads a file to your webserver.
 975       Parameters: String blogid, String username, String password, struct file
 976       Return value: URL to the uploaded file.
 977       Notes: the struct file should contain two keys: base64 bits (the base64-encoded contents of the file)
 978       and String name (the name of the file). The type key (media type of the file) is currently ignored.
 979       */
 980  
 981      //code refactoring for blogger_newPost & blogger_editPost
 982  	function _getBloggerContents($content)
 983      {
 984          $body = $content;
 985  
 986          // Trick to add title, category and excerpts using XML-RPC
 987          if (preg_match('/<title>(.*)<\/title>(.*)/s', $content, $matches))
 988          {
 989              $body  = $matches[2];
 990              $title = $matches[1];
 991          }
 992  
 993          $contents = array(
 994              'Body' => str_replace('\n', n, $body)
 995          );
 996  
 997          if (isset($title)) $contents['Title'] = $title;
 998  
 999          return $contents;
1000      }
1001  
1002      //code refactoring for metaWeblog_newPost & metaweblog_EditPost
1003  	function _getMetaWeblogContents($struct, $publish, $txp)
1004      {
1005          global $gmtoffset, $is_dst;
1006  
1007          $contents = array(
1008              'Body'   => str_replace('\n', n, $struct['description']),
1009              'Status' => $publish ? '4' : '1',
1010              'Title'  => $struct['title']
1011          );
1012  
1013          if (!empty($struct['categories']))
1014          {
1015              if (!empty($struct['categories'][0]))
1016              {
1017                  $c = $txp->getCategoryTitle($struct['categories'][0]);
1018                  $contents['Category1'] = $c['name'];
1019              }
1020  
1021              if (!empty($struct['categories'][1]))
1022              {
1023                  $c = $txp->getCategoryTitle($struct['categories'][1]);
1024                  $contents['Category2'] = $c['name'];
1025              }
1026          }
1027  
1028          if (isset($struct['date_created_gmt']))
1029          {
1030              $struct['dateCreated'] = $struct['date_created_gmt'];
1031              $struct['dateCreated']->tz = 'Z'; // force GMT timezone
1032          }
1033  
1034          if (isset($struct['dateCreated']))
1035          {
1036              if ($struct['dateCreated']->tz == 'Z')
1037              {
1038                  // GMT-based posting time; transform into server time zone
1039                  $posted = $struct['dateCreated']->getTimestamp() - tz_offset() + $gmtoffset + ($is_dst ? 3600 : 0);
1040              }
1041              elseif (!$struct['dateCreated']->tz)
1042              {
1043                  // posting in an unspecified time zone: Assume site time.
1044                  $posted = $struct['dateCreated']->getTimestamp() - tz_offset();
1045              }
1046              else
1047              {
1048                  // numeric time zone offsets
1049                  if (preg_match('/([+-][0-9]{2})([0-9]{2})/', $struct['dateCreated']->tz, $t))
1050                  {
1051                      $tz = $t[1] * 3600 + $t[2] * 60;
1052                      $posted = $struct['dateCreated']->getTimestamp() - tz_offset() + $gmtoffset + ($is_dst ? 3600 : 0) - $tz;
1053                  }
1054              }
1055          }
1056  
1057          if (isset($posted)) $contents['Posted'] = date('Y-m-d H:i:s', $posted);
1058  
1059          // MovableType Implementation Add ons
1060          if (isset($struct['mt_allow_comments']))
1061          {
1062              $contents['Annotate'] = $struct['mt_allow_comments'];
1063          }
1064  
1065          if (isset($struct['mt_convert_breaks']))
1066          {
1067              $contents['textile_body'] = $contents['textile_excerpt'] = intval($struct['mt_convert_breaks']);
1068          }
1069  
1070          if (isset($struct['mt_text_more']))
1071          {
1072              $contents['Body'] .= n.n.str_replace('\n', n ,$struct['mt_text_more']);
1073          }
1074  
1075          if (isset($struct['mt_excerpt']))
1076          {
1077              $contents['Excerpt'] = str_replace('\n', n, $struct['mt_excerpt']);
1078          }
1079  
1080          if (isset($struct['mt_keywords']))
1081          {
1082              $contents['Keywords'] = $struct['mt_keywords'];
1083          }
1084  
1085          if (isset($struct['mt_basename']))
1086          {
1087              $contents['url_title'] = stripSpace($struct['mt_basename']);
1088          }
1089          elseif (isset($struct['wp_slug']))
1090          {
1091              $contents['url_title'] = stripSpace($struct['wp_slug']);
1092          }
1093  
1094          return $contents;
1095      }
1096  
1097      // common code to metaWeblog_getPost and metaWeblog_getRecentPosts
1098      // could not be this placed on a different file from taghandlers?
1099      // remove if it is the case
1100  	function _buildMetaWeblogStruct($rs, $txp)
1101      {
1102          global $permlink_mode, $is_dst, $gmtoffset;
1103  
1104          switch ($permlink_mode)
1105          {
1106              case 'section_id_title':
1107                  $url = hu.join('/', array($rs['Section'], $rs['ID'], $rs['url_title']));
1108                  break;
1109  
1110              case 'year_month_day_title':
1111                  $url = hu.join('/', array(
1112                      date("Y", $rs['uPosted']),
1113                      date("m", $rs['uPosted']),
1114                      date("d", $rs['uPosted']),
1115                      $rs['url_title']
1116                  ));
1117                  break;
1118  
1119              case 'title_only':
1120                  $url = hu.$rs['url_title'];
1121                  break;
1122  
1123              case 'section_title':
1124                  $url = hu.join('/', array($rs['Section'], $rs['url_title']));
1125                  break;
1126  
1127              case 'id_title':
1128                  $url = hu.join('/', array($rs['ID'], $rs['url_title']));
1129                  break;
1130  
1131              default:
1132                  //assume messy mode?
1133                  $url = hu.'?id='.$rs['ID'];
1134                  break;
1135          }
1136  
1137          $cat  = $txp->getCategory($rs['Category1']);
1138          $cat1 = $cat['title'];
1139          $cat  = $txp->getCategory($rs['Category2']);
1140          $cat2 = $cat['title'];
1141  
1142          $out = array(
1143              'categories'  => array($cat1, $cat2),
1144              'description' => $rs['Body'],
1145              'userid'      => $txp->txp_user,
1146              'postid'      => $rs['ID'],
1147              'dateCreated' => new IXR_Date($rs['uPosted'] + tz_offset() - $gmtoffset - ($is_dst ? 3600 : 0)),
1148              'link'        => $url,
1149              'permaLink'   => $url,
1150              'title'       => $rs['Title'],
1151          );
1152  
1153          $out['dateCreated']->tz = 'Z'; // GMT
1154  
1155          // MovableType Implementation Add ons
1156          if (isset($rs['Annotate']) && !empty($rs['Annotate']))
1157          {
1158              $out['mt_allow_comments'] = intval($rs['Annotate']);
1159          }
1160  
1161          if (isset($rs['textile_body']) && !empty($rs['textile_body']))
1162          {
1163              $out['mt_convert_breaks'] = strval($rs['textile_body']);
1164          }
1165  
1166          if (isset($rs['Excerpt']) && !empty($rs['Excerpt']))
1167          {
1168              $out['mt_excerpt'] = $rs['Excerpt'];
1169          }
1170  
1171          if (isset($rs['Keywords']) && !empty($rs['Keywords']))
1172          {
1173              $out['mt_keywords'] = $rs['Keywords'];
1174          }
1175  
1176          if (isset($rs['url_title']) && !empty($rs['url_title']))
1177          {
1178              $out['mt_basename'] = $out['wp_slug'] = $rs['url_title'];
1179          }
1180  
1181          return $out;
1182      }
1183  }
1184  
1185  ?>


Generated: Thu May 21 23:03:01 2009 Cross-referenced by PHPXref 0.7