Ticket #2: 0000002-xmlrpc.php

File 0000002-xmlrpc.php, 85.5 kB (added by steamedpenguin, 3 years ago)
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
8 require_once(ABSPATH.WPINC."/class-xmlrpc.php");
9 require_once(ABSPATH.WPINC."/class-xmlrpcs.php");
10 require_once(ABSPATH.WPINC."/template-functions.php");
11 require_once(ABSPATH.WPINC."/functions.php");
12 require_once(ABSPATH.WPINC."/vars.php");
13
14 $use_cache = 1;
15 $post_autobr = 0;
16 $post_default_title = ""; // posts submitted via the xmlrpc interface get that title
17 $post_default_category = 1; // posts submitted via the xmlrpc interface go into that category
18
19 $xmlrpc_logging = 0;
20
21 function logIO($io,$msg) {
22     global $xmlrpc_logging;
23     if ($xmlrpc_logging) {
24         $fp = fopen("./xmlrpc.log","a+");
25         $date = date("Y-m-d H:i:s ");
26         $iot = ($io == "I") ? " Input: " : " Output: ";
27         fwrite($fp, "\n\n".$date.$iot.$msg);
28         fclose($fp);
29     }
30     return true;
31     }
32
33 function starify($string) {
34     $i = strlen($string);
35     return str_repeat('*', $i);
36 }
37
38 logIO("I",$HTTP_RAW_POST_DATA);
39
40 /**** DB Functions ****/
41
42 /*
43  * These really should be moved into wp-includes/functions.php,
44  * and re-used throughout the code, where possible. -- emc3
45  */
46
47 /*
48  * generic function for inserting data into the posts table.
49  */
50 function wp_insert_post($postarr = array()) {
51     global $wpdb, $tableposts;
52
53     // export array as variables
54     extract($postarr);
55     
56     // Do some escapes for safety
57     $post_content = $wpdb->escape($post_content);
58     $post_title = $wpdb->escape($post_title);
59     
60     $post_cat = $post_category[0];
61     
62     $sql = "INSERT INTO $tableposts
63         (post_author, post_date, post_content, post_title, post_excerpt, post_category, post_status)
64         VALUES ('$post_author','$post_date','$post_content','$post_title', '$post_excerpt','$post_cat', '$post_status')";
65
66     $result = $wpdb->query($sql);
67     $post_ID = $wpdb->insert_id;
68     
69     wp_set_post_cats('',$post_ID,$post_category);
70
71     // Return insert_id if we got a good result, otherwise return zero.
72     return $result?$post_ID:0;
73 }
74
75 function wp_get_single_post($postid = 0, $mode = OBJECT) {
76     global $wpdb, $tableposts;
77
78     $sql = "SELECT * FROM $tableposts WHERE ID=$postid";
79     $result = $wpdb->get_row($sql, $mode);
80
81     return $result;
82 }
83
84 function wp_get_recent_posts($num = 10) {
85     global $wpdb, $tableposts;
86
87     // Set the limit clause, if we got a limit
88     if ($num) {
89         $limit = "LIMIT $num";
90     }
91
92     $sql = "SELECT * FROM $tableposts ORDER BY post_date DESC $limit";
93     $result = $wpdb->get_results($sql,ARRAY_A);
94
95     return $result?$result:array();
96 }
97
98 function wp_update_post($postarr = array()) {
99     global $wpdb, $tableposts;
100
101     // First get all of the original fields
102     extract(wp_get_single_post($postarr['ID']));   
103
104     // Now overwrite any changed values being passed in
105     extract($postarr);
106     
107     // Do some escapes for safety
108     $post_content = $wpdb->escape($post_content);
109     $post_title = $wpdb->escape($post_title);
110     $post_excerpt = $wpdb->escape($post_excerpt);
111     
112     $sql = "UPDATE $tableposts
113         SET post_content = '$post_content',
114         post_title = '$post_title',
115         post_category = $post_category[0],
116         post_status = '$post_status',
117         post_date = '$post_date',
118         post_excerpt = '$post_excerpt',
119         ping_status = '$ping_status',
120         comment_status = '$comment_status'
121         WHERE ID = $ID";
122         
123     $result = $wpdb->query($sql);
124
125     wp_set_post_cats('',$ID,$post_category);
126     
127     return $wpdb->rows_affected;
128 }
129
130 function wp_get_post_cats($blogid = '1', $post_ID = 0) {
131     global $wpdb, $tablepost2cat;
132     
133     $sql = "SELECT category_id FROM $tablepost2cat WHERE post_id = $post_ID ORDER BY category_id";
134
135     $result = $wpdb->get_col($sql);
136
137     return $result;
138 }
139
140 function wp_set_post_cats($blogid = '1', $post_ID = 0, $post_categories = array()) {
141     global $wpdb, $tablepost2cat;
142     // If $post_categories isn't already an array, make it one:
143     if (!is_array($post_categories)) {
144         if (!$post_categories) {
145             $post_categories = 1;
146         }
147         $post_categories = array($post_categories);
148     }
149
150     // First the old categories
151     $old_categories = $wpdb->get_col("SELECT category_id FROM $tablepost2cat WHERE post_id = $post_ID");
152
153     // Delete any?
154     foreach ($old_categories as $old_cat) {
155         if (!in_array($old_cat, $post_categories)) // If a category was there before but isn't now
156             $wpdb->query("DELETE FROM $tablepost2cat WHERE category_id = $old_cat AND post_id = $post_ID LIMIT 1");
157 logio("O","deleting post/cat: $post_ID, $old_cat");
158     }
159
160     // Add any?
161     foreach ($post_categories as $new_cat) {
162         if (!in_array($new_cat, $old_categories))
163             $wpdb->query("INSERT INTO $tablepost2cat (post_id, category_id) VALUES ($post_ID, $new_cat)");
164 logio("O","adding post/cat: $post_ID, $new_cat");
165     }
166 }
167
168 function wp_delete_post($postid = 0) {
169     global $wpdb, $tableposts, $tablepost2cat;
170     
171     $sql = "DELETE FROM $tablepost2cat WHERE post_id = $postid";
172     $wpdb->query($sql);
173         
174     $sql = "DELETE FROM $tableposts WHERE ID = $postid";
175     
176     $wpdb->query($sql);
177
178     $result = $wpdb->rows_affected;
179     
180     return $result;
181 }
182
183 /**** /DB Functions ****/
184
185 /**** Misc ****/
186
187 // get permalink from post ID
188 function post_permalink($post_ID=0, $mode = 'id') {
189     global $wpdb;
190     global $tableposts;
191     global $siteurl, $blogfilename, $querystring_start, $querystring_equal, $querystring_separator;
192
193     $blog_URL = $siteurl.'/'.$blogfilename;
194
195     $postdata = get_postdata($post_ID);
196
197     // this will probably change to $blog_ID = $postdata['Blog_ID'] one day.
198     $blog_ID = 1;
199
200     if (!($postdata===false)) {
201     
202         switch(strtolower($mode)) {
203             case 'title':
204                 $title = preg_replace('/[^a-zA-Z0-9_\.-]/', '_', $postdata['Title']);
205                 break;
206             case 'id':
207             default:
208                 $title = "post-$post_ID";
209                 break;
210         }
211
212         // this code is blatantly derived from permalink_link()
213         $archive_mode = get_settings('archive_mode');
214         switch($archive_mode) {
215             case 'daily':
216                 $post_URL = $blog_URL.$querystring_start.'m'.$querystring_equal.substr($postdata['Date'],0,4).substr($postdata['Date'],5,2).substr($postdata['Date'],8,2).'#'.$title;
217                 break;
218             case 'monthly':
219                 $post_URL = $blog_URL.$querystring_start.'m'.$querystring_equal.substr($postdata['Date'],0,4).substr($postdata['Date'],5,2).'#'.$title;
220                 break;
221             case 'weekly':
222                 if((!isset($cacheweekly)) || (empty($cacheweekly[$postdata['Date']]))) {
223                     $sql = "SELECT WEEK('".$postdata['Date']."') as wk";
224                         $row = $wpdb->get_row($sql);
225                     $cacheweekly[$postdata['Date']] = $row->wk;
226                 }
227                 $post_URL = $blog_URL.$querystring_start.'m'.$querystring_equal.substr($postdata['Date'],0,4).$querystring_separator.'w'.$querystring_equal.$cacheweekly[$postdata['Date']].'#'.$title;
228                 break;
229             case 'postbypost':
230                 $post_URL = $blog_URL.$querystring_start.'p'.$querystring_equal.$post_ID;
231                 break;
232         }
233     }
234
235     return $post_URL;
236 }
237
238 // Get the name of a category from its ID
239 function get_cat_name($cat_id) {
240     global $wpdb,$tablecategories;
241     
242     $cat_id -= 0;     // force numeric
243     $name = $wpdb->get_var("SELECT cat_name FROM $tablecategories WHERE cat_ID=$cat_id");
244     
245     return $name;
246 }
247
248 // Get the ID of a category from its name
249 function get_cat_ID($cat_name='General') {
250     global $wpdb,$tablecategories;
251     
252     $cid = $wpdb->get_var("SELECT cat_ID FROM $tablecategories WHERE cat_name='$cat_name'");
253
254     return $cid?$cid:1;    // default to cat 1
255 }
256
257 // Get author's preferred display name
258 function get_author_name($auth_id) {
259     $authordata = get_userdata($auth_id);
260
261     switch($authordata["user_idmode"]) {
262         case "nickname":
263             $authorname = $authordata["user_nickname"];
264
265         case "login":
266             $authorname = $authordata["user_login"];
267             break;
268     
269         case "firstname":
270             $authorname = $authordata["user_firstname"];
271             break;
272
273         case "lastname":
274             $authorname = $authordata["user_lastname"];
275             break;
276
277         case "namefl":
278             $authorname = $authordata["user_firstname"]." ".$authordata["user_lastname"];
279             break;
280
281         case "namelf":
282             $authorname = $authordata["user_lastname"]." ".$authordata["user_firstname"];
283             break;
284
285         default:
286             $authorname = $authordata["user_nickname"];
287             break;
288     }
289
290     return $authorname;
291 }
292
293 // get extended entry info (<!--more-->)
294 function get_extended($post) {
295     list($main,$extended) = explode('<!--more-->',$post);
296
297     // Strip leading and trailing whitespace
298     $main = preg_replace('/^[\s]*(.*)[\s]*$/','\\1',$main);
299     $extended = preg_replace('/^[\s]*(.*)[\s]*$/','\\1',$extended);
300
301     return array('main' => $main, 'extended' => $extended);
302 }
303
304 // do trackbacks for a list of urls
305 // borrowed from edit.php
306 // accepts a comma-separated list of trackback urls and a post id
307 function trackback_url_list($tb_list, $post_id) {
308     if (!empty($tb_list)) {
309         // get post data
310         $postdata = wp_get_single_post($post_id, ARRAY_A);
311
312         // import postdata as variables
313         extract($postdata);
314         
315         // form an excerpt
316         $excerpt = strip_tags($post_excerpt?$post_excerpt:$post_content);
317         
318         if (strlen($excerpt) > 255) {
319             $exerpt = substr($excerpt,0,252) . '...';
320         }
321         
322         $trackback_urls = explode(',', $tb_list);
323         foreach($trackback_urls as $tb_url) {
324             $tb_url = trim($tb_url);
325             trackback($tb_url, stripslashes($post_title), $excerpt, $post_id);
326         }
327     }
328 }
329
330 /**** /Misc ****/
331
332 /**** B2 API ****/
333
334
335 # note: the b2 API currently consists of the Blogger API,
336 #       plus the following methods:
337 #
338 # b2.newPost , b2.getCategories
339
340 # Note: the b2 API will be replaced by the standard Weblogs.API once the specs are defined.
341
342
343 ### b2.newPost ###
344
345 $wpnewpost_sig=array(array($xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcBoolean, $xmlrpcString, $xmlrpcString, $xmlrpcString));
346
347 $wpnewpost_doc='Adds a post, blogger-api like, +title +category +postdate';
348
349 function b2newpost($m) {
350     global $wpdb;
351
352     global $xmlrpcerruser; // import user errcode value
353     global $blog_ID,$cache_userdata,$tableposts,$use_rss,$use_weblogsping,$post_autobr;
354     global $post_default_title,$post_default_category;
355     global $cafelogID, $sleep_after_edit;
356     $err="";
357
358
359     $username=$m->getParam(2);
360     $password=$m->getParam(3);
361     $content=$m->getParam(4);
362     $title=$m->getParam(6);
363     $category=$m->getParam(7);
364     $postdate=$m->getParam(8);
365
366     $username = $username->scalarval();
367     $password = $password->scalarval();
368     $content = $content->scalarval();
369     $title = $title->scalarval();
370     $post_category = $category->scalarval();
371     $postdate = $postdate->scalarval();
372
373
374     if (user_pass_ok($username,$password)) {
375
376         $userdata = get_userdatabylogin($username);
377         $post_author = $userdata->ID;
378         $user_level = $userdata->user_level;
379         if ($user_level < 1) {
380             return new xmlrpcresp(0, $xmlrpcerruser+1, // user error 1
381        "Sorry, level 0 users can not post");
382         }
383
384
385         $post_content = format_to_post($content);
386         $post_title = addslashes($title);
387
388
389         $time_difference = get_settings("time_difference");
390         if ($postdate != "") {
391             $post_date = $postdate;
392         } else {
393             $post_date = date("Y-m-d H:i:s",(time() + ($time_difference * 3600)));
394         }
395
396         $post_data = compact('post_content','post_title','post_date','post_author','post_category');
397         
398         $result = wp_insert_post($post_data);
399
400         if (!$result)
401             return new xmlrpcresp(0, $xmlrpcerruser+2, // user error 2
402        "For some strange yet very annoying reason, your entry couldn't be posted.");
403
404
405         $post_ID = $result;
406
407         if (!isset($blog_ID)) { $blog_ID = 1; }
408         
409         if (isset($sleep_after_edit) && $sleep_after_edit > 0) {
410             sleep($sleep_after_edit);
411         }
412
413
414
415         pingWeblogs($blog_ID);
416         pingCafelog($cafelogID, $post_title, $post_ID);
417         pingBlogs($blog_ID);
418         pingback($content, $post_ID);
419
420
421         return new xmlrpcresp(new xmlrpcval("$post_ID"));
422
423     } else {
424
425         return new xmlrpcresp(0, $xmlrpcerruser+3, // user error 3
426        'Wrong username/password combination '.$username.' / '.starify($password));
427     }
428 }
429
430
431
432 ### b2.getCategories ###
433
434 $wpgetcategories_sig=array(array($xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString));
435
436 $wpgetcategories_doc='given a blogID, gives a struct that list categories in that blog, using categoryID and categoryName. categoryName is there so the user would choose a category name from the client, rather than just a number. however, when using b2.newPost, only the category ID number should be sent.';
437
438 function b2getcategories($m) {
439     global $wpdb;
440     global $xmlrpcerruser,$tablecategories;
441
442
443     $blogid=$m->getParam(0);
444     $blogid = $blogid->scalarval(); // we dot not use that yet, that will be used with multiple blogs
445
446     $username=$m->getParam(1);
447     $username = $username->scalarval();
448
449     $password=$m->getParam(2);
450     $password = $password->scalarval();
451
452     $userdata = get_userdatabylogin($username);
453
454
455     if (user_pass_ok($username,$password)) {
456
457         $results = $wpdb->get_results("SELECT * FROM $tablecategories ORDER BY cat_ID ASC");
458     if (!$results) die("Error getting data");
459         $i = 0;
460     foreach($results as $row) {
461             $cat_name = $row->cat_name;
462             $cat_ID = $row->cat_ID;
463
464             $struct[$i] = new xmlrpcval(array("categoryID" => new xmlrpcval($cat_ID),
465                                           "categoryName" => new xmlrpcval($cat_name)
466                                           ),"struct");
467             $i = $i + 1;
468         }
469
470         $data = array($struct[0]);
471         for ($j=1; $j<$i; $j++) {
472             array_push($data, $struct[$j]);
473         }
474
475         $resp = new xmlrpcval($data, "array");
476
477         return new xmlrpcresp($resp);
478
479     } else {
480         return new xmlrpcresp(0, $xmlrpcerruser+3, // user error 3
481        'Wrong username/password combination '.$username.' / '.starify($password));
482     }
483 }
484
485
486
487 ### b2.getPostURL ###
488
489 $wp_getPostURL_sig = array(array($xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString));
490
491 $wp_getPostURL_doc = 'Given a blog ID, username, password, and a post ID, returns the URL to that post.';
492
493 function b2_getPostURL($m) {
494     global $wpdb;
495     global $xmlrpcerruser, $tableposts;
496     global $siteurl, $blogfilename, $querystring_start, $querystring_equal, $querystring_separator;
497
498
499     // ideally, this would be used:
500     // $blog_ID = $m->getParam(0);
501     // $blog_ID = $blog_ID->scalarval();
502     // but right now, b2 handles only one blog, so... :P
503     $blog_ID = 1;
504
505     $username=$m->getParam(2);
506     $username = $username->scalarval();
507
508     $password=$m->getParam(3);
509     $password = $password->scalarval();
510
511     $post_ID = $m->getParam(4);
512     $post_ID = intval($post_ID->scalarval());
513
514     $userdata = get_userdatabylogin($username);
515
516     if ($userdata->user_level < 1) {
517         return new xmlrpcresp(0, $xmlrpcerruser+1, // user error 1
518        "Sorry, users whose level is zero, can not use this method.");
519     }
520
521     if (user_pass_ok($username,$password)) {
522
523         $blog_URL = $siteurl.'/'.$blogfilename;
524
525         $postdata = get_postdata($post_ID);
526
527         if (!($postdata===false)) {
528
529             $title = preg_replace('/[^a-zA-Z0-9_\.-]/', '_', $postdata['Title']);
530
531             // this code is blatantly derived from permalink_link()
532             $archive_mode = get_settings('archive_mode');
533             switch($archive_mode) {
534                 case 'daily':
535                     $post_URL = $blog_URL.$querystring_start.'m'.$querystring_equal.substr($postdata['Date'],0,4).