root/tags/1.5.1/xmlrpc.php

Revision 2581, 36.3 kB (checked in by matt, 3 years ago)

Use CURL if available, possible fix for http://mosquito.wordpress.org/view.php?id=1166

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 <?php
2
3 # fix for mozBlog and other cases where '<?xml' isn't on the very first line
4 $HTTP_RAW_POST_DATA = trim($HTTP_RAW_POST_DATA);
5
6 include('./wp-config.php');
7 include_once(ABSPATH . WPINC . '/class-IXR.php');
8
9 // Turn off all warnings and errors.
10 // error_reporting(0);
11
12 $post_default_title = ""; // posts submitted via the xmlrpc interface get that title
13 $post_default_category = 1; // posts submitted via the xmlrpc interface go into that category
14
15 $xmlrpc_logging = 0;
16
17 function logIO($io,$msg) {
18     global $xmlrpc_logging;
19     if ($xmlrpc_logging) {
20         $fp = fopen("../xmlrpc.log","a+");
21         $date = gmdate("Y-m-d H:i:s ");
22         $iot = ($io == "I") ? " Input: " : " Output: ";
23         fwrite($fp, "\n\n".$date.$iot.$msg);
24         fclose($fp);
25     }
26     return true;
27     }
28
29 function starify($string) {
30     $i = strlen($string);
31     return str_repeat('*', $i);
32 }
33
34 logIO("I", $HTTP_RAW_POST_DATA);
35
36
37 function mkdir_p($target) {
38     // from php.net/mkdir user contributed notes
39     if (file_exists($target)) {
40       if (!is_dir($target)) {
41         return false;
42       } else {
43         return true;
44       }
45     }
46
47     // Attempting to create the directory may clutter up our display.
48     if (@mkdir($target)) {
49       return true;
50     }
51
52     // If the above failed, attempt to create the parent node, then try again.
53     if (mkdir_p(dirname($target))) {
54       return mkdir_p($target);
55     }
56
57     return false;
58 }
59
60
61 class wp_xmlrpc_server extends IXR_Server {
62
63     function wp_xmlrpc_server() {
64         $this->methods = array(
65           // Blogger API
66           'blogger.getUsersBlogs' => 'this:blogger_getUsersBlogs',
67           'blogger.getUserInfo' => 'this:blogger_getUserInfo',
68           'blogger.getPost' => 'this:blogger_getPost',
69           'blogger.getRecentPosts' => 'this:blogger_getRecentPosts',
70           'blogger.getTemplate' => 'this:blogger_getTemplate',
71           'blogger.setTemplate' => 'this:blogger_setTemplate',
72           'blogger.newPost' => 'this:blogger_newPost',
73           'blogger.editPost' => 'this:blogger_editPost',
74           'blogger.deletePost' => 'this:blogger_deletePost',
75
76           // MetaWeblog API (with MT extensions to structs)
77           'metaWeblog.newPost' => 'this:mw_newPost',
78           'metaWeblog.editPost' => 'this:mw_editPost',
79           'metaWeblog.getPost' => 'this:mw_getPost',
80           'metaWeblog.getRecentPosts' => 'this:mw_getRecentPosts',
81           'metaWeblog.getCategories' => 'this:mw_getCategories',
82           'metaWeblog.newMediaObject' => 'this:mw_newMediaObject',
83
84           // MetaWeblog API aliases for Blogger API
85           // see http://www.xmlrpc.com/stories/storyReader$2460
86           'metaWeblog.deletePost' => 'this:blogger_deletePost',
87           'metaWeblog.getTemplate' => 'this:blogger_getTemplate',
88           'metaWeblog.setTemplate' => 'this:blogger_setTemplate',
89           'metaWeblog.getUsersBlogs' => 'this:blogger_getUsersBlogs',
90
91           // MovableType API
92           'mt.getCategoryList' => 'this:mt_getCategoryList',
93           'mt.getRecentPostTitles' => 'this:mt_getRecentPostTitles',
94           'mt.getPostCategories' => 'this:mt_getPostCategories',
95           'mt.setPostCategories' => 'this:mt_setPostCategories',
96           'mt.supportedMethods' => 'this:mt_supportedMethods',
97           'mt.supportedTextFilters' => 'this:mt_supportedTextFilters',
98           'mt.getTrackbackPings' => 'this:mt_getTrackbackPings',
99           'mt.publishPost' => 'this:mt_publishPost',
100
101           // PingBack
102           'pingback.ping' => 'this:pingback_ping',
103           'pingback.extensions.getPingbacks' => 'this:pingback_extensions_getPingbacks',
104
105           'demo.sayHello' => 'this:sayHello',
106           'demo.addTwoNumbers' => 'this:addTwoNumbers'
107         );
108         $this->methods = apply_filters('xmlrpc_methods', $this->methods);
109         $this->IXR_Server($this->methods);
110     }
111
112     function sayHello($args) {
113         return 'Hello!';
114     }
115
116     function addTwoNumbers($args) {
117         $number1 = $args[0];
118         $number2 = $args[1];
119         return $number1 + $number2;
120     }
121
122     function login_pass_ok($user_login, $user_pass) {
123       if (!user_pass_ok($user_login, $user_pass)) {
124         $this->error = new IXR_Error(403, 'Bad login/pass combination.');
125         return false;
126       }
127       return true;
128     }
129
130
131
132
133     /* Blogger API functions
134      * specs on http://plant.blogger.com/api and http://groups.yahoo.com/group/bloggerDev/
135      */
136
137
138     /* blogger.getUsersBlogs will make more sense once we support multiple blogs */
139     function blogger_getUsersBlogs($args) {
140
141       $user_login = $args[1];
142       $user_pass  = $args[2];
143
144       if (!$this->login_pass_ok($user_login, $user_pass)) {
145         return $this->error;
146       }
147
148       $user_data = get_userdatabylogin($user_login);
149       $is_admin = $user_data->user_level > 3;
150
151       $struct = array(
152         'isAdmin'  => $is_admin,
153         'url'      => get_settings('home') . '/',
154         'blogid'   => '1',
155         'blogName' => get_settings('blogname')
156       );
157
158       return array($struct);
159     }
160
161
162     /* blogger.getUsersInfo gives your client some info about you, so you don't have to */
163     function blogger_getUserInfo($args) {
164
165       $user_login = $args[1];
166       $user_pass  = $args[2];
167
168       if (!$this->login_pass_ok($user_login, $user_pass)) {
169         return $this->error;
170       }
171
172       $user_data = get_userdatabylogin($user_login);
173
174       $struct = array(
175         'nickname'  => $user_data->user_nickname,
176         'userid'    => $user_data->ID,
177         'url'       => $user_data->user_url,
178         'email'     => $user_data->user_email,
179         'lastname'  => $user_data->user_lastname,
180         'firstname' => $user_data->user_firstname
181       );
182
183       return $struct;
184     }
185
186
187     /* blogger.getPost ...gets a post */
188     function blogger_getPost($args) {
189
190       $post_ID    = $args[1];
191       $user_login = $args[2];
192       $user_pass  = $args[3];
193
194       if (!$this->login_pass_ok($user_login, $user_pass)) {
195         return $this->error;
196       }
197
198       $user_data = get_userdatabylogin($user_login);
199       $post_data = wp_get_single_post($post_ID, ARRAY_A);
200
201       $categories = implode(',', wp_get_post_cats(1, $post_ID));
202
203       $content  = '<title>'.stripslashes($post_data['post_title']).'</title>';
204       $content .= '<category>'.$categories.'</category>';
205       $content .= stripslashes($post_data['post_content']);
206
207       $struct = array(
208         'userid'    => $post_data['post_author'],
209         'dateCreated' => new IXR_Date(mysql2date('Ymd\TH:i:s', $post_data['post_date'])),
210         'content'     => $content,
211         'postid'  => $post_data['ID']
212       );
213
214       return $struct;
215     }
216
217
218     /* blogger.getRecentPosts ...gets recent posts */
219     function blogger_getRecentPosts($args) {
220
221       global $wpdb;
222
223       $blog_ID    = $args[1]; /* though we don't use it yet */
224       $user_login = $args[2];
225       $user_pass  = $args[3];
226       $num_posts  = $args[4];
227
228       if (!$this->login_pass_ok($user_login, $user_pass)) {
229         return $this->error;
230       }
231
232       $posts_list = wp_get_recent_posts($num_posts);
233
234       if (!$posts_list) {
235         $this->error = new IXR_Error(500, 'Either there are no posts, or something went wrong.');
236         return $this->error;
237       }
238
239       foreach ($posts_list as $entry) {
240       
241         $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date']);
242         $categories = implode(',', wp_get_post_cats(1, $entry['ID']));
243
244         $content  = '<title>'.stripslashes($entry['post_title']).'</title>';
245         $content .= '<category>'.$categories.'</category>';
246         $content .= stripslashes($entry['post_content']);
247
248         $struct[] = array(
249           'userid' => $entry['post_author'],
250           'dateCreated' => new IXR_Date($post_date),
251           'content' => $content,
252           'postid' => $entry['ID'],
253         );
254
255       }
256
257       $recent_posts = array();
258       for ($j=0; $j<count($struct); $j++) {
259         array_push($recent_posts, $struct[$j]);
260       }
261
262       return $recent_posts;
263     }
264
265
266     /* blogger.getTemplate returns your blog_filename */
267     function blogger_getTemplate($args) {
268
269       $blog_ID    = $args[1];
270       $user_login = $args[2];
271       $user_pass  = $args[3];
272       $template   = $args[4]; /* could be 'main' or 'archiveIndex', but we don't use it */
273
274       if (!$this->login_pass_ok($user_login, $user_pass)) {
275         return $this->error;
276       }
277
278       $user_data = get_userdatabylogin($user_login);
279
280       if ($user_data->user_level < 3) {
281         return new IXR_Error(401, 'Sorry, users whose level is less than 3, can not edit the template.');
282       }
283
284       /* warning: here we make the assumption that the weblog's URI is on the same server */
285       $filename = get_settings('home') . '/';
286       $filename = preg_replace('#http://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename);
287
288       $f = fopen($filename, 'r');
289       $content = fread($f, filesize($filename));
290       fclose($f);
291
292       /* so it is actually editable with a windows/mac client */
293       // FIXME: (or delete me) do we really want to cater to bad clients at the expense of good ones by BEEPing up their line breaks? commented.     $content = str_replace("\n", "\r\n", $content);
294
295       return $content;
296     }
297
298
299     /* blogger.setTemplate updates the content of blog_filename */
300     function blogger_setTemplate($args) {
301
302       $blog_ID    = $args[1];
303       $user_login = $args[2];
304       $user_pass  = $args[3];
305       $content    = $args[4];
306       $template   = $args[5]; /* could be 'main' or 'archiveIndex', but we don't use it */
307
308       if (!$this->login_pass_ok($user_login, $user_pass)) {
309         return $this->error;
310       }
311
312       $user_data = get_userdatabylogin($user_login);
313
314       if ($user_data->user_level < 3) {
315         return new IXR_Error(401, 'Sorry, users whose level is less than 3, can not edit the template.');
316       }
317
318       /* warning: here we make the assumption that the weblog's URI is on the same server */
319       $filename = get_settings('home') . '/';
320       $filename = preg_replace('#http://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename);
321
322       if ($f = fopen($filename, 'w+')) {
323         fwrite($f, $content);
324         fclose($f);
325       } else {
326         return new IXR_Error(500, 'Either the file is not writable, or something wrong happened. The file has not been updated.');
327       }
328
329       return true;
330     }
331
332
333     /* blogger.newPost ...creates a new post */
334     function blogger_newPost($args) {
335
336       global $wpdb;
337
338       $blog_ID    = $args[1]; /* though we don't use it yet */
339       $user_login = $args[2];
340       $user_pass  = $args[3];
341       $content    = $args[4];
342       $publish    = $args[5];
343
344       if (!$this->login_pass_ok($user_login, $user_pass)) {
345         return $this->error;
346       }
347
348       $user_data = get_userdatabylogin($user_login);
349       if (!user_can_create_post($user_data->ID, $blog_ID)) {
350         return new IXR_Error(401, 'Sorry, you can not post on this weblog or category.');
351       }
352
353       $post_status = ($publish) ? 'publish' : 'draft';
354
355       $post_author = $user_data->ID;
356
357       $post_title = xmlrpc_getposttitle($content);
358       $post_category = xmlrpc_getpostcategory($content);
359
360       $content = xmlrpc_removepostdata($content);
361       $post_content = apply_filters( 'content_save_pre', $content );
362
363       $post_date = current_time('mysql');
364       $post_date_gmt = current_time('mysql', 1);
365
366       $post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status');
367
368       $post_ID = wp_insert_post($post_data);
369
370       if (!$post_ID) {
371         return new IXR_Error(500, 'Sorry, your entry could not be posted. Something wrong happened.');
372       }
373
374       logIO('O', "Posted ! ID: $post_ID");
375
376       return $post_ID;
377     }
378
379
380     /* blogger.editPost ...edits a post */
381     function blogger_editPost($args) {
382
383       global $wpdb;
384
385       $post_ID     = $args[1];
386       $user_login  = $args[2];
387       $user_pass   = $args[3];
388       $new_content = $args[4];
389       $publish     = $args[5];
390
391       if (!$this->login_pass_ok($user_login, $user_pass)) {
392         return $this->error;
393       }
394
395       $actual_post = wp_get_single_post($post_ID,ARRAY_A);
396
397       if (!$actual_post) {
398           return new IXR_Error(404, 'Sorry, no such post.');
399       }
400
401       $post_author_data = get_userdata($actual_post['post_author']);
402       $user_data = get_userdatabylogin($user_login);
403
404       if (!user_can_edit_post($user_data->ID, $post_ID)) {
405         return new IXR_Error(401, 'Sorry, you do not have the right to edit this post.');
406       }
407
408       extract($actual_post);
409       $content = $newcontent;
410
411       $post_title = xmlrpc_getposttitle($content);
412       $post_category = xmlrpc_getpostcategory($content);
413
414       $content = xmlrpc_removepostdata($content);
415       $post_content = apply_filters( 'content_save_pre', $content );
416
417       $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt');
418
419       $result = wp_update_post($postdata);
420
421       if (!$result) {
422           return new IXR_Error(500, 'For some strange yet very annoying reason, this post could not be edited.');
423       }
424
425       return true;
426     }
427
428
429     /* blogger.deletePost ...deletes a post */
430     function blogger_deletePost($args) {
431
432       global $wpdb;
433
434       $post_ID     = $args[1];
435       $user_login  = $args[2];
436       $user_pass   = $args[3];
437       $publish     = $args[4];
438
439       if (!$this->login_pass_ok($user_login, $user_pass)) {
440         return $this->error;
441       }
442
443       $actual_post = wp_get_single_post($post_ID,ARRAY_A);
444
445       if (!$actual_post) {
446           return new IXR_Error(404, 'Sorry, no such post.');
447       }
448
449       $user_data = get_userdatabylogin($user_login);
450
451       if (!user_can_delete_post($user_data->ID, $post_ID)) {
452         return new IXR_Error(401, 'Sorry, you do not have the right to delete this post.');
453       }
454
455       $result = wp_delete_post($post_ID);
456
457       if (!$result) {
458           return new IXR_Error(500, 'For some strange yet very annoying reason, this post could not be deleted.');
459       }
460
461       return true;
462     }
463
464
465
466     /* MetaWeblog API functions
467      * specs on wherever Dave Winer wants them to be
468      */
469
470     /* metaweblog.newPost creates a post */
471     function mw_newPost($args) {
472
473       global $wpdb;
474
475       $blog_ID     = $args[0]; // we will support this in the near future
476       $user_login  = $args[1];
477       $user_pass   = $args[2];
478       $content_struct = $args[3];
479       $publish     = $args[4];
480
481       if (!$this->login_pass_ok($user_login, $user_pass)) {
482         return $this->error;
483       }
484
485       $user_data = get_userdatabylogin($user_login);
486       if (!user_can_create_post($user_data->ID, $blog_ID)) {
487         return new IXR_Error(401, 'Sorry, you can not post on this weblog or category.');
488       }
489
490       $post_author = $user_data->ID;
491
492       $post_title = $content_struct['title'];
493       $post_content = apply_filters( 'content_save_pre', $content_struct['description'] );
494       $post_status = $publish ? 'publish' : 'draft';
495
496       $post_excerpt = $content_struct['mt_excerpt'];
497       $post_more = $content_struct['mt_text_more'];
498
499       $comment_status = (empty($content_struct['mt_allow_comments'])) ?
500         get_settings('default_comment_status')
501         : $content_struct['mt_allow_comments'];
502
503       $ping_status = (empty($content_struct['mt_allow_pings'])) ?
504         get_settings('default_ping_status')
505         : $content_struct['mt_allow_pings'];
506
507       if ($post_more) {
508         $post_content = $post_content . "\n<!--more-->\n" . $post_more;
509       }
510         
511       // Do some timestamp voodoo
512       $dateCreatedd = $content_struct['dateCreated'];
513       if (!empty($dateCreatedd)) {
514         $dateCreated = $dateCreatedd->getIso();
515         $post_date     = get_date_from_gmt(iso8601_to_datetime($dateCreated));
516         $post_date_gmt = iso8601_to_datetime($dateCreated, GMT);
517       } else {
518         $post_date     = current_time('mysql');
519         $post_date_gmt = current_time('mysql', 1);
520       }
521
522       $catnames = $content_struct['categories'];
523       logIO('O', 'Post cats: ' . printr($catnames,true));
524