root/tags/1.3/xmlrpc.php

Revision 1139, 56.8 kB (checked in by donncha, 1 year ago)

Merge with WordPress? 2.3.1

  • Property svn:eol-style set to native
Line 
1 <?php
2
3 define('XMLRPC_REQUEST', true);
4
5 // Some browser-embedded clients send cookies. We don't want them.
6 $_COOKIE = array();
7
8 // A bug in PHP < 5.2.2 makes $HTTP_RAW_POST_DATA not set by default,
9 // but we can do it ourself.
10 if ( !isset( $HTTP_RAW_POST_DATA ) ) {
11     $HTTP_RAW_POST_DATA = file_get_contents( 'php://input' );
12 }
13
14 # fix for mozBlog and other cases where '<?xml' isn't on the very first line
15 if ( isset($HTTP_RAW_POST_DATA) )
16     $HTTP_RAW_POST_DATA = trim($HTTP_RAW_POST_DATA);
17
18 include('./wp-config.php');
19
20 if ( isset( $_GET['rsd'] ) ) { // http://archipelago.phrasewise.com/rsd
21 header('Content-Type: text/xml; charset=' . get_option('blog_charset'), true);
22
23 ?>
24 <?php echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>'; ?>
25 <rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd">
26   <service>
27     <engineName>WordPress</engineName>
28     <engineLink>http://wordpress.org/</engineLink>
29     <homePageLink><?php bloginfo_rss('url') ?></homePageLink>
30     <apis>
31       <api name="WordPress" blogID="1" preferred="true" apiLink="<?php bloginfo_rss('wpurl') ?>/xmlrpc.php" />
32       <api name="Movable Type" blogID="1" preferred="false" apiLink="<?php bloginfo_rss('wpurl') ?>/xmlrpc.php" />
33       <api name="MetaWeblog" blogID="1" preferred="false" apiLink="<?php bloginfo_rss('wpurl') ?>/xmlrpc.php" />
34       <api name="Blogger" blogID="1" preferred="false" apiLink="<?php bloginfo_rss('wpurl') ?>/xmlrpc.php" />
35     </apis>
36   </service>
37 </rsd>
38 <?php
39 exit;
40 }
41
42 include_once(ABSPATH . 'wp-admin/includes/admin.php');
43 include_once(ABSPATH . WPINC . '/class-IXR.php');
44
45 // Turn off all warnings and errors.
46 // error_reporting(0);
47
48 $post_default_title = ""; // posts submitted via the xmlrpc interface get that title
49
50 $xmlrpc_logging = 0;
51
52 function logIO($io,$msg) {
53     global $xmlrpc_logging;
54     if ($xmlrpc_logging) {
55         $fp = fopen("../xmlrpc.log","a+");
56         $date = gmdate("Y-m-d H:i:s ");
57         $iot = ($io == "I") ? " Input: " : " Output: ";
58         fwrite($fp, "\n\n".$date.$iot.$msg);
59         fclose($fp);
60     }
61     return true;
62     }
63
64 function starify($string) {
65     $i = strlen($string);
66     return str_repeat('*', $i);
67 }
68
69 if ( isset($HTTP_RAW_POST_DATA) )
70   logIO("I", $HTTP_RAW_POST_DATA);
71
72
73 class wp_xmlrpc_server extends IXR_Server {
74
75     function wp_xmlrpc_server() {
76         $this->methods = array(
77             // WordPress API
78             'wp.getPage'            => 'this:wp_getPage',
79             'wp.getPages'            => 'this:wp_getPages',
80             'wp.newPage'            => 'this:wp_newPage',
81             'wp.deletePage'            => 'this:wp_deletePage',
82             'wp.editPage'            => 'this:wp_editPage',
83             'wp.getPageList'        => 'this:wp_getPageList',
84             'wp.getAuthors'            => 'this:wp_getAuthors',
85             'wp.getCategories'        => 'this:mw_getCategories',        // Alias
86             'wp.newCategory'        => 'this:wp_newCategory',
87             'wp.suggestCategories'    => 'this:wp_suggestCategories',
88             'wp.uploadFile'            => 'this:mw_newMediaObject',    // Alias
89
90             // Blogger API
91             'blogger.getUsersBlogs' => 'this:blogger_getUsersBlogs',
92             'blogger.getUserInfo' => 'this:blogger_getUserInfo',
93             'blogger.getPost' => 'this:blogger_getPost',
94             'blogger.getRecentPosts' => 'this:blogger_getRecentPosts',
95             'blogger.getTemplate' => 'this:blogger_getTemplate',
96             'blogger.setTemplate' => 'this:blogger_setTemplate',
97             'blogger.newPost' => 'this:blogger_newPost',
98             'blogger.editPost' => 'this:blogger_editPost',
99             'blogger.deletePost' => 'this:blogger_deletePost',
100
101             // MetaWeblog API (with MT extensions to structs)
102             'metaWeblog.newPost' => 'this:mw_newPost',
103             'metaWeblog.editPost' => 'this:mw_editPost',
104             'metaWeblog.getPost' => 'this:mw_getPost',
105             'metaWeblog.getRecentPosts' => 'this:mw_getRecentPosts',
106             'metaWeblog.getCategories' => 'this:mw_getCategories',
107             'metaWeblog.newMediaObject' => 'this:mw_newMediaObject',
108
109             // MetaWeblog API aliases for Blogger API
110             // see http://www.xmlrpc.com/stories/storyReader$2460
111             'metaWeblog.deletePost' => 'this:blogger_deletePost',
112             'metaWeblog.getTemplate' => 'this:blogger_getTemplate',
113             'metaWeblog.setTemplate' => 'this:blogger_setTemplate',
114             'metaWeblog.getUsersBlogs' => 'this:blogger_getUsersBlogs',
115
116             // MovableType API
117             'mt.getCategoryList' => 'this:mt_getCategoryList',
118             'mt.getRecentPostTitles' => 'this:mt_getRecentPostTitles',
119             'mt.getPostCategories' => 'this:mt_getPostCategories',
120             'mt.setPostCategories' => 'this:mt_setPostCategories',
121             'mt.supportedMethods' => 'this:mt_supportedMethods',
122             'mt.supportedTextFilters' => 'this:mt_supportedTextFilters',
123             'mt.getTrackbackPings' => 'this:mt_getTrackbackPings',
124             'mt.publishPost' => 'this:mt_publishPost',
125
126             // PingBack
127             'pingback.ping' => 'this:pingback_ping',
128             'pingback.extensions.getPingbacks' => 'this:pingback_extensions_getPingbacks',
129
130             'demo.sayHello' => 'this:sayHello',
131             'demo.addTwoNumbers' => 'this:addTwoNumbers'
132         );
133         $this->methods = apply_filters('xmlrpc_methods', $this->methods);
134         $this->IXR_Server($this->methods);
135     }
136
137     function sayHello($args) {
138         return 'Hello!';
139     }
140
141     function addTwoNumbers($args) {
142         $number1 = $args[0];
143         $number2 = $args[1];
144         return $number1 + $number2;
145     }
146
147     function login_pass_ok($user_login, $user_pass) {
148         if (!user_pass_ok($user_login, $user_pass)) {
149             $this->error = new IXR_Error(403, __('Bad login/pass combination.'));
150             return false;
151         }
152         return true;
153     }
154
155     function escape(&$array) {
156         global $wpdb;
157
158         if(!is_array($array)) {
159             return($wpdb->escape($array));
160         }
161         else {
162             foreach ( (array) $array as $k => $v ) {
163                 if (is_array($v)) {
164                     $this->escape($array[$k]);
165                 } else if (is_object($v)) {
166                     //skip
167                 } else {
168                     $array[$k] = $wpdb->escape($v);
169                 }
170             }
171         }
172     }
173
174     /**
175      * WordPress XML-RPC API
176      * wp_getPage
177      */
178     function wp_getPage($args) {
179         $this->escape($args);
180
181         $blog_id    = (int) $args[0];
182         $page_id    = (int) $args[1];
183         $username    = $args[2];
184         $password    = $args[3];
185
186         if(!$this->login_pass_ok($username, $password)) {
187             return($this->error);
188         }
189
190         // Lookup page info.
191         $page = get_page($page_id);
192
193         // If we found the page then format the data.
194         if($page->ID && ($page->post_type == "page")) {
195             // Get all of the page content and link.
196             $full_page = get_extended($page->post_content);
197             $link = post_permalink($page->ID);
198
199             // Get info the page parent if there is one.
200             $parent_title = "";
201             if(!empty($page->post_parent)) {
202                 $parent = get_page($page->post_parent);
203                 $parent_title = $parent->post_title;
204             }
205
206             // Determine comment and ping settings.
207             $allow_comments = ("open" == $page->comment_status) ? 1 : 0;
208             $allow_pings = ("open" == $page->ping_status) ? 1 : 0;
209
210             // Format page date.
211             $page_date = mysql2date("Ymd\TH:i:s", $page->post_date);
212             $page_date_gmt = mysql2date("Ymd\TH:i:s", $page->post_date_gmt);
213
214             // Pull the categories info together.
215             $categories = array();
216             foreach(wp_get_post_categories($page->ID) as $cat_id) {
217                 $categories[] = get_cat_name($cat_id);
218             }
219
220             // Get the author info.
221             $author = get_userdata($page->post_author);
222
223             $page_struct = array(
224                 "dateCreated"            => new IXR_Date($page_date),
225                 "userid"                => $page->post_author,
226                 "page_id"                => $page->ID,
227                 "page_status"            => $page->post_status,
228                 "description"            => $full_page["main"],
229                 "title"                    => $page->post_title,
230                 "link"                    => $link,
231                 "permaLink"                => $link,
232                 "categories"            => $categories,
233                 "excerpt"                => $page->post_excerpt,
234                 "text_more"                => $full_page["extended"],
235                 "mt_allow_comments"        => $allow_comments,
236                 "mt_allow_pings"        => $allow_pings,
237                 "wp_slug"                => $page->post_name,
238                 "wp_password"            => $page->post_password,
239                 "wp_author"                => $author->display_name,
240                 "wp_page_parent_id"        => $page->post_parent,
241                 "wp_page_parent_title"    => $parent_title,
242                 "wp_page_order"            => $page->menu_order,
243                 "wp_author_id"            => $author->ID,
244                 "wp_author_display_name"    => $author->display_name,
245                 "date_created_gmt"        => new IXR_Date($page_date_gmt)
246             );
247
248             return($page_struct);
249         }
250         // If the page doesn't exist indicate that.
251         else {
252             return(new IXR_Error(404, __("Sorry, no such page.")));
253         }
254     }
255
256     /**
257      * WordPress XML-RPC API
258       * wp_getPages
259      */
260     function wp_getPages($args) {
261         $this->escape($args);
262
263         $blog_id    = (int) $args[0];
264         $username    = $args[1];
265         $password    = $args[2];
266
267         if(!$this->login_pass_ok($username, $password)) {
268             return($this->error);
269         }
270
271         // Lookup info on pages.
272         $pages = get_pages();
273         $num_pages = count($pages);
274
275         // If we have pages, put together their info.
276         if($num_pages >= 1) {
277             $pages_struct = array();
278
279             for($i = 0; $i < $num_pages; $i++) {
280                 $page = wp_xmlrpc_server::wp_getPage(array(
281                     $blog_id, $pages[$i]->ID, $username, $password
282                 ));
283                 $pages_struct[] = $page;
284             }
285
286             return($pages_struct);
287         }
288         // If no pages were found return an error.
289         else {
290             return(array());
291         }
292     }
293
294     /**
295      * WordPress XML-RPC API
296       * wp_newPage
297      */
298     function wp_newPage($args) {
299         // Items not escaped here will be escaped in newPost.
300         $username    = $this->escape($args[1]);
301         $password    = $this->escape($args[2]);
302         $page        = $args[3];
303         $publish    = $args[4];
304
305         if(!$this->login_pass_ok($username, $password)) {
306             return($this->error);
307         }
308
309         // Set the user context and check if they are allowed
310         // to add new pages.
311         $user = set_current_user(0, $username);
312         if(!current_user_can("publish_pages")) {
313             return(new IXR_Error(401, __("Sorry, you can not add new pages.")));
314         }
315
316         // Mark this as content for a page.
317         $args[3]["post_type"] = "page";
318
319         // Let mw_newPost do all of the heavy lifting.
320         return($this->mw_newPost($args));
321     }
322
323     /**
324      * WordPress XML-RPC API
325      * wp_deletePage
326      */
327     function wp_deletePage($args) {
328         $this->escape($args);
329
330         $blog_id    = (int) $args[0];
331         $username    = $args[1];
332         $password    = $args[2];
333         $page_id    = (int) $args[3];
334
335         if(!$this->login_pass_ok($username, $password)) {
336             return($this->error);
337         }
338
339         // Get the current page based on the page_id and
340         // make sure it is a page and not a post.
341         $actual_page = wp_get_single_post($page_id, ARRAY_A);
342         if(
343             !$actual_page
344             || ($actual_page["post_type"] != "page")
345         ) {
346             return(new IXR_Error(404, __("Sorry, no such page.")));
347         }
348
349         // Set the user context and make sure they can delete pages.
350         set_current_user(0, $username);
351         if(!current_user_can("delete_page", $page_id)) {
352             return(new IXR_Error(401, __("Sorry, you do not have the right to delete this page.")));
353         }
354
355         // Attempt to delete the page.
356         $result = wp_delete_post($page_id);
357         if(!$result) {
358             return(new IXR_Error(500, __("Failed to delete the page.")));
359         }
360
361         return(true);
362     }
363
364     /**
365      * WordPress XML-RPC API
366      * wp_editPage
367      */
368     function wp_editPage($args) {
369         // Items not escaped here will be escaped in editPost.
370         $blog_id    = (int) $args[0];
371         $page_id    = (int) $this->escape($args[1]);
372         $username    = $this->escape($args[2]);
373         $password    = $this->escape($args[3]);
374         $content    = $args[4];
375         $publish    = $args[5];
376
377         if(!$this->login_pass_ok($username, $password)) {
378             return($this->error);
379         }
380
381         // Get the page data and make sure it is a page.
382         $actual_page = wp_get_single_post($page_id, ARRAY_A);
383         if(
384             !$actual_page
385             || ($actual_page["post_type"] != "page")
386         ) {
387             return(new IXR_Error(404, __("Sorry, no such page.")));
388         }
389
390         // Set the user context and make sure they are allowed to edit pages.
391         set_current_user(0, $username);
392         if(!current_user_can("edit_page", $page_id)) {
393             return(new IXR_Error(401, __("Sorry, you do not have the right to edit this page.")));
394         }
395
396         // Mark this as content for a page.
397         $content["post_type"] = "page";
398
399         // Arrange args in the way mw_editPost understands.
400         $args = array(
401             $page_id,
402             $username,
403             $password,
404             $content,
405             $publish
406         );
407
408         // Let mw_editPost do all of the heavy lifting.
409         return($this->mw_editPost($args));
410     }
411
412     /**
413      * WordPress XML-RPC API
414      * wp_getPageList
415      */
416     function wp_getPageList($args) {
417         global $wpdb;
418
419         $this->escape($args);
420
421         $blog_id                = (int) $args[0];
422         $username                = $args[1];
423         $password                = $args[2];
424
425         if(!$this->login_pass_ok($username, $password)) {
426             return($this->error);
427         }
428
429         // Get list of pages ids and titles
430         $page_list = $wpdb->get_results("
431             SELECT ID page_id,
432                 post_title page_title,
433                 post_parent page_parent_id,
434                 post_date_gmt,
435                 post_date
436             FROM {$wpdb->posts}
437             WHERE post_type = 'page'
438             ORDER BY ID
439         ");
440
441         // The date needs to be formated properly.
442         $num_pages = count($page_list);
443         for($i = 0; $i < $num_pages; $i++) {
444             $post_date = mysql2date("Ymd\TH:i:s", $page_list[$i]->post_date);
445             $post_date_gmt = mysql2date("Ymd\TH:i:s", $page_list[$i]->post_date_gmt);
446
447             $page_list[$i]->dateCreated = new IXR_Date($post_date);
448             $page_list[$i]->date_created_gmt = new IXR_Date($post_date_gmt);
449
450             unset($page_list[$i]->post_date_gmt);
451             unset($page_list[$i]->post_date);
452         }
453
454         return($page_list);
455     }
456
457     /**
458      * WordPress XML-RPC API
459      * wp_getAuthors
460      */
461     function wp_getAuthors($args) {
462         global $wpdb;
463
464         $this->escape($args);
465
466         $blog_id    = (int) $args[0];
467         $username    = $args[1];
468         $password    = $args[2];
469
470         if(!$this->login_pass_ok($username, $password)) {
471             return($this->error);
472         }
473
474         return(get_users_of_blog());
475     }
476
477     /**
478      * WordPress XML-RPC API
479      * wp_newCategory
480      */
481     function wp_newCategory($args) {
482         $this->escape($args);
483
484         $blog_id                = (int) $args[0];
485         $username                = $args[1];
486         $password                = $args[2];
487         $category                = $args[3];
488
489         if(!$this->login_pass_ok($username, $password)) {
490             return($this->error);
491         }
492
493         // Set the user context and make sure they are
494         // allowed to add a category.
495         set_current_user(0, $username);
496         if(!current_user_can("manage_categories", $page_id)) {
497             return(new IXR_Error(401, __("Sorry, you do not have the right to add a category.")));
498         }
499
500         // If no slug was provided make it empty so that
501         // WordPress will generate one.
502         if(empty($category["slug"])) {
503             $category["slug"] = "";
504         }
505
506         // If no parent_id was provided make it empty
507         // so that it will be a top level page (no parent).
508         if ( !isset($category["parent_id"]) )
509             $category["parent_id"] = "";
510
511         // If no description was provided make it empty.
512         if(empty($category["description"])) {
513             $category["description"] = "";
514         }
515
516         $new_category = array(
517