[ Index ] |
PHP Cross Reference of Textpattern 4.0.8 |
[Summary view] [Print] [Text view]
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&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 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu May 21 23:03:01 2009 | Cross-referenced by PHPXref 0.7 |