/var/Widget/XmlRpc.php

http://typecho.googlecode.com/ · PHP · 2093 lines · 1294 code · 216 blank · 583 comment · 182 complexity · bf2e49967123395911f6fd693f80cd05 MD5 · raw file

  1. <?php
  2. /**
  3. * Typecho Blog Platform
  4. *
  5. * @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
  6. * @license GNU General Public License 2.0
  7. * @version $Id$
  8. */
  9. /**
  10. * XmlRpc??
  11. *
  12. * @author blankyao
  13. * @category typecho
  14. * @package Widget
  15. * @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
  16. * @license GNU General Public License 2.0
  17. */
  18. class Widget_XmlRpc extends Widget_Abstract_Contents implements Widget_Interface_Do
  19. {
  20. /**
  21. * ????
  22. *
  23. * @access private
  24. * @var IXR_Error
  25. */
  26. private $error;
  27. /**
  28. * wordpress???????
  29. *
  30. * @access private
  31. * @var array
  32. */
  33. private $_wpOptions;
  34. /**
  35. * ??????????
  36. *
  37. * @access private
  38. * @var array
  39. */
  40. private $_usedWidgetNameList = array();
  41. /**
  42. * ??????
  43. *
  44. * @access private
  45. * @param Widget_Abstract_Contents $content
  46. * @return array
  47. */
  48. private function getPostExtended(Widget_Abstract_Contents $content)
  49. {
  50. //??????????????html??
  51. $agent = $this->request->getAgent();
  52. $text = '';
  53. switch (true) {
  54. case false !== strpos($agent, 'wp-iphone'): // wordpress iphone???
  55. case false !== strpos($agent, 'wp-blackberry'): // ??
  56. case false !== strpos($agent, 'wp-andriod'): // andriod
  57. case false !== strpos($agent, 'plain-text'): // ??????????????, ??????????????
  58. $text = $content->text;
  59. break;
  60. default:
  61. $text = $content->content;
  62. break;
  63. }
  64. $post = explode('<!--more-->', $text, 2);
  65. return array(Typecho_Common::fixHtml($post[0]), isset($post[1]) ? Typecho_Common::fixHtml($post[1]) : NULL);
  66. }
  67. /**
  68. * ?typecho????????wordperss???
  69. *
  70. * @access private
  71. * @param string $status typecho???
  72. * @param string $type ????
  73. * @return string
  74. */
  75. private function typechoToWordpressStatus($status, $type = 'post')
  76. {
  77. if ('post' == $type) {
  78. /** ???? */
  79. switch ($status) {
  80. case 'waiting':
  81. return 'pending';
  82. case 'publish':
  83. case 'draft':
  84. case 'private':
  85. return $status;
  86. default:
  87. return 'publish';
  88. }
  89. } else if ('page' == $type) {
  90. switch ($status) {
  91. case 'publish':
  92. case 'draft':
  93. case 'private':
  94. return $status;
  95. default:
  96. return 'publish';
  97. }
  98. } else if ('comment' == $type) {
  99. switch ($status) {
  100. case 'publish':
  101. case 'approved':
  102. return 'approve';
  103. case 'waiting':
  104. return 'hold';
  105. case 'spam':
  106. return $status;
  107. default:
  108. return 'approve';
  109. }
  110. }
  111. return '';
  112. }
  113. /**
  114. * ?wordpress????????typecho???
  115. *
  116. * @access private
  117. * @param string $status wordpress???
  118. * @param string $type ????
  119. * @return string
  120. */
  121. private function wordpressToTypechoStatus($status, $type = 'post')
  122. {
  123. if ('post' == $type) {
  124. /** ???? */
  125. switch ($status) {
  126. case 'pending':
  127. return 'waiting';
  128. case 'publish':
  129. case 'draft':
  130. case 'private':
  131. case 'waiting':
  132. return $status;
  133. default:
  134. return 'publish';
  135. }
  136. } else if ('page' == $type) {
  137. switch ($status) {
  138. case 'publish':
  139. case 'draft':
  140. case 'private':
  141. return $status;
  142. default:
  143. return 'publish';
  144. }
  145. } else if ('comment' == $type) {
  146. switch ($status) {
  147. case 'approve':
  148. case 'publish':
  149. case 'approved':
  150. return 'approved';
  151. case 'hold':
  152. case 'waiting':
  153. return 'waiting';
  154. case 'spam':
  155. return $status;
  156. default:
  157. return 'approved';
  158. }
  159. }
  160. return '';
  161. }
  162. /**
  163. * ??????,???????????
  164. *
  165. * @access public
  166. * @param string $alias ????
  167. * @param mixed $params ?????
  168. * @param mixed $request ????
  169. * @param boolean $enableResponse ????http??
  170. * @return object
  171. * @throws Typecho_Exception
  172. */
  173. private function singletonWidget($alias, $params = NULL, $request = NULL, $enableResponse = true)
  174. {
  175. $this->_usedWidgetNameList[] = $alias;
  176. return Typecho_Widget::widget($alias, $params, $request, $enableResponse);
  177. }
  178. /**
  179. * ????????, ?????????
  180. *
  181. * @access public
  182. * @param boolen $run ????
  183. * @return void
  184. */
  185. public function execute($run = false)
  186. {
  187. if ($run) {
  188. parent::execute();
  189. }
  190. $this->_wpOptions = array(
  191. // Read only options
  192. 'software_name' => array(
  193. 'desc' => _t( '????' ),
  194. 'readonly' => true,
  195. 'value' => $this->options->software
  196. ),
  197. 'software_version' => array(
  198. 'desc' => _t( '????' ),
  199. 'readonly' => true,
  200. 'value' => $this->options->version
  201. ),
  202. 'blog_url' => array(
  203. 'desc' => _t( '????' ),
  204. 'readonly' => true,
  205. 'option' => 'siteUrl'
  206. ),
  207. // Updatable options
  208. 'time_zone' => array(
  209. 'desc' => _t( '??' ),
  210. 'readonly' => false,
  211. 'option' => 'timezone'
  212. ),
  213. 'blog_title' => array(
  214. 'desc' => _t( '????' ),
  215. 'readonly' => false,
  216. 'option' => 'title'
  217. ),
  218. 'blog_tagline' => array(
  219. 'desc' => _t( '?????' ),
  220. 'readonly' => false,
  221. 'option' => 'description'
  222. ),
  223. 'date_format' => array(
  224. 'desc' => _t( '????' ),
  225. 'readonly' => false,
  226. 'option' => 'postDateFormat'
  227. ),
  228. 'time_format' => array(
  229. 'desc' => _t( '????' ),
  230. 'readonly' => false,
  231. 'option' => 'postDateFormat'
  232. ),
  233. 'users_can_register' => array(
  234. 'desc' => _t( '??????' ),
  235. 'readonly' => false,
  236. 'option' => 'allowRegister'
  237. )
  238. );
  239. }
  240. /**
  241. * ????
  242. *
  243. * @access public
  244. * @return void
  245. */
  246. public function checkAccess($name, $password, $level = 'contributor')
  247. {
  248. if ($this->user->login($name, $password, true)) {
  249. /** ???? */
  250. if ($this->user->pass($level, true)) {
  251. return true;
  252. } else {
  253. $this->error = new IXR_Error(403, _t('????'));
  254. return false;
  255. }
  256. } else {
  257. $this->error = new IXR_Error(403, _t('????, ????'));
  258. return false;
  259. }
  260. }
  261. /** about wp xmlrpc api, you can see http://codex.wordpress.org/XML-RPC*/
  262. /**
  263. * ??pageId???page
  264. *
  265. * @param int $blogId
  266. * @param int $pageId
  267. * @param string $userName
  268. * @param string $password
  269. * @access public
  270. * @return struct $pageStruct
  271. */
  272. public function wpGetPage($blogId, $pageId, $userName, $password)
  273. {
  274. /** ???? */
  275. if (!$this->checkAccess($userName, $password)) {
  276. return $this->error;
  277. }
  278. /** ???? */
  279. try {
  280. /** ??Widget_Contents_Page_Edit??request?????, ??????????flush??request */
  281. /** widget???????????????????widget?request?? */
  282. /** ????????????? */
  283. $page = $this->singletonWidget('Widget_Contents_Page_Edit', NULL, "cid={$pageId}");
  284. } catch (Typecho_Widget_Exception $e) {
  285. /** ??????????(?? Widget_Contents_Page_Edit ? execute ??) */
  286. return new IXR_Error($e->getCode(), $e->getMessage());
  287. }
  288. /** ??????????????description?text_more*/
  289. list($excerpt, $more) = $this->getPostExtended($page);
  290. $pageStruct = array(
  291. 'dateCreated' => new IXR_Date($this->options->timezone + $page->created),
  292. 'userid' => $page->authorId,
  293. 'page_id' => $page->cid,
  294. 'page_status' => $this->typechoToWordpressStatus($page->status, 'page'),
  295. 'description' => $excerpt,
  296. 'title' => $page->title,
  297. 'link' => $page->permalink,
  298. 'permalink' => $page->permalink,
  299. 'categories' => $page->categories,
  300. 'excerpt' => $page->description,
  301. 'text_more' => $more,
  302. 'mt_allow_comments' => intval($page->allowComment),
  303. 'mt_allow_pings' => intval($page->allowPing),
  304. 'wp_slug' => $page->slug,
  305. 'wp_password' => $page->password,
  306. 'wp_author' => $page->author->name,
  307. 'wp_page_parent_id' => '0',
  308. 'wp_page_parent_title' => '',
  309. 'wp_page_order' => $page->order, //meta?????, ?page?????
  310. 'wp_author_id' => $page->authorId,
  311. 'wp_author_display_name' => $page->author->screenName,
  312. 'date_created_gmt' => new IXR_Date($page->created),
  313. 'custom_fields' => array(),
  314. 'wp_page_template' => $page->template
  315. );
  316. return $pageStruct;
  317. }
  318. /**
  319. * ?????page
  320. *
  321. * @param int $blogId
  322. * @param string $userName
  323. * @param string $password
  324. * @access public
  325. * @return array(contains $pageStruct)
  326. */
  327. public function wpGetPages($blogId, $userName, $password)
  328. {
  329. if (!$this->checkAccess($userName, $password)) {
  330. return $this->error;
  331. }
  332. /** ??type?page?contents */
  333. /** ????flush??, ??????status??? */
  334. $pages = $this->singletonWidget('Widget_Contents_Page_Admin', NULL, 'status=all');
  335. /** ??????????? */
  336. $pageStructs = array();
  337. while ($pages->next()) {
  338. /** ??????????????description?text_more*/
  339. list($excerpt, $more) = $this->getPostExtended($pages);
  340. $pageStructs[] = array(
  341. 'dateCreated' => new IXR_Date($this->options->timezone + $pages->created),
  342. 'userid' => $pages->authorId,
  343. 'page_id' => $pages->cid,
  344. /** todo:????? */
  345. 'page_status' => $this->typechoToWordpressStatus($pages->status, 'page'),
  346. 'description' => $excerpt,
  347. 'title' => $pages->title,
  348. 'link' => $pages->permalink,
  349. 'permalink' => $pages->permalink,
  350. 'categories' => $pages->categories,
  351. 'excerpt' => $pages->description,
  352. 'text_more' => $more,
  353. 'mt_allow_comments' => intval($pages->allowComment),
  354. 'mt_allow_pings' => intval($pages->allowPing),
  355. 'wp_slug' => $pages->slug,
  356. 'wp_password' => $pages->password,
  357. 'wp_author' => $pages->author->name,
  358. 'wp_page_parent_id' => '0',
  359. 'wp_page_parent_title' => '',
  360. 'wp_page_order' => $pages->order, //meta?????, ?page?????
  361. 'wp_author_id' => $pages->authorId,
  362. 'wp_author_display_name' => $pages->author->screenName,
  363. 'date_created_gmt' => new IXR_Date($pages->created),
  364. 'custom_fields' => array(),
  365. 'wp_page_template' => $pages->template
  366. );
  367. }
  368. return $pageStructs;
  369. }
  370. /**
  371. * ?????page
  372. *
  373. * @param int $blogId
  374. * @param string $userName
  375. * @param string $password
  376. * @param struct $content
  377. * @param bool $publish
  378. * @access public
  379. * @return void
  380. */
  381. public function wpNewPage($blogId, $userName, $password, $content, $publish)
  382. {
  383. if (!$this->checkAccess($userName, $password, 'editor')) {
  384. return $this->error;
  385. }
  386. $content['post_type'] = 'page';
  387. $this->mwNewPost($blogId, $userName, $password, $content, $publish);
  388. }
  389. /**
  390. * ??pageId???page
  391. *
  392. * @param int $blogId
  393. * @param string $userName
  394. * @param string $password
  395. * @param int $pageId
  396. * @access public
  397. * @return bool
  398. */
  399. public function wpDeletePage($blogId, $userName, $password, $pageId)
  400. {
  401. if (!$this->checkAccess($userName, $password, 'editor')) {
  402. return $this->error;
  403. }
  404. /** ???? */
  405. try {
  406. /** ????????????? */
  407. $this->singletonWidget('Widget_Contents_Page_Edit', NULL, "cid={$pageId}", false)->deletePage();
  408. } catch (Typecho_Widget_Exception $e) {
  409. /** ??????????(?? Widget_Contents_Page_Edit ? execute ??) */
  410. return new IXR_Error($e->getCode(), $e->getMessage());
  411. }
  412. return true;
  413. }
  414. /**
  415. * ??pageId???page
  416. *
  417. * @param int $blogId
  418. * @param int $pageId
  419. * @param string $userName
  420. * @param string $password
  421. * @param struct $content
  422. * @param bool $publish
  423. * @access public
  424. * @return bool
  425. */
  426. public function wpEditPage($blogId, $pageId, $userName, $password, $content, $publish)
  427. {
  428. $content['type'] = 'page';
  429. $this->mwEditPost($blogId, $pageId, $userName, $password, $content, $publish);
  430. }
  431. /**
  432. * ??page?????wpGetPages?????
  433. *
  434. * @param int $blogId
  435. * @param string $userName
  436. * @param string $password
  437. * @access public
  438. * @return array
  439. */
  440. public function wpGetPageList($blogId, $userName, $password)
  441. {
  442. if (!$this->checkAccess($userName, $password, 'editor')) {
  443. return ($this->error);
  444. }
  445. $pages = $this->singletonWidget('Widget_Contents_Page_Admin', NULL, 'status=all');
  446. /**???*/
  447. $pageStructs = array();
  448. while ($pages->next()) {
  449. $pageStructs[] = array(
  450. 'dateCreated' => new IXR_Date($this->options->timezone + $pages->created),
  451. 'date_created_gmt' => new IXR_Date($this->options->timezone + $pages->created),
  452. 'page_id' => $pages->cid,
  453. 'page_title' => $pages->title,
  454. 'page_parent_id' => '0',
  455. );
  456. }
  457. return $pageStructs;
  458. }
  459. /**
  460. * ?????blog????????????
  461. *
  462. * @param int $blogId
  463. * @param string $userName
  464. * @param string $password
  465. * @access public
  466. * @return struct
  467. */
  468. public function wpGetAuthors($blogId, $userName, $password)
  469. {
  470. if (!$this->checkAccess($userName, $password, 'editor')) {
  471. return ($this->error);
  472. }
  473. /** ????*/
  474. $select = $this->db->select('table.users.uid', 'table.users.name', 'table.users.screenName')->from('table.users');
  475. $authors = $this->db->fetchAll($select);
  476. $authorStructs = array();
  477. foreach ($authors as $author) {
  478. $authorStructs[] = array(
  479. 'user_id' => $author['uid'],
  480. 'user_login' => $author['name'],
  481. 'display_name' => $author['screenName']
  482. );
  483. }
  484. return $authorStructs;
  485. }
  486. /**
  487. * ????????
  488. *
  489. * @param int $blogId
  490. * @param string $userName
  491. * @param string $password
  492. * @param struct $category
  493. * @access public
  494. * @return void
  495. */
  496. public function wpNewCategory($blogId, $userName, $password, $category)
  497. {
  498. if (!$this->checkAccess($userName, $password)) {
  499. return ($this->error);
  500. }
  501. /** ?????? */
  502. $input['name'] = $category['name'];
  503. $input['slug'] = Typecho_Common::slugName(empty($category['slug']) ? $category['name'] : $category['slug']);
  504. $input['type'] = 'category';
  505. $input['description'] = isset($category['description']) ? $category['description'] : $category['name'];
  506. $input['do'] = 'insert';
  507. /** ?????? */
  508. try {
  509. /** ?? */
  510. $this->singletonWidget('Widget_Metas_Category_Edit', NULL, $input, false)->action();
  511. return $this->singletonWidget('Widget_Notice')->getHighlightId() ? true : false;
  512. } catch (Typecho_Widget_Exception $e) {
  513. return new IXR_Error($e->getCode(), $e->getMessage());
  514. }
  515. return true;
  516. }
  517. /**
  518. * ??????string??????????
  519. *
  520. * @param int $blogId
  521. * @param string $userName
  522. * @param string $password
  523. * @param string $category
  524. * @param int $max_results
  525. * @access public
  526. * @return array
  527. */
  528. public function wpSuggestCategories($blogId, $userName, $password, $category, $max_results)
  529. {
  530. if (!$this->checkAccess($userName, $password)) {
  531. return ($this->error);
  532. }
  533. $meta = $this->singletonWidget('Widget_Abstract_Metas');
  534. /** ???????????*/
  535. $key = Typecho_Common::filterSearchQuery($category);
  536. $key = '%' . $key . '%';
  537. $select = $meta->select()->where('table.metas.type = ? AND (table.metas.name LIKE ? OR slug LIKE ?)', 'category', $key, $key);
  538. /** ??category push?contents???? */
  539. $categories = $this->db->fetchAll($select);
  540. /** ???categorise??*/
  541. $categoryStructs = array();
  542. foreach ($categories as $category) {
  543. $categoryStructs[] = array(
  544. 'category_id' => $category['mid'],
  545. 'category_name' => $category['name'],
  546. );
  547. }
  548. return $categoryStructs;
  549. }
  550. /**
  551. * ????
  552. *
  553. * @access public
  554. * @param string $userName ???
  555. * @param string $password ??
  556. * @return array
  557. */
  558. public function wpGetUsersBlogs($userName, $password)
  559. {
  560. if (!$this->checkAccess($userName, $password)) {
  561. return $this->error;
  562. }
  563. $struct = array();
  564. $struct[] = array(
  565. 'isAdmin' => $this->user->pass('administrator', true),
  566. 'url' => $this->options->siteUrl,
  567. 'blogid' => '1',
  568. 'blogName' => $this->options->title,
  569. 'xmlrpc' => $this->options->xmlRpcUrl
  570. );
  571. return $struct;
  572. }
  573. /**
  574. * ??????
  575. *
  576. * @access public
  577. * @param integer $blogId
  578. * @param string $userName
  579. * @param string $password
  580. * @return array
  581. */
  582. public function wpGetTags($blogId, $userName, $password)
  583. {
  584. /** ????*/
  585. if (!$this->checkAccess($userName, $password)) {
  586. return $this->error;
  587. }
  588. $struct = array();
  589. $tags = $this->singletonWidget('Widget_Metas_Tag_Cloud');
  590. while ($tags->next()) {
  591. $struct[] = array(
  592. 'tag_id' => $tags->mid,
  593. 'name' => $tags->name,
  594. 'count' => $tags->count,
  595. 'slug' => $tags->slug,
  596. 'html_url' => $tags->permalink,
  597. 'rss_url' => $tags->feedUrl
  598. );
  599. }
  600. return $struct;
  601. }
  602. /**
  603. * ????
  604. *
  605. * @access public
  606. * @param integer $blogId
  607. * @param string $userName
  608. * @param string $password
  609. * @param integer $categoryId
  610. * @return array
  611. */
  612. public function wpDeleteCategory($blogId, $userName, $password, $categoryId)
  613. {
  614. /** ????*/
  615. if (!$this->checkAccess($userName, $password, 'editor')) {
  616. return $this->error;
  617. }
  618. try {
  619. $this->singletonWidget('Widget_Metas_Category_Edit', NULL, 'do=delete&mid=' . intval($categoryId), false);
  620. return true;
  621. } catch (Typecho_Exception $e) {
  622. return false;
  623. }
  624. }
  625. /**
  626. * ??????
  627. *
  628. * @access public
  629. * @param integer $blogId
  630. * @param string $userName
  631. * @param string $password
  632. * @param integer $postId
  633. * @return array
  634. */
  635. public function wpGetCommentCount($blogId, $userName, $password, $postId)
  636. {
  637. /** ????*/
  638. if (!$this->checkAccess($userName, $password)) {
  639. return $this->error;
  640. }
  641. $stat = $this->singletonWidget('Widget_Stat', NULL, 'cid=' . intval($postId), false);
  642. return array(
  643. 'approved' => $stat->currentPublishedCommentsNum,
  644. 'awaiting_moderation' => $stat->currentWaitingCommentsNum,
  645. 'spam' => $stat->currentSpamCommentsNum,
  646. 'total_comments' => $stat->currentCommentsNum
  647. );
  648. }
  649. /**
  650. * ????????
  651. *
  652. * @access public
  653. * @param integer $blogId
  654. * @param string $userName
  655. * @param string $password
  656. * @return array
  657. */
  658. public function wpGetPostStatusList($blogId, $userName, $password)
  659. {
  660. /** ????*/
  661. if (!$this->checkAccess($userName, $password)) {
  662. return $this->error;
  663. }
  664. return array(
  665. 'draft' => _t('??'),
  666. 'pending' => _t('???'),
  667. 'publish' => _t('???')
  668. );
  669. }
  670. /**
  671. * ????????
  672. *
  673. * @access public
  674. * @param integer $blogId
  675. * @param string $userName
  676. * @param string $password
  677. * @return array
  678. */
  679. public function wpGetPageStatusList($blogId, $userName, $password)
  680. {
  681. /** ????*/
  682. if (!$this->checkAccess($userName, $password, 'editor')) {
  683. return $this->error;
  684. }
  685. return array(
  686. 'draft' => _t('??'),
  687. 'publish' => _t('???')
  688. );
  689. }
  690. /**
  691. * ????????
  692. *
  693. * @access public
  694. * @param integer $blogId
  695. * @param string $userName
  696. * @param string $password
  697. * @return array
  698. */
  699. public function wpGetCommentStatusList($blogId, $userName, $password)
  700. {
  701. /** ????*/
  702. if (!$this->checkAccess($userName, $password)) {
  703. return $this->error;
  704. }
  705. return array(
  706. 'hold' => _t('???'),
  707. 'approve' => _t('??'),
  708. 'spam' => _t('??')
  709. );
  710. }
  711. /**
  712. * ??????
  713. *
  714. * @access public
  715. * @param integer $blogId
  716. * @param string $userName
  717. * @param string $password
  718. * @return array
  719. */
  720. public function wpGetPageTemplates($blogId, $userName, $password)
  721. {
  722. /** ????*/
  723. if (!$this->checkAccess($userName, $password, 'editor')) {
  724. return $this->error;
  725. }
  726. $templates = array_flip($this->getTemplates());
  727. $templates['Default'] = '';
  728. return $templates;
  729. }
  730. /**
  731. * ??????
  732. *
  733. * @access public
  734. * @param integer $blogId
  735. * @param string $userName
  736. * @param string $password
  737. * @param array $options
  738. * @return array
  739. */
  740. public function wpGetOptions($blogId, $userName, $password, $options = array())
  741. {
  742. /** ????*/
  743. if (!$this->checkAccess($userName, $password, 'administrator')) {
  744. return $this->error;
  745. }
  746. $struct = array();
  747. if (empty($options)) {
  748. $options = array_keys($this->_wpOptions);
  749. }
  750. foreach ($options as $option) {
  751. if (isset($this->_wpOptions[$option])) {
  752. $struct[$option] = $this->_wpOptions[$option];
  753. if (isset($struct[$option]['option'])) {
  754. $struct[$option]['value'] = $this->options->{$struct[$option]['option']};
  755. unset($struct[$option]['option']);
  756. }
  757. }
  758. }
  759. return $struct;
  760. }
  761. /**
  762. * ??????
  763. *
  764. * @access public
  765. * @param integer $blogId
  766. * @param string $userName
  767. * @param string $password
  768. * @param array $options
  769. * @return array
  770. */
  771. public function wpSetOptions($blogId, $userName, $password, $options = array())
  772. {
  773. /** ????*/
  774. if (!$this->checkAccess($userName, $password, 'administrator')) {
  775. return $this->error;
  776. }
  777. $struct = array();
  778. foreach ($options as $option => $value) {
  779. if (isset($this->_wpOptions[$option])) {
  780. $struct[$option] = $this->_wpOptions[$option];
  781. if (isset($struct[$option]['option'])) {
  782. $struct[$option]['value'] = $this->options->{$struct[$option]['option']};
  783. unset($struct[$option]['option']);
  784. }
  785. if (!$this->_wpOptions[$option]['readonly'] && isset($this->_wpOptions[$option]['option'])) {
  786. if ($db->query($db->update('table.options')
  787. ->rows(array('value' => $value))
  788. ->where('name = ?', $this->_wpOptions[$option]['option'])) > 0) {
  789. $struct[$option]['value'] = $value;
  790. }
  791. }
  792. }
  793. }
  794. return $struct;
  795. }
  796. /**
  797. * ????
  798. *
  799. * @access public
  800. * @param integer $blogId
  801. * @param string $userName
  802. * @param string $password
  803. * @param integer $commentId
  804. * @return array
  805. */
  806. public function wpGetComment($blogId, $userName, $password, $commentId)
  807. {
  808. /** ????*/
  809. if (!$this->checkAccess($userName, $password)) {
  810. return $this->error;
  811. }
  812. $comment = $this->singletonWidget('Widget_Comments_Edit', NULL, 'do=get&coid=' . intval($commentId), false);
  813. if (!$comment->have()) {
  814. return new IXR_Error(404, _t('?????'));
  815. }
  816. if (!$comment->commentIsWriteable()) {
  817. return new IXR_Error(403, _t('?????????'));
  818. }
  819. return array(
  820. 'date_created_gmt' => new IXR_Date($this->options->timezone + $comment->created),
  821. 'user_id' => $comment->authorId,
  822. 'comment_id' => $comment->coid,
  823. 'parent' => $comment->parent,
  824. 'status' => $this->typechoToWordpressStatus($comment->status, 'comment'),
  825. 'content' => $comment->text,
  826. 'link' => $comment->permalink,
  827. 'post_id' => $comment->cid,
  828. 'post_title' => $comment->title,
  829. 'author' => $comment->author,
  830. 'author_url' => $comment->url,
  831. 'author_email' => $comment->mail,
  832. 'author_ip' => $comment->ip,
  833. 'type' => $comment->type
  834. );
  835. }
  836. /**
  837. * ??????
  838. *
  839. * @access public
  840. * @param integer $blogId
  841. * @param string $userName
  842. * @param string $password
  843. * @param array $struct
  844. * @return array
  845. */
  846. public function wpGetComments($blogId, $userName, $password, $struct)
  847. {
  848. /** ????*/
  849. if (!$this->checkAccess($userName, $password)) {
  850. return $this->error;
  851. }
  852. $input = array();
  853. if (!empty($struct['status'])) {
  854. $input['status'] = 'hold' == $input['status'] ? $input['status'] :
  855. $this->wordpressToTypechoStatus($struct['status']);
  856. } else {
  857. $input['__typecho_all_comments'] = 'on';
  858. }
  859. if (!empty($struct['post_id'])) {
  860. $input['cid'] = $struct['post_id'];
  861. }
  862. $pageSize = 10;
  863. if (!empty($struct['number'])) {
  864. $pageSize = abs(intval($struct['number']));
  865. }
  866. if (!empty($struct['offset'])) {
  867. $offset = abs(intval($struct['offset']));
  868. $input['page'] = ceil($offset / $pageSize);
  869. }
  870. $comments = $this->singletonWidget('Widget_Comments_Admin', 'pageSize=' . $pageSize, $input, false);
  871. $commentsStruct = array();
  872. while ($comments->next()) {
  873. $commentsStruct[] = array(
  874. 'date_created_gmt' => new IXR_Date($this->options->timezone + $comments->created),
  875. 'user_id' => $comments->authorId,
  876. 'comment_id' => $comments->coid,
  877. 'parent' => $comments->parent,
  878. 'status' => $this->typechoToWordpressStatus($comments->status, 'comment'),
  879. 'content' => $comments->text,
  880. 'link' => $comments->permalink,
  881. 'post_id' => $comments->cid,
  882. 'post_title' => $comments->title,
  883. 'author' => $comments->author,
  884. 'author_url' => $comments->url,
  885. 'author_email' => $comments->mail,
  886. 'author_ip' => $comments->ip,
  887. 'type' => $comments->type
  888. );
  889. }
  890. return $commentsStruct;
  891. }
  892. /**
  893. * ????
  894. *
  895. * @access public
  896. * @param integer $blogId
  897. * @param string $userName
  898. * @param string $password
  899. * @param integer $commentId
  900. * @return boolean
  901. */
  902. public function wpDeleteComment($blogId, $userName, $password, $commentId)
  903. {
  904. /** ????*/
  905. if (!$this->checkAccess($userName, $password)) {
  906. return $this->error;
  907. }
  908. $commentId = abs(intval($commentId));
  909. return intval($this->singletonWidget('Widget_Abstract_Comments')->delete(
  910. $this->db->sql()->where('coid = ?', $commentId))) > 0;
  911. }
  912. /**
  913. * ????
  914. *
  915. * @access public
  916. * @param integer $blogId
  917. * @param string $userName
  918. * @param string $password
  919. * @param integer $commentId
  920. * @param array $struct
  921. * @return boolean
  922. */
  923. public function wpEditComment($blogId, $userName, $password, $commentId, $struct)
  924. {
  925. /** ????*/
  926. if (!$this->checkAccess($userName, $password)) {
  927. return $this->error;
  928. }
  929. $commentId = abs(intval($commentId));
  930. $commentWidget = $this->singletonWidget('Widget_Abstract_Comments');
  931. $where = $this->db->sql()->where('coid = ?', $commentId);
  932. if (!$commentWidget->commentIsWriteable($where)) {
  933. return new IXR_Error(403, _t('???????'));
  934. }
  935. $input = array();
  936. if (isset($struct['date_created_gmt'])) {
  937. $input['created'] = $struct['date_created_gmt']->getTimestamp() - $this->options->timezone + $this->options->serverTimezone;
  938. }
  939. if (isset($struct['status'])) {
  940. $input['status'] = $this->wordpressToTypechoStatus($struct['status'], 'comment');
  941. }
  942. if (isset($struct['content'])) {
  943. $input['text'] = $struct['content'];
  944. }
  945. if (isset($struct['author'])) {
  946. $input['author'] = $struct['author'];
  947. }
  948. if (isset($struct['author_url'])) {
  949. $input['url'] = $struct['author_url'];
  950. }
  951. if (isset($struct['author_email'])) {
  952. $input['mail'] = $struct['author_email'];
  953. }
  954. $result = $commentWidget->update((array) $input, $where);
  955. if (!$result) {
  956. return new IXR_Error(404, _t('?????'));
  957. }
  958. return true;
  959. }
  960. /**
  961. * ????
  962. *
  963. * @access public
  964. * @param integer $blogId
  965. * @param string $userName
  966. * @param string $password
  967. * @param mixed $post
  968. * @param array $struct
  969. * @return boolean
  970. */
  971. public function wpNewComment($blogId, $userName, $password, $path, $struct)
  972. {
  973. /** ????*/
  974. if (!$this->checkAccess($userName, $password)) {
  975. return $this->error;
  976. }
  977. if (is_numeric($path)) {
  978. $post = $this->singletonWidget('Widget_Archive', 'type=single', 'cid=' . $path, false);
  979. } else {
  980. /** ??????????*/
  981. $pathInfo = Typecho_Common::url(substr($path, strlen($this->options->index)), '/');
  982. $post = Typecho_Router::match($pathInfo);
  983. }
  984. /** ??????cid??slug*/
  985. if (!isset($post) || !($post instanceof Widget_Archive) || !$post->have() || !$post->is('single')) {
  986. return new IXR_Error(404, _t('?????????'));
  987. }
  988. $input = array();
  989. $input['permalink'] = $post->pathinfo;
  990. $input['type'] = 'comment';
  991. if (isset($struct['comment_author'])) {
  992. $input['author'] = $struct['author'];
  993. }
  994. if (isset($struct['comment_author_email'])) {
  995. $input['mail'] = $struct['author_email'];
  996. }
  997. if (isset($struct['comment_author_url'])) {
  998. $input['url'] = $struct['author_url'];
  999. }
  1000. if (isset($struct['comment_parent'])) {
  1001. $input['parent'] = $struct['comment_parent'];
  1002. }
  1003. if (isset($struct['content'])) {
  1004. $input['text'] = $struct['content'];
  1005. }
  1006. try {
  1007. $this->singletonWidget('Widget_Feedback', NULL, $input, false);
  1008. } catch (Typecho_Exception $e) {
  1009. return new IXR_Error(500, $e->getMessage());
  1010. }
  1011. return true;
  1012. }
  1013. /**about MetaWeblog API, you can see http://www.xmlrpc.com/metaWeblogApi*/
  1014. /**
  1015. * MetaWeblog API
  1016. *
  1017. * @param int $blogId
  1018. * @param string $userName
  1019. * @param string $password
  1020. * @param struct $content
  1021. * @param bool $publish
  1022. * @access public
  1023. * @return int
  1024. */
  1025. public function mwNewPost($blogId, $userName, $password, $content, $publish)
  1026. {
  1027. /** ????*/
  1028. if (!$this->checkAccess($userName, $password)) {
  1029. return $this->error;
  1030. }
  1031. /** ??content?? */
  1032. $input = array();
  1033. $type = isset($content['post_type']) && 'page' == $content['post_type'] ? 'page' : 'post';
  1034. $input['title'] = trim($content['title']) == NULL ? _t('?????') : $content['title'];
  1035. if (isset($content['slug'])) {
  1036. $input['slug'] = $content['slug'];
  1037. } else if (isset($content['wp_slug'])) {
  1038. //fix issue 338, wlw?????
  1039. $input['slug'] = $content['wp_slug'];
  1040. }
  1041. $input['text'] = !empty($content['mt_text_more']) ? $content['description']
  1042. . "\n<!--more-->\n" . $content['mt_text_more'] : $content['description'];
  1043. $input['text'] = $this->pluginHandle()->textFilter($input['text'], $this);
  1044. $input['password'] = isset($content["wp_password"]) ? $content["wp_password"] : NULL;
  1045. $input['order'] = isset($content["wp_page_order"]) ? $content["wp_page_order"] : NULL;
  1046. $input['tags'] = isset($content['mt_keywords']) ? $content['mt_keywords'] : NULL;
  1047. $input['category'] = array();
  1048. if (isset($content['postId'])) {
  1049. $input['cid'] = $content['postId'];
  1050. }
  1051. if ('page' == $type && isset($content['wp_page_template'])) {
  1052. $input['template'] = $content['wp_page_template'];
  1053. }
  1054. if (isset($content['dateCreated'])) {
  1055. /** ?????????????? */
  1056. $input['created'] = $content['dateCreated']->getTimestamp() - $this->options->timezone + $this->options->serverTimezone;
  1057. }
  1058. if (!empty($content['categories']) && is_array($content['categories'])) {
  1059. foreach ($content['categories'] as $category) {
  1060. if (!$this->db->fetchRow($this->db->select('mid')
  1061. ->from('table.metas')->where('type = ? AND name = ?', 'category', $category))) {
  1062. $result = $this->wpNewCategory($blogId, $userName, $password, array('name' => $category));
  1063. if (true !== $result) {
  1064. return $result;
  1065. }
  1066. }
  1067. $input['category'][] = $this->db->fetchObject($this->db->select('mid')
  1068. ->from('table.metas')->where('type = ? AND name = ?', 'category', $category)
  1069. ->limit(1))->mid;
  1070. }
  1071. }
  1072. $input['allowComment'] = (isset($content['mt_allow_comments']) && (1 == $content['mt_allow_comments']
  1073. || 'open' == $content['mt_allow_comments'])) ? 1 : ((isset($content['mt_allow_comments']) && (0 == $content['mt_allow_comments']
  1074. || 'closed' == $content['mt_allow_comments'])) ? 0 : $this->options->defaultAllowComment);
  1075. $input['allowPing'] = (isset($content['mt_allow_pings']) && (1 == $content['mt_allow_pings']
  1076. || 'open' == $content['mt_allow_pings'])) ? 1 : ((isset($content['mt_allow_pings']) && (0 == $content['mt_allow_pings']
  1077. || 'closed' == $content['mt_allow_pings'])) ? 0 : $this->options->defaultAllowPing);
  1078. $input['allowFeed'] = $this->options->defaultAllowFeed;
  1079. $input['do'] = $publish ? 'publish' : 'save';
  1080. /** ???? */
  1081. if (isset($content["{$type}_status"])) {
  1082. $status = $this->wordpressToTypechoStatus($content["{$type}_status"], $type);
  1083. if ('publish' == $status || 'waiting' == $status || 'private' == $status) {
  1084. $input['do'] = 'publish';
  1085. if ('private' == $status) {
  1086. $input['private'] = 1;
  1087. }
  1088. } else {
  1089. $input['do'] = 'save';
  1090. }
  1091. }
  1092. /** ?????????? */
  1093. $unattached = $this->db->fetchAll($this->select()->where('table.contents.type = ? AND
  1094. (table.contents.parent = 0 OR table.contents.parent IS NULL)', 'attachment'), array($this, 'filter'));
  1095. if (!empty($unattached)) {
  1096. foreach ($unattached as $attach) {
  1097. if (false !== strpos($input['text'], $attach['attachment']->url)) {
  1098. if (!isset($input['attachment'])) {
  1099. $input['attachment'] = array();
  1100. }
  1101. $input['attachment'][] = $attach['cid'];
  1102. }
  1103. }
  1104. }
  1105. /** ?????? */
  1106. try {
  1107. /** ?? */
  1108. if ('page' == $type) {
  1109. $this->singletonWidget('Widget_Contents_Page_Edit', NULL, $input, false)->action();
  1110. } else {
  1111. $this->singletonWidget('Widget_Contents_Post_Edit', NULL, $input, false)->action();
  1112. }
  1113. return $this->singletonWidget('Widget_Notice')->getHighlightId();
  1114. } catch (Typecho_Widget_Exception $e) {
  1115. return new IXR_Error($e->getCode(), $e->getMessage());
  1116. }
  1117. }
  1118. /**
  1119. * ??post
  1120. *
  1121. * @param int $postId
  1122. * @param string $userName
  1123. * @param string $password
  1124. * @param struct $content
  1125. * @param bool $publish
  1126. * @access public
  1127. * @return int
  1128. */
  1129. public function mwEditPost($postId, $userName, $password, $content, $publish = true)
  1130. {
  1131. $content['postId'] = $postId;
  1132. return $this->mwNewPost(1, $userName, $password, $content, $publish);
  1133. }
  1134. /**
  1135. * ????id?post
  1136. *
  1137. * @param int $postId
  1138. * @param string $userName
  1139. * @param string $password
  1140. * @access public
  1141. * @return void
  1142. */
  1143. public function mwGetPost($postId, $userName, $password)
  1144. {
  1145. if (!$this->checkAccess($userName, $password)) {
  1146. return $this->error;
  1147. }
  1148. try {
  1149. $post = $this->singletonWidget('Widget_Contents_Post_Edit', NULL, "cid={$postId}");
  1150. } catch (Typecho_Widget_Exception $e) {
  1151. return new IXR_Error($e->getCode(), $e->getMessage());
  1152. }
  1153. /** ??????????????description?text_more*/
  1154. list($excerpt, $more) = $this->getPostExtended($post);
  1155. /** ??????name*/
  1156. $categories = Typecho_Common::arrayFlatten($post->categories, 'name');
  1157. $tags = Typecho_Common::arrayFlatten($post->tags, 'name');
  1158. $postStruct = array(
  1159. 'dateCreated' => new IXR_Date($this->options->timezone + $post->created),
  1160. 'userid' => $post->authorId,
  1161. 'postid' => $post->cid,
  1162. 'description' => $excerpt,
  1163. 'title' => $post->title,
  1164. 'link' => $post->permalink,
  1165. 'permalink' => $post->permalink,
  1166. 'categories' => $categories,
  1167. 'mt_excerpt' => $post->description,
  1168. 'mt_text_more' => $more,
  1169. 'mt_allow_comments' => intval($post->allowComment),
  1170. 'mt_allow_pings' => intval($post->allowPing),
  1171. 'mt_keywords' => implode(', ', $tags),
  1172. 'wp_slug' => $post->slug,
  1173. 'wp_password' => $post->password,
  1174. 'wp_author' => $post->author->name,
  1175. 'wp_author_id' => $post->authorId,
  1176. 'wp_author_display_name' => $post->author->screenName,
  1177. 'date_created_gmt' => new IXR_Date($post->created),
  1178. 'post_status' => $this->typechoToWordpressStatus($post->status, 'post'),
  1179. 'custom_fields' => array(),
  1180. 'sticky' => 0
  1181. );
  1182. return $postStruct;
  1183. }
  1184. /**
  1185. * ???$postsNum?post
  1186. *
  1187. * @param int $blogId
  1188. * @param string $userName
  1189. * @param string $password
  1190. * @param int $postsNum
  1191. * @access public
  1192. * @return postStructs
  1193. */
  1194. public function mwGetRecentPosts($blogId, $userName, $password, $postsNum)
  1195. {
  1196. if (!$this->checkAccess($userName, $password)) {
  1197. return $this->error;
  1198. }
  1199. $posts = $this->singletonWidget('Widget_Contents_Post_Admin', "pageSize={$postsNum}", 'status=all');
  1200. $postStructs = array();
  1201. /** ????post???????????? */
  1202. while ($posts->next()) {
  1203. /** ??????????????description?text_more*/
  1204. list($excerpt, $more) = $this->getPostExtended($posts);
  1205. /** ??????name*/
  1206. /** ???flatten???? */
  1207. $categories = Typecho_Common::arrayFlatten($posts->categories, 'name');
  1208. $tags = Typecho_Common::arrayFlatten($posts->tags, 'name');
  1209. $postStructs[] = array(
  1210. 'dateCreated' => new IXR_Date($this->options->timezone + $posts->created),
  1211. 'userid' => $posts->authorId,
  1212. 'postid' => $posts->cid,
  1213. 'description' => $excerpt,
  1214. 'title' => $posts->title,
  1215. 'link' => $posts->permalink,
  1216. 'permalink' => $posts->permalink,
  1217. 'categories' => $categories,
  1218. 'mt_excerpt' => $posts->description,
  1219. 'mt_text_more' => $more,
  1220. 'mt_allow_comments' => intval($posts->allowComment),
  1221. 'mt_allow_pings' => intval($posts->allowPing),
  1222. 'mt_keywords' => implode(', ', $tags),
  1223. 'wp_slug' => $posts->slug,
  1224. 'wp_password' => $posts->password,
  1225. 'wp_author' => $posts->author->name,
  1226. 'wp_author_id' => $posts->authorId,
  1227. 'wp_author_display_name' => $posts->author->screenName,
  1228. 'date_created_gmt' => new IXR_Date($posts->created),
  1229. 'post_status' => $this->typechoToWordpressStatus($posts->status, 'post'),
  1230. 'custom_fields' => array(),
  1231. 'sticky' => 0
  1232. );
  1233. }
  1234. return $postStructs;
  1235. }
  1236. /**
  1237. * ???????
  1238. *
  1239. * @param int $blogId
  1240. * @param string $userName
  1241. * @param string $password
  1242. * @access public
  1243. * @return categoryStructs
  1244. */
  1245. public function mwGetCategories($blogId, $userName, $password)
  1246. {
  1247. if (!$this->checkAccess($userName, $password)) {
  1248. return ($this->error);
  1249. }
  1250. $categories = $this->singletonWidget('Widget_Metas_Category_List');
  1251. /** ???category??*/
  1252. $categoryStructs = array();
  1253. while ($categories->next()) {
  1254. $categoryStructs[] = array(
  1255. 'categoryId' => $categories->mid,
  1256. 'parentId' => '0',
  1257. 'categoryName' => $categories->name,
  1258. 'categoryDescription' => $categories->description,
  1259. 'description' => $categories->name,
  1260. 'htmlUrl' => $categories->permalink,
  1261. 'rssUrl' => $categories->feedUrl,
  1262. );
  1263. }
  1264. return $categoryStructs;
  1265. }
  1266. /**
  1267. * mwNewMediaObject
  1268. *
  1269. * @param int $blogId
  1270. * @param string $userName
  1271. * @param string $password
  1272. * @param mixed $data
  1273. * @access public
  1274. * @return void
  1275. */
  1276. public function mwNewMediaObject($blogId, $userName, $password, $data)
  1277. {
  1278. if (!$this->checkAccess($userName, $password)) {
  1279. return $this->error;
  1280. }
  1281. $result = Widget_Upload::uploadHandle($data);
  1282. if (false === $result) {
  1283. return IXR_Error(500, _t('????'));
  1284. } else {
  1285. $insertId = $this->insert(array(
  1286. 'title' => $result['name'],
  1287. 'slug' => $result['name'],
  1288. 'type' => 'attachment',
  1289. 'status' => 'publish',
  1290. 'text' => serialize($result),
  1291. 'allowComment' => 1,
  1292. 'allowPing' => 0,
  1293. 'allowFeed' => 1
  1294. ));
  1295. $this->db->fetchRow($this->select()->where('table.contents.cid = ?', $insertId)
  1296. ->where('table.contents.type = ?', 'attachment'), array($this, 'push'));
  1297. /** ?????? */
  1298. $this->pluginHandle()->upload($this);
  1299. return array(
  1300. 'file' => $this->attachment->name,
  1301. 'url' => $this->attachment->url
  1302. );
  1303. }
  1304. }
  1305. /**
  1306. * ?? $postNum?post title
  1307. *
  1308. * @param int $blogId
  1309. * @param string $userName
  1310. * @param string $password
  1311. * @param int $postNum
  1312. * @access public
  1313. * @return postTitleStructs
  1314. */
  1315. public function mtGetRecentPostTitles($blogId, $userName, $password, $postsNum)
  1316. {
  1317. if (!$this->checkAccess($userName, $password)) {
  1318. return ($this->error);
  1319. }
  1320. /** ????*/
  1321. $posts = $this->singletonWidget('Widget_Contents_Post_Admin', "pageSize=$postsNum", 'status=all');
  1322. /**???*/
  1323. $postTitleStructs = array();
  1324. while ($posts->next()) {
  1325. $postTitleStructs[] = array(
  1326. 'dateCreated' => new IXR_Date($this->options->timezone + $posts->created),
  1327. 'userid' => $posts->authorId,
  1328. 'postid' => $posts->cid,
  1329. 'title' => $posts->title,
  1330. 'date_created_gmt' => new IXR_Date($this->options->timezone + $posts->created)
  1331. );
  1332. }
  1333. return $postTitleStructs;
  1334. }
  1335. /**
  1336. * ??????
  1337. *
  1338. * @param int $blogId
  1339. * @param string $userName
  1340. * @param string $password
  1341. * @access public
  1342. * @return categories
  1343. */
  1344. public function mtGetCategoryList($blogId, $userName, $password)
  1345. {
  1346. if (!$this->checkAccess($userName, $password)) {
  1347. return ($this->error);
  1348. }
  1349. $categories = $this->singletonWidget('Widget_Metas_Category_List');
  1350. /** ???categorise??*/
  1351. $categoryStructs = array();
  1352. while ($categories->next()) {
  1353. $categoryStructs[] = array(
  1354. 'categoryId' => $categories->mid,
  1355. 'categoryName' => $categories->name,
  1356. );
  1357. }
  1358. return $categoryStructs;
  1359. }
  1360. /**
  1361. * ????post???
  1362. *
  1363. * @param int $postId
  1364. * @param string $userName
  1365. * @param string $password
  1366. * @access public
  1367. * @return void
  1368. */
  1369. public function mtGetPostCategories($postId, $userName, $password)
  1370. {
  1371. if (!$this->checkAccess($userName, $password)) {
  1372. return $this->error;
  1373. }
  1374. try {
  1375. $post = $this->singletonWidget('Widget_Contents_Post_Edit', NULL, "cid={$postId}");
  1376. } catch (Typecho_Widget_Exception $e) {
  1377. return new IXR_Error($e->getCode(), $e->getMessage());
  1378. }
  1379. /** ???categories*/
  1380. $categories = array();
  1381. foreach ($post->categories as $category) {
  1382. $categories[] = array(
  1383. 'categoryName' => $category['name'],
  1384. 'categoryId' => $category['mid'],
  1385. 'isPrimary' => true
  1386. );
  1387. }
  1388. return $categories;
  1389. }
  1390. /**
  1391. * ??post???
  1392. *
  1393. * @param int $postId
  1394. * @param string $userName
  1395. * @param string $password
  1396. * @param string $categories
  1397. * @access public
  1398. * @return bool
  1399. */
  1400. public function mtSetPostCategories($postId, $userName, $password, $categories)
  1401. {
  1402. if (!$this->checkAccess($userName, $password, 'editor')) {
  1403. return $this->error;
  1404. }
  1405. try {
  1406. $post = $this->singletonWidget('Widget_Contents_Post_Edit', NULL, "cid={$postId}");
  1407. } catch (Typecho_Widget_Exception $e) {
  1408. return new IXR_Error($e->getCode(), $e->getMessage());
  1409. }
  1410. $post->setCategories($postId, Typecho_Common::arrayFlatten($categories, 'categoryId'),
  1411. 'publish' == $post->status);
  1412. return true;
  1413. }
  1414. /**
  1415. * ??(??)??
  1416. *
  1417. * @param int $postId
  1418. * @param string $userName
  1419. * @param string $password
  1420. * @access public
  1421. * @return bool
  1422. */
  1423. public function mtPublishPost($postId, $userName, $password)
  1424. {
  1425. if (!$this->checkAccess($userName, $password, 'editor')) {
  1426. return $this->error;
  1427. }
  1428. /** ??id?$postId?post */
  1429. $select = $this->select()->where('table.contents.cid = ? AND table.contents.type = ?', $postId, 'post')->limit(1);
  1430. /** ???? */
  1431. $post = $this->$db->fetchRow($select, array($this, 'push'));
  1432. if ($this->authorId != $this->user->uid && !$this->checkAccess($userName, $password, 'administrator')) {
  1433. return new IXR_Error(403, '????.');
  1434. }
  1435. /** ???????*/
  1436. $content = array();
  1437. $this->update($content, $this->db->sql()->where('table.contents.cid = ?', $postId));
  1438. }
  1439. /**
  1440. * ?????????blog
  1441. *
  1442. * @param int $blogId
  1443. * @param string $userName
  1444. * @param string $password
  1445. * @access public
  1446. * @return void
  1447. */
  1448. public function bloggerGetUsersBlogs($blogId, $userName, $password)
  1449. {
  1450. if (!$this->checkAccess($userName, $password)) {
  1451. return $this->error;
  1452. }
  1453. $struct = array();
  1454. $struct[] = array(
  1455. 'isAdmin' => $this->user->pass('administrator', true),
  1456. 'url' => $this->options->siteUrl,
  1457. 'blogid' => '1',
  1458. 'blogName' => $this->options->title,
  1459. 'xmlrpc' => $this->options->xmlRpcUrl
  1460. );
  1461. return $struct;
  1462. }
  1463. /**
  1464. * ?????????
  1465. *
  1466. * @param int $blogId
  1467. * @param string $userName
  1468. * @param string $password
  1469. * @access public
  1470. * @return void
  1471. */
  1472. public function bloggerGetUserInfo($blogId, $userName, $password)
  1473. {
  1474. if (!$this->checkAccess($userName, $password)) {
  1475. return $this->error;
  1476. }
  1477. $struct = array(
  1478. 'nickname' => $this->user->screenName,
  1479. 'userid' => $this->user->uid,
  1480. 'url' => $this->user->url,
  1481. 'email' => $this->user->mail,
  1482. 'lastname' => '',
  1483. 'firstname' => ''
  1484. );
  1485. return $struct;
  1486. }
  1487. /**
  1488. * ???????????id?post?????
  1489. *
  1490. * @param int $blogId
  1491. * @param int $postId
  1492. * @param string $userName
  1493. * @param string $password
  1494. * @access public
  1495. * @return void
  1496. */
  1497. public function bloggerGetPost($blogId, $postId, $userName, $password)
  1498. {
  1499. if (!$this->checkAccess($userName, $password)) {
  1500. return $this->error;
  1501. }
  1502. try {
  1503. $post = $this->singletonWidget('Widget_Contents_Post_Edit', NULL, "cid={$postId}");
  1504. } catch (Typecho_Widget_Exception $e) {
  1505. return new IXR_Error($e->getCode(), $e->getMessage());
  1506. }
  1507. $categories = Typecho_Common::arrayFlatten($post->categories, 'name');
  1508. $content = '<title>' . $post->title . '</title>';
  1509. $content .= '<category>' . implode(',', $categories) . '</category>';
  1510. $content .= stripslashes($post->text);
  1511. $struct = array(
  1512. 'userid' => $post->authorId,
  1513. 'dateCreated' => new IXR_Date($this->options->timezone + $post->created),
  1514. 'content' => $content,
  1515. 'postid' => $post->cid
  1516. );
  1517. return $struct;
  1518. }
  1519. /**
  1520. * bloggerDeletePost
  1521. * ????
  1522. * @param mixed $blogId
  1523. * @param mixed $userName
  1524. * @param mixed $password
  1525. * @param mixed $publish
  1526. * @access public
  1527. * @return bool
  1528. */
  1529. public function bloggerDeletePost($blogId, $postId, $userName, $password, $publish)
  1530. {
  1531. if (!$this->checkAccess($userName, $password)) {
  1532. return $this->error;
  1533. }
  1534. try {
  1535. $this->singletonWidget('Widget_Contents_Post_Edit', NULL, "cid={$postId}", false)->deletePost();
  1536. } catch (Typecho_Widget_Exception $e) {
  1537. return new IXR_Error($e->getCode(), $e->getMessage());
  1538. }
  1539. }
  1540. /**
  1541. * ???????postsNum?post
  1542. *
  1543. * @param int $blogId
  1544. * @param string $userName
  1545. * @param string $password
  1546. * @param int $postsNum
  1547. * @access public
  1548. * @return void
  1549. */
  1550. public function bloggerGetRecentPosts($blogId, $userName, $password, $postsNum)
  1551. {
  1552. if (!$this->checkAccess($userName, $password)) {
  1553. return $this->error;
  1554. }
  1555. //todo:????
  1556. $posts = $this->singletonWidget('Widget_Contents_Post_Admin', "pageSize=$postsNum", 'status=all');
  1557. $postStructs = array();
  1558. while ($posts->next()) {
  1559. $categories = Typecho_Common::arrayFlatten($posts->categories, 'name');
  1560. $content = '<title>' . $posts->title . '</title>';
  1561. $content .= '<category>' . implode(',', $categories) . '</category>';
  1562. $content .= stripslashes($posts->text);
  1563. $struct = array(
  1564. 'userid' => $posts->authorId,
  1565. 'dateCreated' => new IXR_Date($this->options->timezone + $posts->created),
  1566. 'content' => $content,
  1567. 'postid' => $posts->cid,
  1568. );
  1569. $postStructs[] = $struct;
  1570. }
  1571. if (NULL == $postStructs) {
  1572. return new IXR_Error('404', '??????');
  1573. }
  1574. return $postStructs;
  1575. }
  1576. /**
  1577. * bloggerGetTemplate
  1578. *
  1579. * @param int $blogId
  1580. * @param string $userName
  1581. * @param string $password
  1582. * @param mixed $template
  1583. * @access public
  1584. * @return void
  1585. */
  1586. public function bloggerGetTemplate($blogId, $userName, $password, $template)
  1587. {
  1588. if (!$this->checkAccess($userName, $password)) {
  1589. return $this->error;
  1590. }
  1591. /** todo:?????true*/
  1592. return true;
  1593. }
  1594. /**
  1595. * bloggerSetTemplate
  1596. *
  1597. * @param int $blogId
  1598. * @param string $userName
  1599. * @param string $password
  1600. * @param mixed $content
  1601. * @param mixed $template
  1602. * @access public
  1603. * @return void
  1604. */
  1605. public function bloggerSetTemplate($blogId, $userName, $password, $content, $template)
  1606. {
  1607. if (!$this->checkAccess($userName, $password)) {
  1608. return $this->error;
  1609. }
  1610. /** todo:?????true*/
  1611. return true;
  1612. }
  1613. /**
  1614. * pingbackPing
  1615. *
  1616. * @param string $source
  1617. * @param string $target
  1618. * @access public
  1619. * @return void
  1620. */
  1621. public function pingbackPing($source, $target)
  1622. {
  1623. /** ?????????*/
  1624. if (!($http = Typecho_Http_Client::get())) {
  1625. return new IXR_Error(16, _t('????????'));
  1626. }
  1627. try {
  1628. $http->setTimeout(5)->send($source);
  1629. $response = $http->getResponseBody();
  1630. if (200 == $http->getResponseStatus()) {
  1631. if (!$http->getResponseHeader('x-pingback')) {
  1632. preg_match_all("/<link[^>]*rel=[\"']([^\"']*)[\"'][^>]*href=[\"']([^\"']*)[\"'][^>]*>/i", $response, $out);
  1633. if (!isset($out[1]['pingback'])) {
  1634. return new IXR_Error(50, _t('??????PingBack'));
  1635. }
  1636. }
  1637. } else {
  1638. return new IXR_Error(16, _t('????????'));
  1639. }
  1640. } catch (Exception $e) {
  1641. return new IXR_Error(16, _t('????????'));
  1642. }
  1643. /** ??????????*/
  1644. $pathInfo = Typecho_Common::url(substr($target, strlen($this->options->index)), '/');
  1645. $post = Typecho_Router::match($pathInfo);
  1646. /** ??????cid??slug*/
  1647. if (!($post instanceof Widget_Archive) || !$post->have() || !$post->is('single')) {
  1648. return new IXR_Error(33, _t('?????????'));
  1649. }
  1650. if ($post) {
  1651. /** ??????ping*/
  1652. if ($post->allowPing) {
  1653. /** ????ping???????????pingback???????*/
  1654. $pingNum = $this->db->fetchObject($this->db->select(array('COUNT(coid)' => 'num'))
  1655. ->from('table.comments')->where('table.comments.cid = ? AND table.comments.url = ? AND table.comments.type <> ?',
  1656. $post->cid, $source, 'comment'))->num;
  1657. if ($pingNum <= 0) {
  1658. /** ????????????? $response?????????????*/
  1659. preg_match("/\<title\>([^<]*?)\<\/title\\>/is", $response, $matchTitle);
  1660. $finalTitle = Typecho_Common::removeXSS(trim(strip_tags($matchTitle[1])));
  1661. /** ??html tag????<a>*/
  1662. $text = Typecho_Common::stripTags($response, '<a href="">');
  1663. /** ???$target quote,?????*/
  1664. $pregLink = preg_quote($target);
  1665. /** ????target??????????$finalText*/
  1666. $finalText = '';
  1667. $lines = explode("\n", $text);
  1668. foreach ($lines as $line) {
  1669. $line = trim($line);
  1670. if (NULL != $line) {
  1671. if (preg_match("|<a[^>]*href=[\"']{$pregLink}[\"'][^>]*>(.*?)</a>|",$line)) {
  1672. if (strlen($line) > strlen($finalText)) {
  1673. /** <a>?????*/
  1674. $finalText = Typecho_Common::stripTags($line);
  1675. }
  1676. }
  1677. }
  1678. }
  1679. /** ?????*/
  1680. if (NULL == trim($finalText)) {
  1681. return new IXR_Error('17', _t('???????????'));
  1682. }
  1683. $finalText = '[...]' . Typecho_Common::subStr($finalText, 0, 200, '') . '[...]';
  1684. $pingback = array(
  1685. 'cid' => $post->cid,
  1686. 'created' => $this->options->gmtTime,
  1687. 'agent' => $this->request->getAgent(),
  1688. 'ip' => $this->request->getIp(),
  1689. 'author' => $finalTitle,
  1690. 'url' => Typecho_Common::safeUrl($source),
  1691. 'text' => $finalText,
  1692. 'ownerId' => $post->author->uid,
  1693. 'type' => 'pingback',
  1694. 'status' => $this->options->commentsRequireModeration ? 'waiting' : 'approved'
  1695. );
  1696. /** ??plugin */
  1697. $pingback = $this->pluginHandle()->pingback($pingback, $post);
  1698. /** ????*/
  1699. $insertId = $this->singletonWidget('Widget_Abstract_Comments')->insert($pingback);
  1700. /** ?????? */
  1701. $this->pluginHandle()->finishPingback($this);
  1702. return $insertId;
  1703. /** todo:??????*/
  1704. } else {
  1705. return new IXR_Error(48, _t('PingBack????'));
  1706. }
  1707. } else {
  1708. return IXR_Error(49, _t('??????Ping'));
  1709. }
  1710. } else {
  1711. return new IXR_Error(33, _t('?????????'));
  1712. }
  1713. }
  1714. /**
  1715. * ????
  1716. *
  1717. * @access public
  1718. * @param string $methodName ??
  1719. * @return void
  1720. */
  1721. public function hookAfterCall($methodName)
  1722. {
  1723. if (!empty($this->_usedWidgetNameList)) {
  1724. foreach ($this->_usedWidgetNameList as $key => $widgetName) {
  1725. $this->destory($widgetName);
  1726. unset($this->_usedWidgetNameList[$key]);
  1727. }
  1728. }
  1729. }
  1730. /**
  1731. * ??????
  1732. *
  1733. * @access public
  1734. * @return void
  1735. */
  1736. public function action()
  1737. {
  1738. if (isset($this->request->rsd)) {
  1739. echo
  1740. <<<EOF
  1741. <?xml version="1.0" encoding="{$this->options->charset}"?>
  1742. <rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd">
  1743. <service>
  1744. <engineName>Typecho</engineName>
  1745. <engineLink>http://www.typecho.org/</engineLink>
  1746. <homePageLink>{$this->options->siteUrl}</homePageLink>
  1747. <apis>
  1748. <api name="WordPress" blogID="1" preferred="true" apiLink="{$this->options->xmlRpcUrl}" />
  1749. <api name="Movable Type" blogID="1" preferred="false" apiLink="{$this->options->xmlRpcUrl}" />
  1750. <api name="MetaWeblog" blogID="1" preferred="false" apiLink="{$this->options->xmlRpcUrl}" />
  1751. <api name="Blogger" blogID="1" preferred="false" apiLink="{$this->options->xmlRpcUrl}" />
  1752. </apis>
  1753. </service>
  1754. </rsd>
  1755. EOF;
  1756. } else if (isset($this->request->wlw)) {
  1757. echo
  1758. <<<EOF
  1759. <?xml version="1.0" encoding="{$this->options->charset}"?>
  1760. <manifest xmlns="http://schemas.microsoft.com/wlw/manifest/weblog">
  1761. <options>
  1762. <supportsKeywords>Yes</supportsKeywords>
  1763. <supportsFileUpload>Yes</supportsFileUpload>
  1764. <supportsExtendedEntries>Yes</supportsExtendedEntries>
  1765. <supportsCustomDate>Yes</supportsCustomDate>
  1766. <supportsCategories>Yes</supportsCategories>
  1767. <supportsCategoriesInline>Yes</supportsCategoriesInline>
  1768. <supportsMultipleCategories>Yes</supportsMultipleCategories>
  1769. <supportsHierarchicalCategories>No</supportsHierarchicalCategories>
  1770. <supportsNewCategories>Yes</supportsNewCategories>
  1771. <supportsNewCategoriesInline>Yes</supportsNewCategoriesInline>
  1772. <supportsCommentPolicy>Yes</supportsCommentPolicy>
  1773. <supportsPingPolicy>Yes</supportsPingPolicy>
  1774. <supportsAuthor>Yes</supportsAuthor>
  1775. <supportsSlug>Yes</supportsSlug>
  1776. <supportsPassword>Yes</supportsPassword>
  1777. <supportsExcerpt>Yes</supportsExcerpt>
  1778. <supportsTrackbacks>Yes</supportsTrackbacks>
  1779. <supportsPostAsDraft>Yes</supportsPostAsDraft>
  1780. <supportsPages>Yes</supportsPages>
  1781. <supportsPageParent>No</supportsPageParent>
  1782. <supportsPageOrder>Yes</supportsPageOrder>
  1783. <requiresXHTML>True</requiresXHTML>
  1784. <supportsAutoUpdate>No</supportsAutoUpdate>
  1785. </options>
  1786. </manifest>
  1787. EOF;
  1788. } else {
  1789. /** ?????????? */
  1790. new IXR_Server(array(
  1791. /** WordPress API */
  1792. 'wp.getPage' => array($this, 'wpGetPage'),
  1793. 'wp.getPages' => array($this, 'wpGetPages'),
  1794. 'wp.newPage' => array($this, 'wpNewPage'),
  1795. 'wp.deletePage' => array($this, 'wpDeletePage'),
  1796. 'wp.editPage' => array($this, 'wpEditPage'),
  1797. 'wp.getPageList' => array($this, 'wpGetPageList'),
  1798. 'wp.getAuthors' => array($this, 'wpGetAuthors'),
  1799. 'wp.getCategories' => array($this, 'mwGetCategories'),
  1800. 'wp.newCategory' => array($this, 'wpNewCategory'),
  1801. 'wp.suggestCategories' => array($this, 'wpSuggestCategories'),
  1802. 'wp.uploadFile' => array($this, 'mwNewMediaObject'),
  1803. /** New Wordpress API since 2.9.2 */
  1804. 'wp.getUsersBlogs' => array($this, 'wpGetUsersBlogs'),
  1805. 'wp.getTags' => array($this, 'wpGetTags'),
  1806. 'wp.deleteCategory' => array($this, 'wpDeleteCategory'),
  1807. 'wp.getCommentCount' => array($this, 'wpGetCommentCount'),
  1808. 'wp.getPostStatusList' => array($this, 'wpGetPostStatusList'),
  1809. 'wp.getPageStatusList' => array($this, 'wpGetPageStatusList'),
  1810. 'wp.getPageTemplates' => array($this, 'wpGetPageTemplates'),
  1811. 'wp.getOptions' => array($this, 'wpGetOptions'),
  1812. 'wp.setOptions' => array($this, 'wpSetOptions'),
  1813. 'wp.getComment' => array($this, 'wpGetComment'),
  1814. 'wp.getComments' => array($this, 'wpGetComments'),
  1815. 'wp.deleteComment' => array($this, 'wpDeleteComment'),
  1816. 'wp.editComment' => array($this, 'wpEditComment'),
  1817. 'wp.newComment' => array($this, 'wpNewComment'),
  1818. 'wp.getCommentStatusList' => array($this, 'wpGetCommentStatusList'),
  1819. /** Blogger API */
  1820. 'blogger.getUsersBlogs' => array($this, 'bloggerGetUsersBlogs'),
  1821. 'blogger.getUserInfo' => array($this, 'bloggerGetUserInfo'),
  1822. 'blogger.getPost' => array($this, 'bloggerGetPost'),
  1823. 'blogger.getRecentPosts' => array($this, 'bloggerGetRecentPosts'),
  1824. 'blogger.getTemplate' => array($this, 'bloggerGetTemplate'),
  1825. 'blogger.setTemplate' => array($this, 'bloggerSetTemplate'),
  1826. 'blogger.deletePost' => array($this, 'bloggerDeletePost'),
  1827. /** MetaWeblog API (with MT extensions to structs) */
  1828. 'metaWeblog.newPost' => array($this, 'mwNewPost'),
  1829. 'metaWeblog.editPost' => array($this, 'mwEditPost'),
  1830. 'metaWeblog.getPost' => array($this, 'mwGetPost'),
  1831. 'metaWeblog.getRecentPosts' => array($this, 'mwGetRecentPosts'),
  1832. 'metaWeblog.getCategories' => array($this, 'mwGetCategories'),
  1833. 'metaWeblog.newMediaObject' => array($this, 'mwNewMediaObject'),
  1834. /** MetaWeblog API aliases for Blogger API */
  1835. 'metaWeblog.deletePost' => array($this, 'bloggerDeletePost'),
  1836. 'metaWeblog.getTemplate' => array($this, 'bloggerGetTemplate'),
  1837. 'metaWeblog.setTemplate' => array($this, 'bloggerSetTemplate'),
  1838. 'metaWeblog.getUsersBlogs' => array($this, 'bloggerGetUsersBlogs'),
  1839. /** MovableType API */
  1840. 'mt.getCategoryList' => array($this, 'mtGetCategoryList'),
  1841. 'mt.getRecentPostTitles' => array($this, 'mtGetRecentPostTitles'),
  1842. 'mt.getPostCategories' => array($this, 'mtGetPostCategories'),
  1843. 'mt.setPostCategories' => array($this, 'mtSetPostCategories'),
  1844. 'mt.publishPost' => array($this, 'mtPublishPost'),
  1845. /** PingBack */
  1846. 'pingback.ping' => array($this,'pingbackPing'),
  1847. 'pingback.extensions.getPingbacks' => array($this,'pingbackExtensionsGetPingbacks'),
  1848. /** hook after */
  1849. 'hook.afterCall' => array($this, 'hookAfterCall'),
  1850. ));
  1851. }
  1852. }
  1853. }