Make WordPress Core

Ticket #4899: class.app.patch

File class.app.patch, 127.0 KB (added by darkdragon, 19 years ago)

Remove AtomServer from wp-app.php. [6021]

  • wp-app.php

     
    5050}
    5151add_filter('posts_where', 'wa_posts_where_include_drafts_filter');
    5252
    53 class AtomServer {
     53require_once(ABSPATH . WPINC . '/class/AtomServer.php');
    5454
    55         var $ATOM_CONTENT_TYPE = 'application/atom+xml';
    56         var $CATEGORIES_CONTENT_TYPE = 'application/atomcat+xml';
    57         var $SERVICE_CONTENT_TYPE = 'application/atomsvc+xml';
    58 
    59         var $ATOM_NS = 'http://www.w3.org/2005/Atom';
    60         var $ATOMPUB_NS = 'http://www.w3.org/2007/app';
    61 
    62         var $ENTRIES_PATH = "posts";
    63         var $CATEGORIES_PATH = "categories";
    64         var $MEDIA_PATH = "attachments";
    65         var $ENTRY_PATH = "post";
    66         var $SERVICE_PATH = "service";
    67         var $MEDIA_SINGLE_PATH = "attachment";
    68 
    69         var $params = array();
    70         var $script_name = "wp-app.php";
    71         var $media_content_types = array('image/*','audio/*','video/*');
    72         var $atom_content_types = array('application/atom+xml');
    73 
    74         var $selectors = array();
    75 
    76         // support for head
    77         var $do_output = true;
    78 
    79         function AtomServer() {
    80 
    81                 $this->script_name = array_pop(explode('/',$_SERVER['SCRIPT_NAME']));
    82 
    83                 $this->selectors = array(
    84                         '@/service$@' =>
    85                                 array('GET' => 'get_service'),
    86                         '@/categories$@' =>
    87                                 array('GET' => 'get_categories_xml'),
    88                         '@/post/(\d+)$@' =>
    89                                 array('GET' => 'get_post',
    90                                                 'PUT' => 'put_post',
    91                                                 'DELETE' => 'delete_post'),
    92                         '@/posts/?(\d+)?$@' =>
    93                                 array('GET' => 'get_posts',
    94                                                 'POST' => 'create_post'),
    95                         '@/attachments/?(\d+)?$@' =>
    96                                 array('GET' => 'get_attachment',
    97                                                 'POST' => 'create_attachment'),
    98                         '@/attachment/file/(\d+)$@' =>
    99                                 array('GET' => 'get_file',
    100                                                 'PUT' => 'put_file',
    101                                                 'DELETE' => 'delete_file'),
    102                         '@/attachment/(\d+)$@' =>
    103                                 array('GET' => 'get_attachment',
    104                                                 'PUT' => 'put_attachment',
    105                                                 'DELETE' => 'delete_attachment'),
    106                 );
    107         }
    108 
    109         function handle_request() {
    110                 global $always_authenticate;
    111 
    112                 $path = $_SERVER['PATH_INFO'];
    113                 $method = $_SERVER['REQUEST_METHOD'];
    114 
    115                 log_app('REQUEST',"$method $path\n================");
    116 
    117                 $this->process_conditionals();
    118                 //$this->process_conditionals();
    119 
    120                 // exception case for HEAD (treat exactly as GET, but don't output)
    121                 if($method == 'HEAD') {
    122                         $this->do_output = false;
    123                         $method = 'GET';
    124                 }
    125 
    126                 // redirect to /service in case no path is found.
    127                 if(strlen($path) == 0 || $path == '/') {
    128                         $this->redirect($this->get_service_url());
    129                 }
    130        
    131                 // dispatch
    132                 foreach($this->selectors as $regex => $funcs) {
    133                         if(preg_match($regex, $path, $matches)) {
    134                         if(isset($funcs[$method])) {
    135 
    136                                 // authenticate regardless of the operation and set the current
    137                                 // user. each handler will decide if auth is required or not.
    138                                 $this->authenticate();               
    139                                 $u = wp_get_current_user();
    140                                 if(!isset($u) || $u->ID == 0) {
    141                                         if ($always_authenticate) {
    142                                                 $this->auth_required('Credentials required.');
    143                                         }
    144                                 }
    145 
    146                                 array_shift($matches);
    147                                 call_user_func_array(array(&$this,$funcs[$method]), $matches);
    148                                 exit();
    149                         } else {
    150                                 // only allow what we have handlers for...
    151                                 $this->not_allowed(array_keys($funcs));
    152                         }
    153                         }
    154                 }
    155 
    156                 // oops, nothing found
    157                 $this->not_found();
    158         }
    159 
    160         function get_service() {
    161                 log_app('function','get_service()');
    162                 $entries_url = attribute_escape($this->get_entries_url());
    163                 $categories_url = attribute_escape($this->get_categories_url());
    164                 $media_url = attribute_escape($this->get_attachments_url());
    165                 foreach ($this->media_content_types as $med) {
    166                   $accepted_media_types = $accepted_media_types . "<accept>" . $med . "</accept>";
    167                 }
    168                 $atom_prefix="atom";
    169                 $service_doc = <<<EOD
    170 <service xmlns="$this->ATOMPUB_NS" xmlns:$atom_prefix="$this->ATOM_NS">
    171   <workspace>
    172     <$atom_prefix:title>WordPress Workspace</$atom_prefix:title>
    173     <collection href="$entries_url">
    174       <$atom_prefix:title>WordPress Posts</$atom_prefix:title>
    175       <accept>$this->ATOM_CONTENT_TYPE;type=entry</accept>
    176       <categories href="$categories_url" />
    177     </collection>
    178     <collection href="$media_url">
    179       <$atom_prefix:title>WordPress Media</$atom_prefix:title>
    180       $accepted_media_types
    181     </collection>
    182   </workspace>
    183 </service>
    184 
    185 EOD;
    186 
    187                 $this->output($service_doc, $this->SERVICE_CONTENT_TYPE);
    188         }
    189 
    190         function get_categories_xml() {
    191 
    192                 log_app('function','get_categories_xml()');
    193                 $home = attribute_escape(get_bloginfo_rss('home'));
    194 
    195                 $categories = "";
    196                 $cats = get_categories("hierarchical=0&hide_empty=0");
    197                 foreach ((array) $cats as $cat) {
    198                         $categories .= "    <category term=\"" . attribute_escape($cat->cat_name) .  "\" />\n";
    199 }
    200                 $output = <<<EOD
    201 <app:categories xmlns:app="$this->ATOMPUB_NS"
    202         xmlns="$this->ATOM_NS"
    203         fixed="yes" scheme="$home">
    204         $categories
    205 </app:categories>
    206 EOD;
    207         $this->output($output, $this->CATEGORIES_CONTENT_TYPE);
    208 }
    209 
    210         /*
    211          * Create Post (No arguments)
    212          */
    213         function create_post() {
    214                 global $blog_id, $wpdb;
    215                 $this->get_accepted_content_type($this->atom_content_types);
    216 
    217                 $parser = new AtomParser();
    218                 if(!$parser->parse()) {
    219                         $this->client_error();
    220                 }
    221 
    222                 $entry = array_pop($parser->feed->entries);
    223                
    224                 log_app('Received entry:', print_r($entry,true));
    225                
    226                 $catnames = array();
    227                 foreach($entry->categories as $cat)
    228                         array_push($catnames, $cat["term"]);
    229                
    230                 $wp_cats = get_categories(array('hide_empty' => false));
    231                
    232                 $post_category = array();
    233                
    234                 foreach($wp_cats as $cat) {
    235                         if(in_array($cat->cat_name, $catnames))
    236                                 array_push($post_category, $cat->cat_ID);
    237                 }
    238 
    239                 $publish = (isset($entry->draft) && trim($entry->draft) == 'yes') ? false : true;
    240 
    241                 $cap = ($publish) ? 'publish_posts' : 'edit_posts';
    242 
    243                 if(!current_user_can($cap))
    244                         $this->auth_required(__('Sorry, you do not have the right to edit/publish new posts.'));
    245 
    246                 $blog_ID = (int ) $blog_id;
    247                 $post_status = ($publish) ? 'publish' : 'draft';
    248                 $post_author = (int) $user->ID;
    249                 $post_title = $entry->title[1];
    250                 $post_content = $entry->content[1];
    251                 $post_excerpt = $entry->summary[1];
    252                 $pubtimes = $this->get_publish_time($entry);
    253                 $post_date = $pubtimes[0];
    254                 $post_date_gmt = $pubtimes[1];
    255                
    256                 if ( isset( $_SERVER['HTTP_SLUG'] ) )
    257                         $post_name = $_SERVER['HTTP_SLUG'];
    258 
    259                 $post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'post_name');
    260 
    261                 $this->escape($post_data);
    262                 log_app('Inserting Post. Data:', print_r($post_data,true));
    263 
    264                 $postID = wp_insert_post($post_data);
    265 
    266                 if (!$postID) {
    267                         $this->internal_error(__('Sorry, your entry could not be posted. Something wrong happened.'));
    268                 }
    269 
    270                 // getting warning here about unable to set headers
    271                 // because something in the cache is printing to the buffer
    272                 // could we clean up wp_set_post_categories or cache to not print
    273                 // this could affect our ability to send back the right headers
    274                 @wp_set_post_categories($postID, $post_category);
    275 
    276                 $output = $this->get_entry($postID);
    277 
    278                 log_app('function',"create_post($postID)");
    279                 $this->created($postID, $output);
    280         }
    281 
    282         function get_post($postID) {
    283 
    284                 global $entry;
    285                 $this->set_current_entry($postID);
    286                 $output = $this->get_entry($postID);
    287                 log_app('function',"get_post($postID)");
    288                 $this->output($output);
    289 
    290         }
    291 
    292         function put_post($postID) {
    293                 global $wpdb;
    294 
    295                 // checked for valid content-types (atom+xml)
    296                 // quick check and exit
    297                 $this->get_accepted_content_type($this->atom_content_types);
    298 
    299                 $parser = new AtomParser();
    300                 if(!$parser->parse()) {
    301                         $this->bad_request();
    302                 }
    303 
    304                 $parsed = array_pop($parser->feed->entries);
    305 
    306                 log_app('Received UPDATED entry:', print_r($parsed,true));
    307 
    308                 // check for not found
    309                 global $entry;
    310                 $entry = $GLOBALS['entry'];
    311                 $this->set_current_entry($postID);
    312 
    313                 if(!current_user_can('edit_post', $entry['ID']))
    314                         $this->auth_required(__('Sorry, you do not have the right to edit this post.'));
    315 
    316                 $publish = (isset($parsed->draft) && trim($parsed->draft) == 'yes') ? false : true;
    317 
    318                 extract($entry);
    319 
    320                 $post_title = $parsed->title[1];
    321                 $post_content = $parsed->content[1];
    322                 $post_excerpt = $parsed->summary[1];
    323                 $pubtimes = $this->get_publish_time($entry);
    324                 $post_date = $pubtimes[0];
    325                 $post_date_gmt = $pubtimes[1];     
    326 
    327                 // let's not go backwards and make something draft again.
    328                 if(!$publish && $post_status == 'draft') {
    329                         $post_status = ($publish) ? 'publish' : 'draft';
    330                 } elseif($publish) {
    331                         $post_status = 'publish';
    332                 }
    333 
    334                 $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'post_date', 'post_date_gmt');
    335                 $this->escape($postdata);
    336 
    337                 $result = wp_update_post($postdata);
    338 
    339                 if (!$result) {
    340                         $this->internal_error(__('For some strange yet very annoying reason, this post could not be edited.'));
    341                 }
    342 
    343                 log_app('function',"put_post($postID)");
    344                 $this->ok();
    345         }
    346 
    347         function delete_post($postID) {
    348 
    349                 // check for not found
    350                 global $entry;
    351                 $this->set_current_entry($postID);
    352 
    353                 if(!current_user_can('edit_post', $postID)) {
    354                         $this->auth_required(__('Sorry, you do not have the right to delete this post.'));
    355                 }
    356 
    357                 if ($entry['post_type'] == 'attachment') {
    358                         $this->delete_attachment($postID);
    359                 } else {
    360                         $result = wp_delete_post($postID);
    361 
    362                         if (!$result) {
    363                                 $this->internal_error(__('For some strange yet very annoying reason, this post could not be deleted.'));
    364                         }
    365 
    366                         log_app('function',"delete_post($postID)");
    367                         $this->ok();
    368                 }
    369 
    370         }
    371 
    372         function get_attachment($postID = NULL) {
    373 
    374                 global $entry;
    375                 if (!isset($postID)) {
    376                         $this->get_attachments();
    377                 } else {
    378                         $this->set_current_entry($postID);
    379                         $output = $this->get_entry($postID, 'attachment');
    380                         log_app('function',"get_attachment($postID)");
    381                         $this->output($output);
    382                 }
    383         }
    384 
    385         function create_attachment() {
    386                 global $wp, $wpdb, $wp_query, $blog_id;
    387 
    388                 $type = $this->get_accepted_content_type();
    389 
    390                 if(!current_user_can('upload_files'))
    391                         $this->auth_required(__('You do not have permission to upload files.'));
    392 
    393                 $fp = fopen("php://input", "rb");
    394                 $bits = NULL;
    395                 while(!feof($fp)) {
    396                         $bits .= fread($fp, 4096);
    397                 }
    398                 fclose($fp);
    399 
    400                 $slug = '';
    401                 if ( isset( $_SERVER['HTTP_SLUG'] ) )
    402                         $slug = sanitize_file_name( $_SERVER['HTTP_SLUG'] );
    403                 elseif ( isset( $_SERVER['HTTP_TITLE'] ) )
    404                         $slug = sanitize_file_name( $_SERVER['HTTP_TITLE'] );
    405                 elseif ( empty( $slug ) ) // just make a random name
    406                         $slug = substr( md5( uniqid( microtime() ) ), 0, 7);
    407                 $ext = preg_replace( '|.*/([a-z]+)|', '$1', $_SERVER['CONTENT_TYPE'] );
    408                 $slug = "$slug.$ext";
    409                 $file = wp_upload_bits( $slug, NULL, $bits);
    410 
    411                 log_app('wp_upload_bits returns:',print_r($file,true));
    412 
    413                 $url = $file['url'];
    414                 $file = $file['file'];
    415                 $filename = basename($file);
    416 
    417                 $header = apply_filters('wp_create_file_in_uploads', $file); // replicate
    418 
    419                 // Construct the attachment array
    420                 $attachment = array(
    421                         'post_title' => $slug,
    422                         'post_content' => $slug,
    423                         'post_status' => 'attachment',
    424                         'post_parent' => 0,
    425                         'post_mime_type' => $type,
    426                         'guid' => $url
    427                         );
    428 
    429                 // Save the data
    430                 $postID = wp_insert_attachment($attachment, $file, $post);
    431 
    432                 if (!$postID) {
    433                         $this->internal_error(__('Sorry, your entry could not be posted. Something wrong happened.'));
    434                 }
    435 
    436                 $output = $this->get_entry($postID, 'attachment');
    437 
    438                 $this->created($postID, $output, 'attachment');
    439                 log_app('function',"create_attachment($postID)");
    440         }
    441 
    442         function put_attachment($postID) {
    443                 global $wpdb;
    444 
    445                 // checked for valid content-types (atom+xml)
    446                 // quick check and exit
    447                 $this->get_accepted_content_type($this->atom_content_types);
    448 
    449                 $parser = new AtomParser();
    450                 if(!$parser->parse()) {
    451                         $this->bad_request();
    452                 }
    453 
    454                 $parsed = array_pop($parser->feed->entries);
    455 
    456                 // check for not found
    457                 global $entry;
    458                 $this->set_current_entry($postID);
    459 
    460                 if(!current_user_can('edit_post', $entry['ID']))
    461                         $this->auth_required(__('Sorry, you do not have the right to edit this post.'));
    462 
    463                 $publish = (isset($parsed->draft) && trim($parsed->draft) == 'yes') ? false : true;
    464 
    465                 extract($entry);
    466 
    467                 $post_title = $parsed->title[1];
    468                 $post_content = $parsed->content[1];
    469 
    470                 $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt');
    471                 $this->escape($postdata);
    472 
    473                 $result = wp_update_post($postdata);
    474 
    475                 if (!$result) {
    476                         $this->internal_error(__('For some strange yet very annoying reason, this post could not be edited.'));
    477                 }
    478 
    479                 log_app('function',"put_attachment($postID)");
    480                 $this->ok();
    481         }
    482 
    483         function delete_attachment($postID) {
    484                 log_app('function',"delete_attachment($postID). File '$location' deleted.");
    485 
    486                 // check for not found
    487                 global $entry;
    488                 $this->set_current_entry($postID);
    489 
    490                 if(!current_user_can('edit_post', $postID)) {
    491                         $this->auth_required(__('Sorry, you do not have the right to delete this post.'));
    492                 }
    493 
    494                 $location = get_post_meta($entry['ID'], '_wp_attached_file', true);
    495 
    496                 // delete file
    497                 @unlink($location);
    498 
    499                 // delete attachment
    500                 $result = wp_delete_post($postID);
    501 
    502                 if (!$result) {
    503                         $this->internal_error(__('For some strange yet very annoying reason, this post could not be deleted.'));
    504                 }
    505 
    506                 log_app('function',"delete_attachment($postID). File '$location' deleted.");
    507                 $this->ok();
    508         }
    509 
    510         function get_file($postID) {
    511 
    512                 // check for not found
    513                 global $entry;
    514                 $this->set_current_entry($postID);
    515 
    516                 // then whether user can edit the specific post
    517                 if(!current_user_can('edit_post', $postID)) {
    518                         $this->auth_required(__('Sorry, you do not have the right to edit this post.'));
    519                 }
    520 
    521                 $location = get_post_meta($entry['ID'], '_wp_attached_file', true);
    522                 $filetype = wp_check_filetype($location);
    523 
    524                 if(!isset($location) || 'attachment' != $entry['post_type'] || empty($filetype['ext']))
    525                         $this->internal_error(__('Error ocurred while accessing post metadata for file location.'));
    526 
    527                 status_header('200');
    528                 header('Content-Type: ' . $entry['post_mime_type']);
    529                 header('Connection: close');
    530 
    531                 $fp = fopen($location, "rb");
    532                 while(!feof($fp)) {
    533                         echo fread($fp, 4096);
    534                 }
    535                 fclose($fp);
    536 
    537                 log_app('function',"get_file($postID)");
    538                 exit;
    539         }
    540 
    541         function put_file($postID) {
    542 
    543                 $type = $this->get_accepted_content_type();
    544 
    545                 // first check if user can upload
    546                 if(!current_user_can('upload_files'))
    547                         $this->auth_required(__('You do not have permission to upload files.'));
    548 
    549                 // check for not found
    550                 global $entry;
    551                 $this->set_current_entry($postID);
    552 
    553                 // then whether user can edit the specific post
    554                 if(!current_user_can('edit_post', $postID)) {
    555                         $this->auth_required(__('Sorry, you do not have the right to edit this post.'));
    556                 }
    557 
    558                 $location = get_post_meta($entry['ID'], '_wp_attached_file', true);
    559                 $filetype = wp_check_filetype($location);
    560 
    561                 if(!isset($location) || 'attachment' != $entry['post_type'] || empty($filetype['ext']))
    562                         $this->internal_error(__('Error ocurred while accessing post metadata for file location.'));
    563 
    564                 $fp = fopen("php://input", "rb");
    565                 $localfp = fopen($location, "w+");
    566                 while(!feof($fp)) {
    567                         fwrite($localfp,fread($fp, 4096));
    568                 }
    569                 fclose($fp);
    570                 fclose($localfp);
    571 
    572                 $ID = $entry['ID'];
    573                 $pubtimes = $this->get_publish_time($entry);
    574                 $post_date = $pubtimes[0];
    575                 $post_date_gmt = $pubtimes[1];
    576 
    577                 $post_data = compact('ID', 'post_date', 'post_date_gmt');
    578                 $result = wp_update_post($post_data);
    579 
    580                 if (!$result) {
    581                         $this->internal_error(__('Sorry, your entry could not be posted. Something wrong happened.'));
    582                 }
    583 
    584                 log_app('function',"put_file($postID)");
    585                 $this->ok();
    586         }
    587 
    588         function get_entries_url($page = NULL) {
    589                 if($GLOBALS['post_type'] == 'attachment') {
    590                         $path = $this->MEDIA_PATH;
    591                 } else {
    592                         $path = $this->ENTRIES_PATH;
    593                 }
    594                 $url = get_bloginfo('url') . '/' . $this->script_name . '/' . $path;
    595                 if(isset($page) && is_int($page)) {
    596                         $url .= "/$page";
    597                 }
    598                 return $url;
    599         }
    600 
    601         function the_entries_url($page = NULL) {
    602                 $url = $this->get_entries_url($page);
    603                 echo $url;
    604         }
    605 
    606         function get_categories_url($page = NULL) {
    607                 return get_bloginfo('url') . '/' . $this->script_name . '/' . $this->CATEGORIES_PATH;
    608         }
    609 
    610         function the_categories_url() {
    611                 $url = $this->get_categories_url();
    612                 echo $url;
    613         }
    614 
    615         function get_attachments_url($page = NULL) {
    616                 $url = get_bloginfo('url') . '/' . $this->script_name . '/' . $this->MEDIA_PATH;
    617                 if(isset($page) && is_int($page)) {
    618                         $url .= "/$page";
    619                 }
    620                 return $url;
    621         }
    622 
    623         function the_attachments_url($page = NULL) {
    624                 $url = $this->get_attachments_url($page);
    625                 echo $url;
    626         }
    627 
    628         function get_service_url() {
    629                 return get_bloginfo('url') . '/' . $this->script_name . '/' . $this->SERVICE_PATH;
    630         }
    631 
    632         function get_entry_url($postID = NULL) {
    633                 if(!isset($postID)) {
    634                         global $post;
    635                         $postID = (int) $GLOBALS['post']->ID;
    636                 }
    637 
    638                 $url = get_bloginfo('url') . '/' . $this->script_name . '/' . $this->ENTRY_PATH . "/$postID";
    639 
    640                 log_app('function',"get_entry_url() = $url");
    641                 return $url;
    642         }
    643 
    644         function the_entry_url($postID = NULL) {
    645                 $url = $this->get_entry_url($postID);
    646                 echo $url;
    647         }
    648 
    649         function get_media_url($postID = NULL) {
    650                 if(!isset($postID)) {
    651                         global $post;
    652                         $postID = (int) $GLOBALS['post']->ID;
    653                 }
    654 
    655                 $url = get_bloginfo('url') . '/' . $this->script_name . '/' . $this->MEDIA_SINGLE_PATH ."/file/$postID";
    656 
    657                 log_app('function',"get_media_url() = $url");
    658                 return $url;
    659         }
    660 
    661         function the_media_url($postID = NULL) {
    662                 $url = $this->get_media_url($postID);
    663                 echo $url;
    664         }
    665 
    666         function set_current_entry($postID) {
    667                 global $entry;
    668                 log_app('function',"set_current_entry($postID)");
    669 
    670                 if(!isset($postID)) {
    671                         // $this->bad_request();
    672                         $this->not_found();
    673                 }
    674 
    675                 $entry = wp_get_single_post($postID,ARRAY_A);
    676 
    677                 if(!isset($entry) || !isset($entry['ID']))
    678                         $this->not_found();
    679 
    680                 return;
    681         }
    682 
    683         function get_posts($page = 1, $post_type = 'post') {
    684                         log_app('function',"get_posts($page, '$post_type')");
    685                         $feed = $this->get_feed($page, $post_type);
    686                         $this->output($feed);
    687         }
    688 
    689         function get_attachments($page = 1, $post_type = 'attachment') {
    690             log_app('function',"get_attachments($page, '$post_type')");
    691             $GLOBALS['post_type'] = $post_type;
    692             $feed = $this->get_feed($page, $post_type);
    693             $this->output($feed);
    694         }
    695 
    696         function get_feed($page = 1, $post_type = 'post') {
    697                 global $post, $wp, $wp_query, $posts, $wpdb, $blog_id, $post_cache;
    698                 log_app('function',"get_feed($page, '$post_type')");
    699                 ob_start();
    700 
    701                 if(!isset($page)) {
    702                         $page = 1;
    703                 }
    704                 $page = (int) $page;
    705 
    706                 $count = get_option('posts_per_rss');
    707 
    708                 wp('what_to_show=posts&posts_per_page=' . $count . '&offset=' . ($count * ($page-1) ));
    709 
    710                 $post = $GLOBALS['post'];
    711                 $posts = $GLOBALS['posts'];
    712                 $wp = $GLOBALS['wp'];
    713                 $wp_query = $GLOBALS['wp_query'];
    714                 $wpdb = $GLOBALS['wpdb'];
    715                 $blog_id = (int) $GLOBALS['blog_id'];
    716                 $post_cache = $GLOBALS['post_cache'];
    717                 log_app('function',"query_posts(# " . print_r($wp_query, true) . "#)");
    718 
    719                 log_app('function',"total_count(# $wp_query->max_num_pages #)");
    720                 $last_page = $wp_query->max_num_pages;
    721                 $next_page = (($page + 1) > $last_page) ? NULL : $page + 1;
    722                 $prev_page = ($page - 1) < 1 ? NULL : $page - 1;
    723                 $last_page = ((int)$last_page == 1 || (int)$last_page == 0) ? NULL : (int) $last_page;
    724                 $self_page = $page > 1 ? $page : NULL;
    725 ?><feed xmlns="<?php echo $this->ATOM_NS ?>" xmlns:app="<?php echo $this->ATOMPUB_NS ?>" xml:lang="<?php echo get_option('rss_language'); ?>">
    726 <id><?php $this->the_entries_url() ?></id>
    727 <updated><?php echo mysql2date('Y-m-d\TH:i:s\Z', get_lastpostmodified('GMT')); ?></updated>
    728 <title type="text"><?php bloginfo_rss('name') ?></title>
    729 <subtitle type="text"><?php bloginfo_rss("description") ?></subtitle>
    730 <link rel="first" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url() ?>" />
    731 <?php if(isset($prev_page)): ?>
    732 <link rel="previous" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url($prev_page) ?>" />
    733 <?php endif; ?>
    734 <?php if(isset($next_page)): ?>
    735 <link rel="next" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url($next_page) ?>" />
    736 <?php endif; ?>
    737 <link rel="last" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url($last_page) ?>" />
    738 <link rel="self" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url($self_page) ?>" />
    739 <rights type="text">Copyright <?php echo mysql2date('Y', get_lastpostdate('blog')); ?></rights>
    740 <generator uri="http://wordpress.com/" version="1.0.5-dc">WordPress.com Atom API</generator>
    741 <?php if ( have_posts() ) {
    742                         while ( have_posts() ) {
    743                                 the_post();
    744                                 $this->echo_entry();
    745                         }
    746                 }
    747 ?></feed>
    748 <?php
    749                 $feed = ob_get_contents();
    750                 ob_end_clean();
    751                 return $feed;
    752         }
    753 
    754         function get_entry($postID, $post_type = 'post') {
    755                 log_app('function',"get_entry($postID, '$post_type')");
    756                 ob_start();
    757                 global $posts, $post, $wp_query, $wp, $wpdb, $blog_id, $post_cache;
    758                 switch($post_type) {
    759                         case 'post':
    760                                 $varname = 'p';
    761                                 break;
    762                         case 'attachment':
    763                                 $varname = 'attachment_id';
    764                                 break;
    765                 }
    766                 query_posts($varname . '=' . $postID);
    767                 if ( have_posts() ) {
    768                         while ( have_posts() ) {
    769                                 the_post();
    770                                 $this->echo_entry();
    771                                 log_app('$post',print_r($GLOBALS['post'],true));
    772                                 $entry = ob_get_contents();
    773                                 break;
    774                         }
    775                 }
    776                 ob_end_clean();
    777 
    778                 log_app('get_entry returning:',$entry);
    779                 return $entry;
    780         }
    781 
    782         function echo_entry() { ?>
    783 <entry xmlns="<?php echo $this->ATOM_NS ?>"
    784        xmlns:app="<?php echo $this->ATOMPUB_NS ?>" xml:lang="<?php echo get_option('rss_language'); ?>">
    785         <id><?php the_guid($GLOBALS['post']->ID); ?></id>
    786 <?php list($content_type, $content) = $this->prep_content(get_the_title()); ?>
    787         <title type="<?php echo $content_type ?>"><?php echo $content ?></title>
    788         <updated><?php echo get_post_modified_time('Y-m-d\TH:i:s\Z', true); ?></updated>
    789         <published><?php echo get_post_time('Y-m-d\TH:i:s\Z', true); ?></published>
    790         <app:edited><?php echo get_post_modified_time('Y-m-d\TH:i:s\Z', true); ?></app:edited>
    791         <app:control>
    792                 <app:draft><?php echo ($GLOBALS['post']->post_status == 'draft' ? 'yes' : 'no') ?></app:draft>
    793         </app:control>
    794         <author>
    795                 <name><?php the_author()?></name>
    796                 <email><?php the_author_email()?></email>
    797 <?php if (get_the_author_url() && get_the_author_url() != 'http://') { ?>
    798                 <uri><?php the_author_url()?></uri>
    799 <?php } ?>
    800         </author>
    801 <?php if($GLOBALS['post']->post_type == 'attachment') { ?>
    802         <link rel="edit-media" href="<?php $this->the_media_url() ?>" />
    803         <content type="<?php echo $GLOBALS['post']->post_mime_type ?>" src="<?php the_guid(); ?>"/>
    804 <?php } else { ?>
    805         <link href="<?php the_permalink_rss() ?>" />
    806 <?php if ( strlen( $GLOBALS['post']->post_content ) ) :
    807 list($content_type, $content) = $this->prep_content(get_the_content()); ?>
    808         <content type="<?php echo $content_type ?>"><?php echo $content ?></content>
    809 <?php endif; ?>
    810 <?php } ?>
    811         <link rel="edit" href="<?php $this->the_entry_url() ?>" />
    812 <?php foreach(get_the_category() as $category) { ?>
    813         <category scheme="<?php bloginfo_rss('home') ?>" term="<?php echo $category->cat_name?>" />
    814 <?php } ?>
    815 <?php list($content_type, $content) = $this->prep_content(get_the_excerpt()); ?>
    816         <summary type="<?php echo $content_type ?>"><?php echo $content ?></summary>
    817 </entry>
    818 <?php }
    819 
    820         function prep_content($data) {
    821                 if (strpos($data, '<') === false && strpos($data, '&') === false) {
    822                         return array('text', $data);
    823                 }
    824 
    825                 $parser = xml_parser_create();
    826                 xml_parse($parser, '<div>' . $data . '</div>', true);
    827                 $code = xml_get_error_code($parser);
    828                 xml_parser_free($parser);
    829 
    830                 if (!$code) {
    831                         if (strpos($data, '<') === false) {
    832                                 return array('text', $data);
    833                         } else {
    834                                 $data = "<div xmlns='http://www.w3.org/1999/xhtml'>$data</div>";
    835                                 return array('xhtml', $data);
    836                         }
    837                 }
    838 
    839                 if (strpos($data, ']]>') == false) {
    840                         return array('html', "<![CDATA[$data]]>");
    841                 } else {
    842                         return array('html', htmlspecialchars($data));
    843                 }
    844         }
    845 
    846         function ok() {
    847                 log_app('Status','200: OK');
    848                 header('Content-Type: text/plain');
    849                 status_header('200');
    850                 exit;
    851         }
    852 
    853         function no_content() {
    854                 log_app('Status','204: No Content');
    855                 header('Content-Type: text/plain');
    856                 status_header('204');
    857                 echo "Deleted.";
    858                 exit;
    859         }
    860 
    861         function internal_error($msg = 'Internal Server Error') {
    862                 log_app('Status','500: Server Error');
    863                 header('Content-Type: text/plain');
    864                 status_header('500');
    865                 echo $msg;
    866                 exit;
    867         }
    868 
    869         function bad_request() {
    870                 log_app('Status','400: Bad Request');
    871                 header('Content-Type: text/plain');
    872                 status_header('400');
    873                 exit;
    874         }
    875 
    876         function length_required() {
    877                 log_app('Status','411: Length Required');
    878                 header("HTTP/1.1 411 Length Required");
    879                 header('Content-Type: text/plain');
    880                 status_header('411');
    881                 exit;
    882         }
    883 
    884         function invalid_media() {
    885                 log_app('Status','415: Unsupported Media Type');
    886                 header("HTTP/1.1 415 Unsupported Media Type");
    887                 header('Content-Type: text/plain');
    888                 exit;
    889         }
    890 
    891         function not_found() {
    892                 log_app('Status','404: Not Found');
    893                 header('Content-Type: text/plain');
    894                 status_header('404');
    895                 exit;
    896         }
    897 
    898         function not_allowed($allow) {
    899                 log_app('Status','405: Not Allowed');
    900                 header('Allow: ' . join(',', $allow));
    901                 status_header('405');
    902                 exit;
    903         }
    904 
    905         function redirect($url) {
    906 
    907                 log_app('Status','302: Redirect');
    908                 $escaped_url = attribute_escape($url);
    909                 $content = <<<EOD
    910 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
    911 <html>
    912   <head>
    913     <title>302 Found</title>
    914   </head>
    915 <body>
    916   <h1>Found</h1>
    917   <p>The document has moved <a href="$escaped_url">here</a>.</p>
    918   </body>
    919 </html>
    920 
    921 EOD;
    922                 header('HTTP/1.1 302 Moved');
    923                 header('Content-Type: text/html');
    924                 header('Location: ' . $url);
    925                 echo $content;
    926                 exit;
    927 
    928         }
    929 
    930 
    931         function client_error($msg = 'Client Error') {
    932                 log_app('Status','400: Client Error');
    933                 header('Content-Type: text/plain');
    934                 status_header('400');
    935                 exit;
    936         }
    937 
    938         function created($post_ID, $content, $post_type = 'post') {
    939                 log_app('created()::$post_ID',"$post_ID, $post_type");
    940                 $edit = $this->get_entry_url($post_ID);
    941                 switch($post_type) {
    942                         case 'post':
    943                                 $ctloc = $this->get_entry_url($post_ID);
    944                                 break;
    945                         case 'attachment':
    946                                 $edit = get_bloginfo('url') . '/' . $this->script_name . "/attachments/$post_ID";
    947                                 break;
    948                 }
    949                 header("Content-Type: $this->ATOM_CONTENT_TYPE");
    950                 if(isset($ctloc))
    951                         header('Content-Location: ' . $ctloc);
    952                 header('Location: ' . $edit);
    953                 status_header('201');
    954                 echo $content;
    955                 exit;
    956         }
    957 
    958         function auth_required($msg) {
    959                 log_app('Status','401: Auth Required');
    960                 nocache_headers();
    961                 header('WWW-Authenticate: Basic realm="WordPress Atom Protocol"');
    962                 header("HTTP/1.1 401 $msg");
    963                 header('Status: ' . $msg);
    964                 header('Content-Type: text/html');
    965                 $content = <<<EOD
    966 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
    967 <html>
    968   <head>
    969     <title>401 Unauthorized</title>
    970   </head>
    971 <body>
    972     <h1>401 Unauthorized</h1>
    973     <p>$msg</p>
    974   </body>
    975 </html>
    976 
    977 EOD;
    978                 echo $content;
    979                 exit;
    980         }
    981 
    982         function output($xml, $ctype = 'application/atom+xml') {
    983                         status_header('200');
    984                         $xml = '<?xml version="1.0" encoding="' . strtolower(get_option('blog_charset')) . '"?>'."\n".$xml;
    985                         header('Connection: close');
    986                         header('Content-Length: '. strlen($xml));
    987                         header('Content-Type: ' . $ctype);
    988                         header('Content-Disposition: attachment; filename=atom.xml');
    989                         header('Date: '. date('r'));
    990                         if($this->do_output)
    991                                 echo $xml;
    992                         log_app('function', "output:\n$xml");
    993                         exit;
    994         }
    995 
    996         function escape(&$array) {
    997                 global $wpdb;
    998 
    999                 foreach ($array as $k => $v) {
    1000                                 if (is_array($v)) {
    1001                                                 $this->escape($array[$k]);
    1002                                 } else if (is_object($v)) {
    1003                                                 //skip
    1004                                 } else {
    1005                                                 $array[$k] = $wpdb->escape($v);
    1006                                 }
    1007                 }
    1008         }
    1009 
    1010         /*
    1011          * Access credential through various methods and perform login
    1012          */
    1013         function authenticate() {
    1014                 $login_data = array();
    1015                 $already_md5 = false;
    1016 
    1017                 log_app("authenticate()",print_r($_ENV, true));
    1018 
    1019                 // if using mod_rewrite/ENV hack
    1020                 // http://www.besthostratings.com/articles/http-auth-php-cgi.html
    1021                 if(isset($_SERVER['HTTP_AUTHORIZATION'])) {
    1022                         list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) =
    1023                                 explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
    1024                 }
    1025 
    1026                 // If Basic Auth is working...
    1027                 if(isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
    1028                         $login_data = array('login' => $_SERVER['PHP_AUTH_USER'],       'password' => $_SERVER['PHP_AUTH_PW']);
    1029                         log_app("Basic Auth",$login_data['login']);
    1030                 } else {
    1031                         // else, do cookie-based authentication
    1032                         if (function_exists('wp_get_cookie_login')) {
    1033                                 $login_data = wp_get_cookie_login();
    1034                                 $already_md5 = true;
    1035                         }
    1036                 }
    1037 
    1038                 // call wp_login and set current user
    1039                 if (!empty($login_data) && wp_login($login_data['login'], $login_data['password'], $already_md5)) {
    1040                          $current_user = new WP_User(0, $login_data['login']);
    1041                          wp_set_current_user($current_user->ID);
    1042                         log_app("authenticate()",$login_data['login']);
    1043                 }
    1044         }
    1045 
    1046         function get_accepted_content_type($types = NULL) {
    1047 
    1048                 if(!isset($types)) {
    1049                         $types = $this->media_content_types;
    1050                 }
    1051 
    1052                 if(!isset($_SERVER['CONTENT_LENGTH']) || !isset($_SERVER['CONTENT_TYPE'])) {
    1053                         $this->length_required();
    1054                 }
    1055 
    1056                 $type = $_SERVER['CONTENT_TYPE'];
    1057                 list($type,$subtype) = explode('/',$type);
    1058                 list($subtype) = explode(";",$subtype); // strip MIME parameters
    1059                 log_app("get_accepted_content_type", "type=$type, subtype=$subtype");
    1060 
    1061                 foreach($types as $t) {
    1062                         list($acceptedType,$acceptedSubtype) = explode('/',$t);
    1063                         if($acceptedType == '*' || $acceptedType == $type) {
    1064                                 if($acceptedSubtype == '*' || $acceptedSubtype == $subtype)
    1065                                         return $type . "/" . $subtype;
    1066                         }
    1067                 }
    1068 
    1069                 $this->invalid_media();
    1070         }
    1071 
    1072         function process_conditionals() {
    1073 
    1074                 if(empty($this->params)) return;
    1075                 if($_SERVER['REQUEST_METHOD'] == 'DELETE') return;
    1076 
    1077                 switch($this->params[0]) {
    1078                         case $this->ENTRY_PATH:
    1079                                 global $post;
    1080                                 $post = wp_get_single_post($this->params[1]);
    1081                                 $wp_last_modified = get_post_modified_time('D, d M Y H:i:s', true);
    1082                                 $post = NULL;
    1083                                 break;
    1084                         case $this->ENTRIES_PATH:
    1085                                 $wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastpostmodified('GMT'), 0).' GMT';
    1086                                 break;
    1087                         default:
    1088                                 return;
    1089                 }
    1090                 $wp_etag = md5($wp_last_modified);
    1091                 @header("Last-Modified: $wp_last_modified");
    1092                 @header("ETag: $wp_etag");
    1093 
    1094                 // Support for Conditional GET
    1095                 if (isset($_SERVER['HTTP_IF_NONE_MATCH']))
    1096                         $client_etag = stripslashes($_SERVER['HTTP_IF_NONE_MATCH']);
    1097                 else
    1098                         $client_etag = false;
    1099 
    1100                 $client_last_modified = trim( $_SERVER['HTTP_IF_MODIFIED_SINCE']);
    1101                 // If string is empty, return 0. If not, attempt to parse into a timestamp
    1102                 $client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;
    1103 
    1104                 // Make a timestamp for our most recent modification...
    1105                 $wp_modified_timestamp = strtotime($wp_last_modified);
    1106 
    1107                 if ( ($client_last_modified && $client_etag) ?
    1108                 (($client_modified_timestamp >= $wp_modified_timestamp) && ($client_etag == $wp_etag)) :
    1109                 (($client_modified_timestamp >= $wp_modified_timestamp) || ($client_etag == $wp_etag)) ) {
    1110                         status_header( 304 );
    1111                         exit;
    1112                 }
    1113         }
    1114 
    1115         function rfc3339_str2time($str) {
    1116            
    1117             $match = false;
    1118             if(!preg_match("/(\d{4}-\d{2}-\d{2})T(\d{2}\:\d{2}\:\d{2})\.?\d{0,3}(Z|[+-]+\d{2}\:\d{2})/", $str, $match))
    1119                         return false;
    1120        
    1121             if($match[3] == 'Z')
    1122                         $match[3] == '+0000';
    1123        
    1124             return strtotime($match[1] . " " . $match[2] . " " . $match[3]);
    1125         }       
    1126 
    1127         function get_publish_time($entry) {
    1128 
    1129             $pubtime = $this->rfc3339_str2time($entry->published);
    1130            
    1131             if(!$pubtime) {
    1132                         return array(current_time('mysql'),current_time('mysql',1));
    1133             } else {
    1134                         return array(date("Y-m-d H:i:s", $pubtime), gmdate("Y-m-d H:i:s", $pubtime));
    1135             }
    1136         }
    1137 
    1138 }
    1139 
    114055$server = new AtomServer();
    114156$server->handle_request();
    114257
  • wp-includes/class/IXR.php

     
     1<?php
     2/*
     3   IXR - The Inutio XML-RPC Library - (c) Incutio Ltd 2002-2005
     4   Version 1.7 (beta) - Simon Willison, 23rd May 2005
     5   Site:   http://scripts.incutio.com/xmlrpc/
     6   Manual: http://scripts.incutio.com/xmlrpc/manual.php
     7   Made available under the BSD License: http://www.opensource.org/licenses/bsd-license.php
     8*/
     9
     10class IXR_Value {
     11    var $data;
     12    var $type;
     13    function IXR_Value ($data, $type = false) {
     14        $this->data = $data;
     15        if (!$type) {
     16            $type = $this->calculateType();
     17        }
     18        $this->type = $type;
     19        if ($type == 'struct') {
     20            /* Turn all the values in the array in to new IXR_Value objects */
     21            foreach ($this->data as $key => $value) {
     22                $this->data[$key] = new IXR_Value($value);
     23            }
     24        }
     25        if ($type == 'array') {
     26            for ($i = 0, $j = count($this->data); $i < $j; $i++) {
     27                $this->data[$i] = new IXR_Value($this->data[$i]);
     28            }
     29        }
     30    }
     31    function calculateType() {
     32        if ($this->data === true || $this->data === false) {
     33            return 'boolean';
     34        }
     35        if (is_integer($this->data)) {
     36            return 'int';
     37        }
     38        if (is_double($this->data)) {
     39            return 'double';
     40        }
     41        // Deal with IXR object types base64 and date
     42        if (is_object($this->data) && is_a($this->data, 'IXR_Date')) {
     43            return 'date';
     44        }
     45        if (is_object($this->data) && is_a($this->data, 'IXR_Base64')) {
     46            return 'base64';
     47        }
     48        // If it is a normal PHP object convert it in to a struct
     49        if (is_object($this->data)) {
     50
     51            $this->data = get_object_vars($this->data);
     52            return 'struct';
     53        }
     54        if (!is_array($this->data)) {
     55            return 'string';
     56        }
     57        /* We have an array - is it an array or a struct ? */
     58        if ($this->isStruct($this->data)) {
     59            return 'struct';
     60        } else {
     61            return 'array';
     62        }
     63    }
     64    function getXml() {
     65        /* Return XML for this value */
     66        switch ($this->type) {
     67            case 'boolean':
     68                return '<boolean>'.(($this->data) ? '1' : '0').'</boolean>';
     69                break;
     70            case 'int':
     71                return '<int>'.$this->data.'</int>';
     72                break;
     73            case 'double':
     74                return '<double>'.$this->data.'</double>';
     75                break;
     76            case 'string':
     77                return '<string>'.htmlspecialchars($this->data).'</string>';
     78                break;
     79            case 'array':
     80                $return = '<array><data>'."\n";
     81                foreach ($this->data as $item) {
     82                    $return .= '  <value>'.$item->getXml()."</value>\n";
     83                }
     84                $return .= '</data></array>';
     85                return $return;
     86                break;
     87            case 'struct':
     88                $return = '<struct>'."\n";
     89                foreach ($this->data as $name => $value) {
     90                                        $name = htmlspecialchars($name);
     91                    $return .= "  <member><name>$name</name><value>";
     92                    $return .= $value->getXml()."</value></member>\n";
     93                }
     94                $return .= '</struct>';
     95                return $return;
     96                break;
     97            case 'date':
     98            case 'base64':
     99                return $this->data->getXml();
     100                break;
     101        }
     102        return false;
     103    }
     104    function isStruct($array) {
     105        /* Nasty function to check if an array is a struct or not */
     106        $expected = 0;
     107        foreach ($array as $key => $value) {
     108            if ((string)$key != (string)$expected) {
     109                return true;
     110            }
     111            $expected++;
     112        }
     113        return false;
     114    }
     115}
     116
     117
     118class IXR_Message {
     119    var $message;
     120    var $messageType;  // methodCall / methodResponse / fault
     121    var $faultCode;
     122    var $faultString;
     123    var $methodName;
     124    var $params;
     125    // Current variable stacks
     126    var $_arraystructs = array();   // The stack used to keep track of the current array/struct
     127    var $_arraystructstypes = array(); // Stack keeping track of if things are structs or array
     128    var $_currentStructName = array();  // A stack as well
     129    var $_param;
     130    var $_value;
     131    var $_currentTag;
     132    var $_currentTagContents;
     133    // The XML parser
     134    var $_parser;
     135    function IXR_Message ($message) {
     136        $this->message = $message;
     137    }
     138    function parse() {
     139        // first remove the XML declaration
     140        $this->message = preg_replace('/<\?xml(.*)?\?'.'>/', '', $this->message);
     141        if (trim($this->message) == '') {
     142            return false;
     143        }
     144        $this->_parser = xml_parser_create();
     145        // Set XML parser to take the case of tags in to account
     146        xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false);
     147        // Set XML parser callback functions
     148        xml_set_object($this->_parser, $this);
     149        xml_set_element_handler($this->_parser, 'tag_open', 'tag_close');
     150        xml_set_character_data_handler($this->_parser, 'cdata');
     151        if (!xml_parse($this->_parser, $this->message)) {
     152            /* die(sprintf('XML error: %s at line %d',
     153                xml_error_string(xml_get_error_code($this->_parser)),
     154                xml_get_current_line_number($this->_parser))); */
     155            return false;
     156        }
     157        xml_parser_free($this->_parser);
     158        // Grab the error messages, if any
     159        if ($this->messageType == 'fault') {
     160            $this->faultCode = $this->params[0]['faultCode'];
     161            $this->faultString = $this->params[0]['faultString'];
     162        }
     163        return true;
     164    }
     165    function tag_open($parser, $tag, $attr) {
     166                $this->_currentTagContents = '';
     167        $this->currentTag = $tag;
     168        switch($tag) {
     169            case 'methodCall':
     170            case 'methodResponse':
     171            case 'fault':
     172                $this->messageType = $tag;
     173                break;
     174            /* Deal with stacks of arrays and structs */
     175            case 'data':    // data is to all intents and puposes more interesting than array
     176                $this->_arraystructstypes[] = 'array';
     177                $this->_arraystructs[] = array();
     178                break;
     179            case 'struct':
     180                $this->_arraystructstypes[] = 'struct';
     181                $this->_arraystructs[] = array();
     182                break;
     183        }
     184    }
     185    function cdata($parser, $cdata) {
     186        $this->_currentTagContents .= $cdata;
     187    }
     188    function tag_close($parser, $tag) {
     189        $valueFlag = false;
     190        switch($tag) {
     191            case 'int':
     192            case 'i4':
     193                $value = (int) trim($this->_currentTagContents);
     194                $valueFlag = true;
     195                break;
     196            case 'double':
     197                $value = (double) trim($this->_currentTagContents);
     198                $valueFlag = true;
     199                break;
     200            case 'string':
     201                $value = $this->_currentTagContents;
     202                $valueFlag = true;
     203                break;
     204            case 'dateTime.iso8601':
     205                $value = new IXR_Date(trim($this->_currentTagContents));
     206                // $value = $iso->getTimestamp();
     207                $valueFlag = true;
     208                break;
     209            case 'value':
     210                // "If no type is indicated, the type is string."
     211                if (trim($this->_currentTagContents) != '') {
     212                    $value = (string)$this->_currentTagContents;
     213                    $valueFlag = true;
     214                }
     215                break;
     216            case 'boolean':
     217                $value = (boolean) trim($this->_currentTagContents);
     218                $valueFlag = true;
     219                break;
     220            case 'base64':
     221                $value = base64_decode( trim( $this->_currentTagContents ) );
     222                $valueFlag = true;
     223                break;
     224            /* Deal with stacks of arrays and structs */
     225            case 'data':
     226            case 'struct':
     227                $value = array_pop($this->_arraystructs);
     228                array_pop($this->_arraystructstypes);
     229                $valueFlag = true;
     230                break;
     231            case 'member':
     232                array_pop($this->_currentStructName);
     233                break;
     234            case 'name':
     235                $this->_currentStructName[] = trim($this->_currentTagContents);
     236                break;
     237            case 'methodName':
     238                $this->methodName = trim($this->_currentTagContents);
     239                break;
     240        }
     241        if ($valueFlag) {
     242            if (count($this->_arraystructs) > 0) {
     243                // Add value to struct or array
     244                if ($this->_arraystructstypes[count($this->_arraystructstypes)-1] == 'struct') {
     245                    // Add to struct
     246                    $this->_arraystructs[count($this->_arraystructs)-1][$this->_currentStructName[count($this->_currentStructName)-1]] = $value;
     247                } else {
     248                    // Add to array
     249                    $this->_arraystructs[count($this->_arraystructs)-1][] = $value;
     250                }
     251            } else {
     252                // Just add as a paramater
     253                $this->params[] = $value;
     254            }
     255        }
     256                $this->_currentTagContents = '';
     257    }       
     258}
     259
     260
     261class IXR_Server {
     262    var $data;
     263    var $callbacks = array();
     264    var $message;
     265    var $capabilities;
     266    function IXR_Server($callbacks = false, $data = false) {
     267        $this->setCapabilities();
     268        if ($callbacks) {
     269            $this->callbacks = $callbacks;
     270        }
     271        $this->setCallbacks();
     272        $this->serve($data);
     273    }
     274    function serve($data = false) {
     275        if (!$data) {
     276            global $HTTP_RAW_POST_DATA;
     277            if (!$HTTP_RAW_POST_DATA) {
     278               die('XML-RPC server accepts POST requests only.');
     279            }
     280            $data = $HTTP_RAW_POST_DATA;
     281        }
     282        $this->message = new IXR_Message($data);
     283        if (!$this->message->parse()) {
     284            $this->error(-32700, 'parse error. not well formed');
     285        }
     286        if ($this->message->messageType != 'methodCall') {
     287            $this->error(-32600, 'server error. invalid xml-rpc. not conforming to spec. Request must be a methodCall');
     288        }
     289        $result = $this->call($this->message->methodName, $this->message->params);
     290        // Is the result an error?
     291        if (is_a($result, 'IXR_Error')) {
     292            $this->error($result);
     293        }
     294        // Encode the result
     295        $r = new IXR_Value($result);
     296        $resultxml = $r->getXml();
     297        // Create the XML
     298        $xml = <<<EOD
     299<methodResponse>
     300  <params>
     301    <param>
     302      <value>
     303        $resultxml
     304      </value>
     305    </param>
     306  </params>
     307</methodResponse>
     308
     309EOD;
     310        // Send it
     311        $this->output($xml);
     312    }
     313    function call($methodname, $args) {
     314        if (!$this->hasMethod($methodname)) {
     315            return new IXR_Error(-32601, 'server error. requested method '.$methodname.' does not exist.');
     316        }
     317        $method = $this->callbacks[$methodname];
     318        // Perform the callback and send the response
     319        if (count($args) == 1) {
     320            // If only one paramater just send that instead of the whole array
     321            $args = $args[0];
     322        }
     323        // Are we dealing with a function or a method?
     324        if (substr($method, 0, 5) == 'this:') {
     325            // It's a class method - check it exists
     326            $method = substr($method, 5);
     327            if (!method_exists($this, $method)) {
     328                return new IXR_Error(-32601, 'server error. requested class method "'.$method.'" does not exist.');
     329            }
     330            // Call the method
     331            $result = $this->$method($args);
     332        } else {
     333            // It's a function - does it exist?
     334            if (is_array($method)) {
     335                if (!method_exists($method[0], $method[1])) {
     336                return new IXR_Error(-32601, 'server error. requested object method "'.$method[1].'" does not exist.');
     337                }
     338            } else if (!function_exists($method)) {
     339                return new IXR_Error(-32601, 'server error. requested function "'.$method.'" does not exist.');
     340            }
     341            // Call the function
     342            $result = call_user_func($method, $args);
     343        }
     344        return $result;
     345    }
     346
     347    function error($error, $message = false) {
     348        // Accepts either an error object or an error code and message
     349        if ($message && !is_object($error)) {
     350            $error = new IXR_Error($error, $message);
     351        }
     352        $this->output($error->getXml());
     353    }
     354    function output($xml) {
     355        $xml = '<?xml version="1.0"?>'."\n".$xml;
     356        $length = strlen($xml);
     357        header('Connection: close');
     358        header('Content-Length: '.$length);
     359        header('Content-Type: text/xml');
     360        header('Date: '.date('r'));
     361        echo $xml;
     362        exit;
     363    }
     364    function hasMethod($method) {
     365        return in_array($method, array_keys($this->callbacks));
     366    }
     367    function setCapabilities() {
     368        // Initialises capabilities array
     369        $this->capabilities = array(
     370            'xmlrpc' => array(
     371                'specUrl' => 'http://www.xmlrpc.com/spec',
     372                'specVersion' => 1
     373            ),
     374            'faults_interop' => array(
     375                'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php',
     376                'specVersion' => 20010516
     377            ),
     378            'system.multicall' => array(
     379                'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208',
     380                'specVersion' => 1
     381            ),
     382        );   
     383    }
     384    function getCapabilities($args) {
     385        return $this->capabilities;
     386    }
     387    function setCallbacks() {
     388        $this->callbacks['system.getCapabilities'] = 'this:getCapabilities';
     389        $this->callbacks['system.listMethods'] = 'this:listMethods';
     390        $this->callbacks['system.multicall'] = 'this:multiCall';
     391    }
     392    function listMethods($args) {
     393        // Returns a list of methods - uses array_reverse to ensure user defined
     394        // methods are listed before server defined methods
     395        return array_reverse(array_keys($this->callbacks));
     396    }
     397    function multiCall($methodcalls) {
     398        // See http://www.xmlrpc.com/discuss/msgReader$1208
     399        $return = array();
     400        foreach ($methodcalls as $call) {
     401            $method = $call['methodName'];
     402            $params = $call['params'];
     403            if ($method == 'system.multicall') {
     404                $result = new IXR_Error(-32600, 'Recursive calls to system.multicall are forbidden');
     405            } else {
     406                $result = $this->call($method, $params);
     407            }
     408            if (is_a($result, 'IXR_Error')) {
     409                $return[] = array(
     410                    'faultCode' => $result->code,
     411                    'faultString' => $result->message
     412                );
     413            } else {
     414                $return[] = array($result);
     415            }
     416        }
     417        return $return;
     418    }
     419}
     420
     421class IXR_Request {
     422    var $method;
     423    var $args;
     424    var $xml;
     425    function IXR_Request($method, $args) {
     426        $this->method = $method;
     427        $this->args = $args;
     428        $this->xml = <<<EOD
     429<?xml version="1.0"?>
     430<methodCall>
     431<methodName>{$this->method}</methodName>
     432<params>
     433
     434EOD;
     435        foreach ($this->args as $arg) {
     436            $this->xml .= '<param><value>';
     437            $v = new IXR_Value($arg);
     438            $this->xml .= $v->getXml();
     439            $this->xml .= "</value></param>\n";
     440        }
     441        $this->xml .= '</params></methodCall>';
     442    }
     443    function getLength() {
     444        return strlen($this->xml);
     445    }
     446    function getXml() {
     447        return $this->xml;
     448    }
     449}
     450
     451
     452class IXR_Client {
     453    var $server;
     454    var $port;
     455    var $path;
     456    var $useragent;
     457    var $response;
     458    var $message = false;
     459    var $debug = false;
     460        var $timeout;
     461    // Storage place for an error message
     462    var $error = false;
     463    function IXR_Client($server, $path = false, $port = 80, $timeout = false) {
     464        if (!$path) {
     465            // Assume we have been given a URL instead
     466            $bits = parse_url($server);
     467            $this->server = $bits['host'];
     468            $this->port = isset($bits['port']) ? $bits['port'] : 80;
     469            $this->path = isset($bits['path']) ? $bits['path'] : '/';
     470            // Make absolutely sure we have a path
     471            if (!$this->path) {
     472                $this->path = '/';
     473            }
     474        } else {
     475            $this->server = $server;
     476            $this->path = $path;
     477            $this->port = $port;
     478        }
     479        $this->useragent = 'Incutio XML-RPC';
     480                $this->timeout = $timeout;
     481    }
     482    function query() {
     483        $args = func_get_args();
     484        $method = array_shift($args);
     485        $request = new IXR_Request($method, $args);
     486        $length = $request->getLength();
     487        $xml = $request->getXml();
     488        $r = "\r\n";
     489        $request  = "POST {$this->path} HTTP/1.0$r";
     490        $request .= "Host: {$this->server}$r";
     491        $request .= "Content-Type: text/xml$r";
     492        $request .= "User-Agent: {$this->useragent}$r";
     493        $request .= "Content-length: {$length}$r$r";
     494        $request .= $xml;
     495        // Now send the request
     496        if ($this->debug) {
     497            echo '<pre>'.htmlspecialchars($request)."\n</pre>\n\n";
     498        }
     499        if ($this->timeout) {
     500            $fp = @fsockopen($this->server, $this->port, $errno, $errstr, $this->timeout);
     501        } else {
     502            $fp = @fsockopen($this->server, $this->port, $errno, $errstr);
     503        }
     504        if (!$fp) {
     505            $this->error = new IXR_Error(-32300, "transport error - could not open socket: $errno $errstr");
     506            return false;
     507        }
     508        fputs($fp, $request);
     509        $contents = '';
     510        $gotFirstLine = false;
     511        $gettingHeaders = true;
     512        while (!feof($fp)) {
     513            $line = fgets($fp, 4096);
     514            if (!$gotFirstLine) {
     515                // Check line for '200'
     516                if (strstr($line, '200') === false) {
     517                    $this->error = new IXR_Error(-32300, 'transport error - HTTP status code was not 200');
     518                    return false;
     519                }
     520                $gotFirstLine = true;
     521            }
     522            if (trim($line) == '') {
     523                $gettingHeaders = false;
     524            }
     525            if (!$gettingHeaders) {
     526                $contents .= trim($line)."\n";
     527            }
     528        }
     529        if ($this->debug) {
     530            echo '<pre>'.htmlspecialchars($contents)."\n</pre>\n\n";
     531        }
     532        // Now parse what we've got back
     533        $this->message = new IXR_Message($contents);
     534        if (!$this->message->parse()) {
     535            // XML error
     536            $this->error = new IXR_Error(-32700, 'parse error. not well formed');
     537            return false;
     538        }
     539        // Is the message a fault?
     540        if ($this->message->messageType == 'fault') {
     541            $this->error = new IXR_Error($this->message->faultCode, $this->message->faultString);
     542            return false;
     543        }
     544        // Message must be OK
     545        return true;
     546    }
     547    function getResponse() {
     548        // methodResponses can only have one param - return that
     549        return $this->message->params[0];
     550    }
     551    function isError() {
     552        return (is_object($this->error));
     553    }
     554    function getErrorCode() {
     555        return $this->error->code;
     556    }
     557    function getErrorMessage() {
     558        return $this->error->message;
     559    }
     560}
     561
     562
     563class IXR_Error {
     564    var $code;
     565    var $message;
     566    function IXR_Error($code, $message) {
     567        $this->code = $code;
     568        $this->message = $message;
     569    }
     570    function getXml() {
     571        $xml = <<<EOD
     572<methodResponse>
     573  <fault>
     574    <value>
     575      <struct>
     576        <member>
     577          <name>faultCode</name>
     578          <value><int>{$this->code}</int></value>
     579        </member>
     580        <member>
     581          <name>faultString</name>
     582          <value><string>{$this->message}</string></value>
     583        </member>
     584      </struct>
     585    </value>
     586  </fault>
     587</methodResponse>
     588
     589EOD;
     590        return $xml;
     591    }
     592}
     593
     594
     595class IXR_Date {
     596    var $year;
     597    var $month;
     598    var $day;
     599    var $hour;
     600    var $minute;
     601    var $second;
     602    function IXR_Date($time) {
     603        // $time can be a PHP timestamp or an ISO one
     604        if (is_numeric($time)) {
     605            $this->parseTimestamp($time);
     606        } else {
     607            $this->parseIso($time);
     608        }
     609    }
     610    function parseTimestamp($timestamp) {
     611        $this->year = date('Y', $timestamp);
     612        $this->month = date('m', $timestamp);
     613        $this->day = date('d', $timestamp);
     614        $this->hour = date('H', $timestamp);
     615        $this->minute = date('i', $timestamp);
     616        $this->second = date('s', $timestamp);
     617    }
     618    function parseIso($iso) {
     619        $this->year = substr($iso, 0, 4);
     620        $this->month = substr($iso, 4, 2);
     621        $this->day = substr($iso, 6, 2);
     622        $this->hour = substr($iso, 9, 2);
     623        $this->minute = substr($iso, 12, 2);
     624        $this->second = substr($iso, 15, 2);
     625        $this->timezone = substr($iso, 17);
     626    }
     627    function getIso() {
     628        return $this->year.$this->month.$this->day.'T'.$this->hour.':'.$this->minute.':'.$this->second.$this->timezone;
     629    }
     630    function getXml() {
     631        return '<dateTime.iso8601>'.$this->getIso().'</dateTime.iso8601>';
     632    }
     633    function getTimestamp() {
     634        return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year);
     635    }
     636}
     637
     638
     639class IXR_Base64 {
     640    var $data;
     641    function IXR_Base64($data) {
     642        $this->data = $data;
     643    }
     644    function getXml() {
     645        return '<base64>'.base64_encode($this->data).'</base64>';
     646    }
     647}
     648
     649
     650class IXR_IntrospectionServer extends IXR_Server {
     651    var $signatures;
     652    var $help;
     653    function IXR_IntrospectionServer() {
     654        $this->setCallbacks();
     655        $this->setCapabilities();
     656        $this->capabilities['introspection'] = array(
     657            'specUrl' => 'http://xmlrpc.usefulinc.com/doc/reserved.html',
     658            'specVersion' => 1
     659        );
     660        $this->addCallback(
     661            'system.methodSignature',
     662            'this:methodSignature',
     663            array('array', 'string'),
     664            'Returns an array describing the return type and required parameters of a method'
     665        );
     666        $this->addCallback(
     667            'system.getCapabilities',
     668            'this:getCapabilities',
     669            array('struct'),
     670            'Returns a struct describing the XML-RPC specifications supported by this server'
     671        );
     672        $this->addCallback(
     673            'system.listMethods',
     674            'this:listMethods',
     675            array('array'),
     676            'Returns an array of available methods on this server'
     677        );
     678        $this->addCallback(
     679            'system.methodHelp',
     680            'this:methodHelp',
     681            array('string', 'string'),
     682            'Returns a documentation string for the specified method'
     683        );
     684    }
     685    function addCallback($method, $callback, $args, $help) {
     686        $this->callbacks[$method] = $callback;
     687        $this->signatures[$method] = $args;
     688        $this->help[$method] = $help;
     689    }
     690    function call($methodname, $args) {
     691        // Make sure it's in an array
     692        if ($args && !is_array($args)) {
     693            $args = array($args);
     694        }
     695        // Over-rides default call method, adds signature check
     696        if (!$this->hasMethod($methodname)) {
     697            return new IXR_Error(-32601, 'server error. requested method "'.$this->message->methodName.'" not specified.');
     698        }
     699        $method = $this->callbacks[$methodname];
     700        $signature = $this->signatures[$methodname];
     701        $returnType = array_shift($signature);
     702        // Check the number of arguments
     703        if (count($args) != count($signature)) {
     704            return new IXR_Error(-32602, 'server error. wrong number of method parameters');
     705        }
     706        // Check the argument types
     707        $ok = true;
     708        $argsbackup = $args;
     709        for ($i = 0, $j = count($args); $i < $j; $i++) {
     710            $arg = array_shift($args);
     711            $type = array_shift($signature);
     712            switch ($type) {
     713                case 'int':
     714                case 'i4':
     715                    if (is_array($arg) || !is_int($arg)) {
     716                        $ok = false;
     717                    }
     718                    break;
     719                case 'base64':
     720                case 'string':
     721                    if (!is_string($arg)) {
     722                        $ok = false;
     723                    }
     724                    break;
     725                case 'boolean':
     726                    if ($arg !== false && $arg !== true) {
     727                        $ok = false;
     728                    }
     729                    break;
     730                case 'float':
     731                case 'double':
     732                    if (!is_float($arg)) {
     733                        $ok = false;
     734                    }
     735                    break;
     736                case 'date':
     737                case 'dateTime.iso8601':
     738                    if (!is_a($arg, 'IXR_Date')) {
     739                        $ok = false;
     740                    }
     741                    break;
     742            }
     743            if (!$ok) {
     744                return new IXR_Error(-32602, 'server error. invalid method parameters');
     745            }
     746        }
     747        // It passed the test - run the "real" method call
     748        return parent::call($methodname, $argsbackup);
     749    }
     750    function methodSignature($method) {
     751        if (!$this->hasMethod($method)) {
     752            return new IXR_Error(-32601, 'server error. requested method "'.$method.'" not specified.');
     753        }
     754        // We should be returning an array of types
     755        $types = $this->signatures[$method];
     756        $return = array();
     757        foreach ($types as $type) {
     758            switch ($type) {
     759                case 'string':
     760                    $return[] = 'string';
     761                    break;
     762                case 'int':
     763                case 'i4':
     764                    $return[] = 42;
     765                    break;
     766                case 'double':
     767                    $return[] = 3.1415;
     768                    break;
     769                case 'dateTime.iso8601':
     770                    $return[] = new IXR_Date(time());
     771                    break;
     772                case 'boolean':
     773                    $return[] = true;
     774                    break;
     775                case 'base64':
     776                    $return[] = new IXR_Base64('base64');
     777                    break;
     778                case 'array':
     779                    $return[] = array('array');
     780                    break;
     781                case 'struct':
     782                    $return[] = array('struct' => 'struct');
     783                    break;
     784            }
     785        }
     786        return $return;
     787    }
     788    function methodHelp($method) {
     789        return $this->help[$method];
     790    }
     791}
     792
     793
     794class IXR_ClientMulticall extends IXR_Client {
     795    var $calls = array();
     796    function IXR_ClientMulticall($server, $path = false, $port = 80) {
     797        parent::IXR_Client($server, $path, $port);
     798        $this->useragent = 'The Incutio XML-RPC PHP Library (multicall client)';
     799    }
     800    function addCall() {
     801        $args = func_get_args();
     802        $methodName = array_shift($args);
     803        $struct = array(
     804            'methodName' => $methodName,
     805            'params' => $args
     806        );
     807        $this->calls[] = $struct;
     808    }
     809    function query() {
     810        // Prepare multicall, then call the parent::query() method
     811        return parent::query('system.multicall', $this->calls);
     812    }
     813}
     814 No newline at end of file
  • wp-includes/class/AtomServer.php

     
     1<?php
     2/*
     3 * wp-app.php - Atom Publishing Protocol support for WordPress
     4 * Original code by: Elias Torres, http://torrez.us/archives/2006/08/31/491/
     5 * Modified by: Dougal Campbell, http://dougal.gunters.org/
     6 *
     7 * Version: 1.0.5-dc
     8 */
     9
     10class AtomServer {
     11
     12        var $ATOM_CONTENT_TYPE = 'application/atom+xml';
     13        var $CATEGORIES_CONTENT_TYPE = 'application/atomcat+xml';
     14        var $SERVICE_CONTENT_TYPE = 'application/atomsvc+xml';
     15
     16        var $ATOM_NS = 'http://www.w3.org/2005/Atom';
     17        var $ATOMPUB_NS = 'http://www.w3.org/2007/app';
     18
     19        var $ENTRIES_PATH = "posts";
     20        var $CATEGORIES_PATH = "categories";
     21        var $MEDIA_PATH = "attachments";
     22        var $ENTRY_PATH = "post";
     23        var $SERVICE_PATH = "service";
     24        var $MEDIA_SINGLE_PATH = "attachment";
     25
     26        var $params = array();
     27        var $script_name = "wp-app.php";
     28        var $media_content_types = array('image/*','audio/*','video/*');
     29        var $atom_content_types = array('application/atom+xml');
     30
     31        var $selectors = array();
     32
     33        // support for head
     34        var $do_output = true;
     35
     36        function AtomServer() {
     37
     38                $this->script_name = array_pop(explode('/',$_SERVER['SCRIPT_NAME']));
     39
     40                $this->selectors = array(
     41                        '@/service$@' =>
     42                                array('GET' => 'get_service'),
     43                        '@/categories$@' =>
     44                                array('GET' => 'get_categories_xml'),
     45                        '@/post/(\d+)$@' =>
     46                                array('GET' => 'get_post',
     47                                                'PUT' => 'put_post',
     48                                                'DELETE' => 'delete_post'),
     49                        '@/posts/?(\d+)?$@' =>
     50                                array('GET' => 'get_posts',
     51                                                'POST' => 'create_post'),
     52                        '@/attachments/?(\d+)?$@' =>
     53                                array('GET' => 'get_attachment',
     54                                                'POST' => 'create_attachment'),
     55                        '@/attachment/file/(\d+)$@' =>
     56                                array('GET' => 'get_file',
     57                                                'PUT' => 'put_file',
     58                                                'DELETE' => 'delete_file'),
     59                        '@/attachment/(\d+)$@' =>
     60                                array('GET' => 'get_attachment',
     61                                                'PUT' => 'put_attachment',
     62                                                'DELETE' => 'delete_attachment'),
     63                );
     64        }
     65
     66        function handle_request() {
     67                global $always_authenticate;
     68
     69                $path = $_SERVER['PATH_INFO'];
     70                $method = $_SERVER['REQUEST_METHOD'];
     71
     72                log_app('REQUEST',"$method $path\n================");
     73
     74                $this->process_conditionals();
     75                //$this->process_conditionals();
     76
     77                // exception case for HEAD (treat exactly as GET, but don't output)
     78                if($method == 'HEAD') {
     79                        $this->do_output = false;
     80                        $method = 'GET';
     81                }
     82
     83                // redirect to /service in case no path is found.
     84                if(strlen($path) == 0 || $path == '/') {
     85                        $this->redirect($this->get_service_url());
     86                }
     87       
     88                // dispatch
     89                foreach($this->selectors as $regex => $funcs) {
     90                        if(preg_match($regex, $path, $matches)) {
     91                        if(isset($funcs[$method])) {
     92
     93                                // authenticate regardless of the operation and set the current
     94                                // user. each handler will decide if auth is required or not.
     95                                $this->authenticate();               
     96                                $u = wp_get_current_user();
     97                                if(!isset($u) || $u->ID == 0) {
     98                                        if ($always_authenticate) {
     99                                                $this->auth_required('Credentials required.');
     100                                        }
     101                                }
     102
     103                                array_shift($matches);
     104                                call_user_func_array(array(&$this,$funcs[$method]), $matches);
     105                                exit();
     106                        } else {
     107                                // only allow what we have handlers for...
     108                                $this->not_allowed(array_keys($funcs));
     109                        }
     110                        }
     111                }
     112
     113                // oops, nothing found
     114                $this->not_found();
     115        }
     116
     117        function get_service() {
     118                log_app('function','get_service()');
     119                $entries_url = attribute_escape($this->get_entries_url());
     120                $categories_url = attribute_escape($this->get_categories_url());
     121                $media_url = attribute_escape($this->get_attachments_url());
     122                foreach ($this->media_content_types as $med) {
     123                  $accepted_media_types = $accepted_media_types . "<accept>" . $med . "</accept>";
     124                }
     125                $atom_prefix="atom";
     126                $service_doc = <<<EOD
     127<service xmlns="$this->ATOMPUB_NS" xmlns:$atom_prefix="$this->ATOM_NS">
     128  <workspace>
     129    <$atom_prefix:title>WordPress Workspace</$atom_prefix:title>
     130    <collection href="$entries_url">
     131      <$atom_prefix:title>WordPress Posts</$atom_prefix:title>
     132      <accept>$this->ATOM_CONTENT_TYPE;type=entry</accept>
     133      <categories href="$categories_url" />
     134    </collection>
     135    <collection href="$media_url">
     136      <$atom_prefix:title>WordPress Media</$atom_prefix:title>
     137      $accepted_media_types
     138    </collection>
     139  </workspace>
     140</service>
     141
     142EOD;
     143
     144                $this->output($service_doc, $this->SERVICE_CONTENT_TYPE);
     145        }
     146
     147        function get_categories_xml() {
     148
     149                log_app('function','get_categories_xml()');
     150                $home = attribute_escape(get_bloginfo_rss('home'));
     151
     152                $categories = "";
     153                $cats = get_categories("hierarchical=0&hide_empty=0");
     154                foreach ((array) $cats as $cat) {
     155                        $categories .= "    <category term=\"" . attribute_escape($cat->cat_name) .  "\" />\n";
     156}
     157                $output = <<<EOD
     158<app:categories xmlns:app="$this->ATOMPUB_NS"
     159        xmlns="$this->ATOM_NS"
     160        fixed="yes" scheme="$home">
     161        $categories
     162</app:categories>
     163EOD;
     164        $this->output($output, $this->CATEGORIES_CONTENT_TYPE);
     165}
     166
     167        /*
     168         * Create Post (No arguments)
     169         */
     170        function create_post() {
     171                global $blog_id, $wpdb;
     172                $this->get_accepted_content_type($this->atom_content_types);
     173
     174                $parser = new AtomParser();
     175                if(!$parser->parse()) {
     176                        $this->client_error();
     177                }
     178
     179                $entry = array_pop($parser->feed->entries);
     180               
     181                log_app('Received entry:', print_r($entry,true));
     182               
     183                $catnames = array();
     184                foreach($entry->categories as $cat)
     185                        array_push($catnames, $cat["term"]);
     186               
     187                $wp_cats = get_categories(array('hide_empty' => false));
     188               
     189                $post_category = array();
     190               
     191                foreach($wp_cats as $cat) {
     192                        if(in_array($cat->cat_name, $catnames))
     193                                array_push($post_category, $cat->cat_ID);
     194                }
     195
     196                $publish = (isset($entry->draft) && trim($entry->draft) == 'yes') ? false : true;
     197
     198                $cap = ($publish) ? 'publish_posts' : 'edit_posts';
     199
     200                if(!current_user_can($cap))
     201                        $this->auth_required(__('Sorry, you do not have the right to edit/publish new posts.'));
     202
     203                $blog_ID = (int ) $blog_id;
     204                $post_status = ($publish) ? 'publish' : 'draft';
     205                $post_author = (int) $user->ID;
     206                $post_title = $entry->title[1];
     207                $post_content = $entry->content[1];
     208                $post_excerpt = $entry->summary[1];
     209                $pubtimes = $this->get_publish_time($entry);
     210                $post_date = $pubtimes[0];
     211                $post_date_gmt = $pubtimes[1];
     212               
     213                if ( isset( $_SERVER['HTTP_SLUG'] ) )
     214                        $post_name = $_SERVER['HTTP_SLUG'];
     215
     216                $post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'post_name');
     217
     218                $this->escape($post_data);
     219                log_app('Inserting Post. Data:', print_r($post_data,true));
     220
     221                $postID = wp_insert_post($post_data);
     222
     223                if (!$postID) {
     224                        $this->internal_error(__('Sorry, your entry could not be posted. Something wrong happened.'));
     225                }
     226
     227                // getting warning here about unable to set headers
     228                // because something in the cache is printing to the buffer
     229                // could we clean up wp_set_post_categories or cache to not print
     230                // this could affect our ability to send back the right headers
     231                @wp_set_post_categories($postID, $post_category);
     232
     233                $output = $this->get_entry($postID);
     234
     235                log_app('function',"create_post($postID)");
     236                $this->created($postID, $output);
     237        }
     238
     239        function get_post($postID) {
     240
     241                global $entry;
     242                $this->set_current_entry($postID);
     243                $output = $this->get_entry($postID);
     244                log_app('function',"get_post($postID)");
     245                $this->output($output);
     246
     247        }
     248
     249        function put_post($postID) {
     250                global $wpdb;
     251
     252                // checked for valid content-types (atom+xml)
     253                // quick check and exit
     254                $this->get_accepted_content_type($this->atom_content_types);
     255
     256                $parser = new AtomParser();
     257                if(!$parser->parse()) {
     258                        $this->bad_request();
     259                }
     260
     261                $parsed = array_pop($parser->feed->entries);
     262
     263                log_app('Received UPDATED entry:', print_r($parsed,true));
     264
     265                // check for not found
     266                global $entry;
     267                $entry = $GLOBALS['entry'];
     268                $this->set_current_entry($postID);
     269
     270                if(!current_user_can('edit_post', $entry['ID']))
     271                        $this->auth_required(__('Sorry, you do not have the right to edit this post.'));
     272
     273                $publish = (isset($parsed->draft) && trim($parsed->draft) == 'yes') ? false : true;
     274
     275                extract($entry);
     276
     277                $post_title = $parsed->title[1];
     278                $post_content = $parsed->content[1];
     279                $post_excerpt = $parsed->summary[1];
     280                $pubtimes = $this->get_publish_time($entry);
     281                $post_date = $pubtimes[0];
     282                $post_date_gmt = $pubtimes[1];     
     283
     284                // let's not go backwards and make something draft again.
     285                if(!$publish && $post_status == 'draft') {
     286                        $post_status = ($publish) ? 'publish' : 'draft';
     287                } elseif($publish) {
     288                        $post_status = 'publish';
     289                }
     290
     291                $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'post_date', 'post_date_gmt');
     292                $this->escape($postdata);
     293
     294                $result = wp_update_post($postdata);
     295
     296                if (!$result) {
     297                        $this->internal_error(__('For some strange yet very annoying reason, this post could not be edited.'));
     298                }
     299
     300                log_app('function',"put_post($postID)");
     301                $this->ok();
     302        }
     303
     304        function delete_post($postID) {
     305
     306                // check for not found
     307                global $entry;
     308                $this->set_current_entry($postID);
     309
     310                if(!current_user_can('edit_post', $postID)) {
     311                        $this->auth_required(__('Sorry, you do not have the right to delete this post.'));
     312                }
     313
     314                if ($entry['post_type'] == 'attachment') {
     315                        $this->delete_attachment($postID);
     316                } else {
     317                        $result = wp_delete_post($postID);
     318
     319                        if (!$result) {
     320                                $this->internal_error(__('For some strange yet very annoying reason, this post could not be deleted.'));
     321                        }
     322
     323                        log_app('function',"delete_post($postID)");
     324                        $this->ok();
     325                }
     326
     327        }
     328
     329        function get_attachment($postID = NULL) {
     330
     331                global $entry;
     332                if (!isset($postID)) {
     333                        $this->get_attachments();
     334                } else {
     335                        $this->set_current_entry($postID);
     336                        $output = $this->get_entry($postID, 'attachment');
     337                        log_app('function',"get_attachment($postID)");
     338                        $this->output($output);
     339                }
     340        }
     341
     342        function create_attachment() {
     343                global $wp, $wpdb, $wp_query, $blog_id;
     344
     345                $type = $this->get_accepted_content_type();
     346
     347                if(!current_user_can('upload_files'))
     348                        $this->auth_required(__('You do not have permission to upload files.'));
     349
     350                $fp = fopen("php://input", "rb");
     351                $bits = NULL;
     352                while(!feof($fp)) {
     353                        $bits .= fread($fp, 4096);
     354                }
     355                fclose($fp);
     356
     357                $slug = '';
     358                if ( isset( $_SERVER['HTTP_SLUG'] ) )
     359                        $slug = sanitize_file_name( $_SERVER['HTTP_SLUG'] );
     360                elseif ( isset( $_SERVER['HTTP_TITLE'] ) )
     361                        $slug = sanitize_file_name( $_SERVER['HTTP_TITLE'] );
     362                elseif ( empty( $slug ) ) // just make a random name
     363                        $slug = substr( md5( uniqid( microtime() ) ), 0, 7);
     364                $ext = preg_replace( '|.*/([a-z]+)|', '$1', $_SERVER['CONTENT_TYPE'] );
     365                $slug = "$slug.$ext";
     366                $file = wp_upload_bits( $slug, NULL, $bits);
     367
     368                log_app('wp_upload_bits returns:',print_r($file,true));
     369
     370                $url = $file['url'];
     371                $file = $file['file'];
     372                $filename = basename($file);
     373
     374                $header = apply_filters('wp_create_file_in_uploads', $file); // replicate
     375
     376                // Construct the attachment array
     377                $attachment = array(
     378                        'post_title' => $slug,
     379                        'post_content' => $slug,
     380                        'post_status' => 'attachment',
     381                        'post_parent' => 0,
     382                        'post_mime_type' => $type,
     383                        'guid' => $url
     384                        );
     385
     386                // Save the data
     387                $postID = wp_insert_attachment($attachment, $file, $post);
     388
     389                if (!$postID) {
     390                        $this->internal_error(__('Sorry, your entry could not be posted. Something wrong happened.'));
     391                }
     392
     393                $output = $this->get_entry($postID, 'attachment');
     394
     395                $this->created($postID, $output, 'attachment');
     396                log_app('function',"create_attachment($postID)");
     397        }
     398
     399        function put_attachment($postID) {
     400                global $wpdb;
     401
     402                // checked for valid content-types (atom+xml)
     403                // quick check and exit
     404                $this->get_accepted_content_type($this->atom_content_types);
     405
     406                $parser = new AtomParser();
     407                if(!$parser->parse()) {
     408                        $this->bad_request();
     409                }
     410
     411                $parsed = array_pop($parser->feed->entries);
     412
     413                // check for not found
     414                global $entry;
     415                $this->set_current_entry($postID);
     416
     417                if(!current_user_can('edit_post', $entry['ID']))
     418                        $this->auth_required(__('Sorry, you do not have the right to edit this post.'));
     419
     420                $publish = (isset($parsed->draft) && trim($parsed->draft) == 'yes') ? false : true;
     421
     422                extract($entry);
     423
     424                $post_title = $parsed->title[1];
     425                $post_content = $parsed->content[1];
     426
     427                $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt');
     428                $this->escape($postdata);
     429
     430                $result = wp_update_post($postdata);
     431
     432                if (!$result) {
     433                        $this->internal_error(__('For some strange yet very annoying reason, this post could not be edited.'));
     434                }
     435
     436                log_app('function',"put_attachment($postID)");
     437                $this->ok();
     438        }
     439
     440        function delete_attachment($postID) {
     441                log_app('function',"delete_attachment($postID). File '$location' deleted.");
     442
     443                // check for not found
     444                global $entry;
     445                $this->set_current_entry($postID);
     446
     447                if(!current_user_can('edit_post', $postID)) {
     448                        $this->auth_required(__('Sorry, you do not have the right to delete this post.'));
     449                }
     450
     451                $location = get_post_meta($entry['ID'], '_wp_attached_file', true);
     452
     453                // delete file
     454                @unlink($location);
     455
     456                // delete attachment
     457                $result = wp_delete_post($postID);
     458
     459                if (!$result) {
     460                        $this->internal_error(__('For some strange yet very annoying reason, this post could not be deleted.'));
     461                }
     462
     463                log_app('function',"delete_attachment($postID). File '$location' deleted.");
     464                $this->ok();
     465        }
     466
     467        function get_file($postID) {
     468
     469                // check for not found
     470                global $entry;
     471                $this->set_current_entry($postID);
     472
     473                // then whether user can edit the specific post
     474                if(!current_user_can('edit_post', $postID)) {
     475                        $this->auth_required(__('Sorry, you do not have the right to edit this post.'));
     476                }
     477
     478                $location = get_post_meta($entry['ID'], '_wp_attached_file', true);
     479                $filetype = wp_check_filetype($location);
     480
     481                if(!isset($location) || 'attachment' != $entry['post_type'] || empty($filetype['ext']))
     482                        $this->internal_error(__('Error ocurred while accessing post metadata for file location.'));
     483
     484                status_header('200');
     485                header('Content-Type: ' . $entry['post_mime_type']);
     486                header('Connection: close');
     487
     488                $fp = fopen($location, "rb");
     489                while(!feof($fp)) {
     490                        echo fread($fp, 4096);
     491                }
     492                fclose($fp);
     493
     494                log_app('function',"get_file($postID)");
     495                exit;
     496        }
     497
     498        function put_file($postID) {
     499
     500                $type = $this->get_accepted_content_type();
     501
     502                // first check if user can upload
     503                if(!current_user_can('upload_files'))
     504                        $this->auth_required(__('You do not have permission to upload files.'));
     505
     506                // check for not found
     507                global $entry;
     508                $this->set_current_entry($postID);
     509
     510                // then whether user can edit the specific post
     511                if(!current_user_can('edit_post', $postID)) {
     512                        $this->auth_required(__('Sorry, you do not have the right to edit this post.'));
     513                }
     514
     515                $location = get_post_meta($entry['ID'], '_wp_attached_file', true);
     516                $filetype = wp_check_filetype($location);
     517
     518                if(!isset($location) || 'attachment' != $entry['post_type'] || empty($filetype['ext']))
     519                        $this->internal_error(__('Error ocurred while accessing post metadata for file location.'));
     520
     521                $fp = fopen("php://input", "rb");
     522                $localfp = fopen($location, "w+");
     523                while(!feof($fp)) {
     524                        fwrite($localfp,fread($fp, 4096));
     525                }
     526                fclose($fp);
     527                fclose($localfp);
     528
     529                $ID = $entry['ID'];
     530                $pubtimes = $this->get_publish_time($entry);
     531                $post_date = $pubtimes[0];
     532                $post_date_gmt = $pubtimes[1];
     533
     534                $post_data = compact('ID', 'post_date', 'post_date_gmt');
     535                $result = wp_update_post($post_data);
     536
     537                if (!$result) {
     538                        $this->internal_error(__('Sorry, your entry could not be posted. Something wrong happened.'));
     539                }
     540
     541                log_app('function',"put_file($postID)");
     542                $this->ok();
     543        }
     544
     545        function get_entries_url($page = NULL) {
     546                if($GLOBALS['post_type'] == 'attachment') {
     547                        $path = $this->MEDIA_PATH;
     548                } else {
     549                        $path = $this->ENTRIES_PATH;
     550                }
     551                $url = get_bloginfo('url') . '/' . $this->script_name . '/' . $path;
     552                if(isset($page) && is_int($page)) {
     553                        $url .= "/$page";
     554                }
     555                return $url;
     556        }
     557
     558        function the_entries_url($page = NULL) {
     559                $url = $this->get_entries_url($page);
     560                echo $url;
     561        }
     562
     563        function get_categories_url($page = NULL) {
     564                return get_bloginfo('url') . '/' . $this->script_name . '/' . $this->CATEGORIES_PATH;
     565        }
     566
     567        function the_categories_url() {
     568                $url = $this->get_categories_url();
     569                echo $url;
     570        }
     571
     572        function get_attachments_url($page = NULL) {
     573                $url = get_bloginfo('url') . '/' . $this->script_name . '/' . $this->MEDIA_PATH;
     574                if(isset($page) && is_int($page)) {
     575                        $url .= "/$page";
     576                }
     577                return $url;
     578        }
     579
     580        function the_attachments_url($page = NULL) {
     581                $url = $this->get_attachments_url($page);
     582                echo $url;
     583        }
     584
     585        function get_service_url() {
     586                return get_bloginfo('url') . '/' . $this->script_name . '/' . $this->SERVICE_PATH;
     587        }
     588
     589        function get_entry_url($postID = NULL) {
     590                if(!isset($postID)) {
     591                        global $post;
     592                        $postID = (int) $GLOBALS['post']->ID;
     593                }
     594
     595                $url = get_bloginfo('url') . '/' . $this->script_name . '/' . $this->ENTRY_PATH . "/$postID";
     596
     597                log_app('function',"get_entry_url() = $url");
     598                return $url;
     599        }
     600
     601        function the_entry_url($postID = NULL) {
     602                $url = $this->get_entry_url($postID);
     603                echo $url;
     604        }
     605
     606        function get_media_url($postID = NULL) {
     607                if(!isset($postID)) {
     608                        global $post;
     609                        $postID = (int) $GLOBALS['post']->ID;
     610                }
     611
     612                $url = get_bloginfo('url') . '/' . $this->script_name . '/' . $this->MEDIA_SINGLE_PATH ."/file/$postID";
     613
     614                log_app('function',"get_media_url() = $url");
     615                return $url;
     616        }
     617
     618        function the_media_url($postID = NULL) {
     619                $url = $this->get_media_url($postID);
     620                echo $url;
     621        }
     622
     623        function set_current_entry($postID) {
     624                global $entry;
     625                log_app('function',"set_current_entry($postID)");
     626
     627                if(!isset($postID)) {
     628                        // $this->bad_request();
     629                        $this->not_found();
     630                }
     631
     632                $entry = wp_get_single_post($postID,ARRAY_A);
     633
     634                if(!isset($entry) || !isset($entry['ID']))
     635                        $this->not_found();
     636
     637                return;
     638        }
     639
     640        function get_posts($page = 1, $post_type = 'post') {
     641                        log_app('function',"get_posts($page, '$post_type')");
     642                        $feed = $this->get_feed($page, $post_type);
     643                        $this->output($feed);
     644        }
     645
     646        function get_attachments($page = 1, $post_type = 'attachment') {
     647            log_app('function',"get_attachments($page, '$post_type')");
     648            $GLOBALS['post_type'] = $post_type;
     649            $feed = $this->get_feed($page, $post_type);
     650            $this->output($feed);
     651        }
     652
     653        function get_feed($page = 1, $post_type = 'post') {
     654                global $post, $wp, $wp_query, $posts, $wpdb, $blog_id, $post_cache;
     655                log_app('function',"get_feed($page, '$post_type')");
     656                ob_start();
     657
     658                if(!isset($page)) {
     659                        $page = 1;
     660                }
     661                $page = (int) $page;
     662
     663                $count = get_option('posts_per_rss');
     664
     665                wp('what_to_show=posts&posts_per_page=' . $count . '&offset=' . ($count * ($page-1) ));
     666
     667                $post = $GLOBALS['post'];
     668                $posts = $GLOBALS['posts'];
     669                $wp = $GLOBALS['wp'];
     670                $wp_query = $GLOBALS['wp_query'];
     671                $wpdb = $GLOBALS['wpdb'];
     672                $blog_id = (int) $GLOBALS['blog_id'];
     673                $post_cache = $GLOBALS['post_cache'];
     674                log_app('function',"query_posts(# " . print_r($wp_query, true) . "#)");
     675
     676                log_app('function',"total_count(# $wp_query->max_num_pages #)");
     677                $last_page = $wp_query->max_num_pages;
     678                $next_page = (($page + 1) > $last_page) ? NULL : $page + 1;
     679                $prev_page = ($page - 1) < 1 ? NULL : $page - 1;
     680                $last_page = ((int)$last_page == 1 || (int)$last_page == 0) ? NULL : (int) $last_page;
     681                $self_page = $page > 1 ? $page : NULL;
     682?><feed xmlns="<?php echo $this->ATOM_NS ?>" xmlns:app="<?php echo $this->ATOMPUB_NS ?>" xml:lang="<?php echo get_option('rss_language'); ?>">
     683<id><?php $this->the_entries_url() ?></id>
     684<updated><?php echo mysql2date('Y-m-d\TH:i:s\Z', get_lastpostmodified('GMT')); ?></updated>
     685<title type="text"><?php bloginfo_rss('name') ?></title>
     686<subtitle type="text"><?php bloginfo_rss("description") ?></subtitle>
     687<link rel="first" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url() ?>" />
     688<?php if(isset($prev_page)): ?>
     689<link rel="previous" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url($prev_page) ?>" />
     690<?php endif; ?>
     691<?php if(isset($next_page)): ?>
     692<link rel="next" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url($next_page) ?>" />
     693<?php endif; ?>
     694<link rel="last" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url($last_page) ?>" />
     695<link rel="self" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url($self_page) ?>" />
     696<rights type="text">Copyright <?php echo mysql2date('Y', get_lastpostdate('blog')); ?></rights>
     697<generator uri="http://wordpress.com/" version="1.0.5-dc">WordPress.com Atom API</generator>
     698<?php if ( have_posts() ) {
     699                        while ( have_posts() ) {
     700                                the_post();
     701                                $this->echo_entry();
     702                        }
     703                }
     704?></feed>
     705<?php
     706                $feed = ob_get_contents();
     707                ob_end_clean();
     708                return $feed;
     709        }
     710
     711        function get_entry($postID, $post_type = 'post') {
     712                log_app('function',"get_entry($postID, '$post_type')");
     713                ob_start();
     714                global $posts, $post, $wp_query, $wp, $wpdb, $blog_id, $post_cache;
     715                switch($post_type) {
     716                        case 'post':
     717                                $varname = 'p';
     718                                break;
     719                        case 'attachment':
     720                                $varname = 'attachment_id';
     721                                break;
     722                }
     723                query_posts($varname . '=' . $postID);
     724                if ( have_posts() ) {
     725                        while ( have_posts() ) {
     726                                the_post();
     727                                $this->echo_entry();
     728                                log_app('$post',print_r($GLOBALS['post'],true));
     729                                $entry = ob_get_contents();
     730                                break;
     731                        }
     732                }
     733                ob_end_clean();
     734
     735                log_app('get_entry returning:',$entry);
     736                return $entry;
     737        }
     738
     739        function echo_entry() { ?>
     740<entry xmlns="<?php echo $this->ATOM_NS ?>"
     741       xmlns:app="<?php echo $this->ATOMPUB_NS ?>" xml:lang="<?php echo get_option('rss_language'); ?>">
     742        <id><?php the_guid($GLOBALS['post']->ID); ?></id>
     743<?php list($content_type, $content) = $this->prep_content(get_the_title()); ?>
     744        <title type="<?php echo $content_type ?>"><?php echo $content ?></title>
     745        <updated><?php echo get_post_modified_time('Y-m-d\TH:i:s\Z', true); ?></updated>
     746        <published><?php echo get_post_time('Y-m-d\TH:i:s\Z', true); ?></published>
     747        <app:edited><?php echo get_post_modified_time('Y-m-d\TH:i:s\Z', true); ?></app:edited>
     748        <app:control>
     749                <app:draft><?php echo ($GLOBALS['post']->post_status == 'draft' ? 'yes' : 'no') ?></app:draft>
     750        </app:control>
     751        <author>
     752                <name><?php the_author()?></name>
     753                <email><?php the_author_email()?></email>
     754<?php if (get_the_author_url() && get_the_author_url() != 'http://') { ?>
     755                <uri><?php the_author_url()?></uri>
     756<?php } ?>
     757        </author>
     758<?php if($GLOBALS['post']->post_type == 'attachment') { ?>
     759        <link rel="edit-media" href="<?php $this->the_media_url() ?>" />
     760        <content type="<?php echo $GLOBALS['post']->post_mime_type ?>" src="<?php the_guid(); ?>"/>
     761<?php } else { ?>
     762        <link href="<?php the_permalink_rss() ?>" />
     763<?php if ( strlen( $GLOBALS['post']->post_content ) ) :
     764list($content_type, $content) = $this->prep_content(get_the_content()); ?>
     765        <content type="<?php echo $content_type ?>"><?php echo $content ?></content>
     766<?php endif; ?>
     767<?php } ?>
     768        <link rel="edit" href="<?php $this->the_entry_url() ?>" />
     769<?php foreach(get_the_category() as $category) { ?>
     770        <category scheme="<?php bloginfo_rss('home') ?>" term="<?php echo $category->cat_name?>" />
     771<?php } ?>
     772<?php list($content_type, $content) = $this->prep_content(get_the_excerpt()); ?>
     773        <summary type="<?php echo $content_type ?>"><?php echo $content ?></summary>
     774</entry>
     775<?php }
     776
     777        function prep_content($data) {
     778                if (strpos($data, '<') === false && strpos($data, '&') === false) {
     779                        return array('text', $data);
     780                }
     781
     782                $parser = xml_parser_create();
     783                xml_parse($parser, '<div>' . $data . '</div>', true);
     784                $code = xml_get_error_code($parser);
     785                xml_parser_free($parser);
     786
     787                if (!$code) {
     788                        if (strpos($data, '<') === false) {
     789                                return array('text', $data);
     790                        } else {
     791                                $data = "<div xmlns='http://www.w3.org/1999/xhtml'>$data</div>";
     792                                return array('xhtml', $data);
     793                        }
     794                }
     795
     796                if (strpos($data, ']]>') == false) {
     797                        return array('html', "<![CDATA[$data]]>");
     798                } else {
     799                        return array('html', htmlspecialchars($data));
     800                }
     801        }
     802
     803        function ok() {
     804                log_app('Status','200: OK');
     805                header('Content-Type: text/plain');
     806                status_header('200');
     807                exit;
     808        }
     809
     810        function no_content() {
     811                log_app('Status','204: No Content');
     812                header('Content-Type: text/plain');
     813                status_header('204');
     814                echo "Deleted.";
     815                exit;
     816        }
     817
     818        function internal_error($msg = 'Internal Server Error') {
     819                log_app('Status','500: Server Error');
     820                header('Content-Type: text/plain');
     821                status_header('500');
     822                echo $msg;
     823                exit;
     824        }
     825
     826        function bad_request() {
     827                log_app('Status','400: Bad Request');
     828                header('Content-Type: text/plain');
     829                status_header('400');
     830                exit;
     831        }
     832
     833        function length_required() {
     834                log_app('Status','411: Length Required');
     835                header("HTTP/1.1 411 Length Required");
     836                header('Content-Type: text/plain');
     837                status_header('411');
     838                exit;
     839        }
     840
     841        function invalid_media() {
     842                log_app('Status','415: Unsupported Media Type');
     843                header("HTTP/1.1 415 Unsupported Media Type");
     844                header('Content-Type: text/plain');
     845                exit;
     846        }
     847
     848        function not_found() {
     849                log_app('Status','404: Not Found');
     850                header('Content-Type: text/plain');
     851                status_header('404');
     852                exit;
     853        }
     854
     855        function not_allowed($allow) {
     856                log_app('Status','405: Not Allowed');
     857                header('Allow: ' . join(',', $allow));
     858                status_header('405');
     859                exit;
     860        }
     861
     862        function redirect($url) {
     863
     864                log_app('Status','302: Redirect');
     865                $escaped_url = attribute_escape($url);
     866                $content = <<<EOD
     867<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
     868<html>
     869  <head>
     870    <title>302 Found</title>
     871  </head>
     872<body>
     873  <h1>Found</h1>
     874  <p>The document has moved <a href="$escaped_url">here</a>.</p>
     875  </body>
     876</html>
     877
     878EOD;
     879                header('HTTP/1.1 302 Moved');
     880                header('Content-Type: text/html');
     881                header('Location: ' . $url);
     882                echo $content;
     883                exit;
     884
     885        }
     886
     887
     888        function client_error($msg = 'Client Error') {
     889                log_app('Status','400: Client Error');
     890                header('Content-Type: text/plain');
     891                status_header('400');
     892                exit;
     893        }
     894
     895        function created($post_ID, $content, $post_type = 'post') {
     896                log_app('created()::$post_ID',"$post_ID, $post_type");
     897                $edit = $this->get_entry_url($post_ID);
     898                switch($post_type) {
     899                        case 'post':
     900                                $ctloc = $this->get_entry_url($post_ID);
     901                                break;
     902                        case 'attachment':
     903                                $edit = get_bloginfo('url') . '/' . $this->script_name . "/attachments/$post_ID";
     904                                break;
     905                }
     906                header("Content-Type: $this->ATOM_CONTENT_TYPE");
     907                if(isset($ctloc))
     908                        header('Content-Location: ' . $ctloc);
     909                header('Location: ' . $edit);
     910                status_header('201');
     911                echo $content;
     912                exit;
     913        }
     914
     915        function auth_required($msg) {
     916                log_app('Status','401: Auth Required');
     917                nocache_headers();
     918                header('WWW-Authenticate: Basic realm="WordPress Atom Protocol"');
     919                header("HTTP/1.1 401 $msg");
     920                header('Status: ' . $msg);
     921                header('Content-Type: text/html');
     922                $content = <<<EOD
     923<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
     924<html>
     925  <head>
     926    <title>401 Unauthorized</title>
     927  </head>
     928<body>
     929    <h1>401 Unauthorized</h1>
     930    <p>$msg</p>
     931  </body>
     932</html>
     933
     934EOD;
     935                echo $content;
     936                exit;
     937        }
     938
     939        function output($xml, $ctype = 'application/atom+xml') {
     940                        status_header('200');
     941                        $xml = '<?xml version="1.0" encoding="' . strtolower(get_option('blog_charset')) . '"?>'."\n".$xml;
     942                        header('Connection: close');
     943                        header('Content-Length: '. strlen($xml));
     944                        header('Content-Type: ' . $ctype);
     945                        header('Content-Disposition: attachment; filename=atom.xml');
     946                        header('Date: '. date('r'));
     947                        if($this->do_output)
     948                                echo $xml;
     949                        log_app('function', "output:\n$xml");
     950                        exit;
     951        }
     952
     953        function escape(&$array) {
     954                global $wpdb;
     955
     956                foreach ($array as $k => $v) {
     957                                if (is_array($v)) {
     958                                                $this->escape($array[$k]);
     959                                } else if (is_object($v)) {
     960                                                //skip
     961                                } else {
     962                                                $array[$k] = $wpdb->escape($v);
     963                                }
     964                }
     965        }
     966
     967        /*
     968         * Access credential through various methods and perform login
     969         */
     970        function authenticate() {
     971                $login_data = array();
     972                $already_md5 = false;
     973
     974                log_app("authenticate()",print_r($_ENV, true));
     975
     976                // if using mod_rewrite/ENV hack
     977                // http://www.besthostratings.com/articles/http-auth-php-cgi.html
     978                if(isset($_SERVER['HTTP_AUTHORIZATION'])) {
     979                        list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) =
     980                                explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
     981                }
     982
     983                // If Basic Auth is working...
     984                if(isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
     985                        $login_data = array('login' => $_SERVER['PHP_AUTH_USER'],       'password' => $_SERVER['PHP_AUTH_PW']);
     986                        log_app("Basic Auth",$login_data['login']);
     987                } else {
     988                        // else, do cookie-based authentication
     989                        if (function_exists('wp_get_cookie_login')) {
     990                                $login_data = wp_get_cookie_login();
     991                                $already_md5 = true;
     992                        }
     993                }
     994
     995                // call wp_login and set current user
     996                if (!empty($login_data) && wp_login($login_data['login'], $login_data['password'], $already_md5)) {
     997                         $current_user = new WP_User(0, $login_data['login']);
     998                         wp_set_current_user($current_user->ID);
     999                        log_app("authenticate()",$login_data['login']);
     1000                }
     1001        }
     1002
     1003        function get_accepted_content_type($types = NULL) {
     1004
     1005                if(!isset($types)) {
     1006                        $types = $this->media_content_types;
     1007                }
     1008
     1009                if(!isset($_SERVER['CONTENT_LENGTH']) || !isset($_SERVER['CONTENT_TYPE'])) {
     1010                        $this->length_required();
     1011                }
     1012
     1013                $type = $_SERVER['CONTENT_TYPE'];
     1014                list($type,$subtype) = explode('/',$type);
     1015                list($subtype) = explode(";",$subtype); // strip MIME parameters
     1016                log_app("get_accepted_content_type", "type=$type, subtype=$subtype");
     1017
     1018                foreach($types as $t) {
     1019                        list($acceptedType,$acceptedSubtype) = explode('/',$t);
     1020                        if($acceptedType == '*' || $acceptedType == $type) {
     1021                                if($acceptedSubtype == '*' || $acceptedSubtype == $subtype)
     1022                                        return $type . "/" . $subtype;
     1023                        }
     1024                }
     1025
     1026                $this->invalid_media();
     1027        }
     1028
     1029        function process_conditionals() {
     1030
     1031                if(empty($this->params)) return;
     1032                if($_SERVER['REQUEST_METHOD'] == 'DELETE') return;
     1033
     1034                switch($this->params[0]) {
     1035                        case $this->ENTRY_PATH:
     1036                                global $post;
     1037                                $post = wp_get_single_post($this->params[1]);
     1038                                $wp_last_modified = get_post_modified_time('D, d M Y H:i:s', true);
     1039                                $post = NULL;
     1040                                break;
     1041                        case $this->ENTRIES_PATH:
     1042                                $wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastpostmodified('GMT'), 0).' GMT';
     1043                                break;
     1044                        default:
     1045                                return;
     1046                }
     1047                $wp_etag = md5($wp_last_modified);
     1048                @header("Last-Modified: $wp_last_modified");
     1049                @header("ETag: $wp_etag");
     1050
     1051                // Support for Conditional GET
     1052                if (isset($_SERVER['HTTP_IF_NONE_MATCH']))
     1053                        $client_etag = stripslashes($_SERVER['HTTP_IF_NONE_MATCH']);
     1054                else
     1055                        $client_etag = false;
     1056
     1057                $client_last_modified = trim( $_SERVER['HTTP_IF_MODIFIED_SINCE']);
     1058                // If string is empty, return 0. If not, attempt to parse into a timestamp
     1059                $client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;
     1060
     1061                // Make a timestamp for our most recent modification...
     1062                $wp_modified_timestamp = strtotime($wp_last_modified);
     1063
     1064                if ( ($client_last_modified && $client_etag) ?
     1065                (($client_modified_timestamp >= $wp_modified_timestamp) && ($client_etag == $wp_etag)) :
     1066                (($client_modified_timestamp >= $wp_modified_timestamp) || ($client_etag == $wp_etag)) ) {
     1067                        status_header( 304 );
     1068                        exit;
     1069                }
     1070        }
     1071
     1072        function rfc3339_str2time($str) {
     1073           
     1074            $match = false;
     1075            if(!preg_match("/(\d{4}-\d{2}-\d{2})T(\d{2}\:\d{2}\:\d{2})\.?\d{0,3}(Z|[+-]+\d{2}\:\d{2})/", $str, $match))
     1076                        return false;
     1077       
     1078            if($match[3] == 'Z')
     1079                        $match[3] == '+0000';
     1080       
     1081            return strtotime($match[1] . " " . $match[2] . " " . $match[3]);
     1082        }       
     1083
     1084        function get_publish_time($entry) {
     1085
     1086            $pubtime = $this->rfc3339_str2time($entry->published);
     1087           
     1088            if(!$pubtime) {
     1089                        return array(current_time('mysql'),current_time('mysql',1));
     1090            } else {
     1091                        return array(date("Y-m-d H:i:s", $pubtime), gmdate("Y-m-d H:i:s", $pubtime));
     1092            }
     1093        }
     1094
     1095}
     1096 No newline at end of file
  • wp-includes/class/AtomServer.php

     
     1<?php
     2/*
     3 * wp-app.php - Atom Publishing Protocol support for WordPress
     4 * Original code by: Elias Torres, http://torrez.us/archives/2006/08/31/491/
     5 * Modified by: Dougal Campbell, http://dougal.gunters.org/
     6 *
     7 * Version: 1.0.5-dc
     8 */
     9
     10class AtomServer {
     11
     12        var $ATOM_CONTENT_TYPE = 'application/atom+xml';
     13        var $CATEGORIES_CONTENT_TYPE = 'application/atomcat+xml';
     14        var $SERVICE_CONTENT_TYPE = 'application/atomsvc+xml';
     15
     16        var $ATOM_NS = 'http://www.w3.org/2005/Atom';
     17        var $ATOMPUB_NS = 'http://www.w3.org/2007/app';
     18
     19        var $ENTRIES_PATH = "posts";
     20        var $CATEGORIES_PATH = "categories";
     21        var $MEDIA_PATH = "attachments";
     22        var $ENTRY_PATH = "post";
     23        var $SERVICE_PATH = "service";
     24        var $MEDIA_SINGLE_PATH = "attachment";
     25
     26        var $params = array();
     27        var $script_name = "wp-app.php";
     28        var $media_content_types = array('image/*','audio/*','video/*');
     29        var $atom_content_types = array('application/atom+xml');
     30
     31        var $selectors = array();
     32
     33        // support for head
     34        var $do_output = true;
     35
     36        function AtomServer() {
     37
     38                $this->script_name = array_pop(explode('/',$_SERVER['SCRIPT_NAME']));
     39
     40                $this->selectors = array(
     41                        '@/service$@' =>
     42                                array('GET' => 'get_service'),
     43                        '@/categories$@' =>
     44                                array('GET' => 'get_categories_xml'),
     45                        '@/post/(\d+)$@' =>
     46                                array('GET' => 'get_post',
     47                                                'PUT' => 'put_post',
     48                                                'DELETE' => 'delete_post'),
     49                        '@/posts/?(\d+)?$@' =>
     50                                array('GET' => 'get_posts',
     51                                                'POST' => 'create_post'),
     52                        '@/attachments/?(\d+)?$@' =>
     53                                array('GET' => 'get_attachment',
     54                                                'POST' => 'create_attachment'),
     55                        '@/attachment/file/(\d+)$@' =>
     56                                array('GET' => 'get_file',
     57                                                'PUT' => 'put_file',
     58                                                'DELETE' => 'delete_file'),
     59                        '@/attachment/(\d+)$@' =>
     60                                array('GET' => 'get_attachment',
     61                                                'PUT' => 'put_attachment',
     62                                                'DELETE' => 'delete_attachment'),
     63                );
     64        }
     65
     66        function handle_request() {
     67                global $always_authenticate;
     68
     69                $path = $_SERVER['PATH_INFO'];
     70                $method = $_SERVER['REQUEST_METHOD'];
     71
     72                log_app('REQUEST',"$method $path\n================");
     73
     74                $this->process_conditionals();
     75                //$this->process_conditionals();
     76
     77                // exception case for HEAD (treat exactly as GET, but don't output)
     78                if($method == 'HEAD') {
     79                        $this->do_output = false;
     80                        $method = 'GET';
     81                }
     82
     83                // redirect to /service in case no path is found.
     84                if(strlen($path) == 0 || $path == '/') {
     85                        $this->redirect($this->get_service_url());
     86                }
     87       
     88                // dispatch
     89                foreach($this->selectors as $regex => $funcs) {
     90                        if(preg_match($regex, $path, $matches)) {
     91                        if(isset($funcs[$method])) {
     92
     93                                // authenticate regardless of the operation and set the current
     94                                // user. each handler will decide if auth is required or not.
     95                                $this->authenticate();               
     96                                $u = wp_get_current_user();
     97                                if(!isset($u) || $u->ID == 0) {
     98                                        if ($always_authenticate) {
     99                                                $this->auth_required('Credentials required.');
     100                                        }
     101                                }
     102
     103                                array_shift($matches);
     104                                call_user_func_array(array(&$this,$funcs[$method]), $matches);
     105                                exit();
     106                        } else {
     107                                // only allow what we have handlers for...
     108                                $this->not_allowed(array_keys($funcs));
     109                        }
     110                        }
     111                }
     112
     113                // oops, nothing found
     114                $this->not_found();
     115        }
     116
     117        function get_service() {
     118                log_app('function','get_service()');
     119                $entries_url = attribute_escape($this->get_entries_url());
     120                $categories_url = attribute_escape($this->get_categories_url());
     121                $media_url = attribute_escape($this->get_attachments_url());
     122                foreach ($this->media_content_types as $med) {
     123                  $accepted_media_types = $accepted_media_types . "<accept>" . $med . "</accept>";
     124                }
     125                $atom_prefix="atom";
     126                $service_doc = <<<EOD
     127<service xmlns="$this->ATOMPUB_NS" xmlns:$atom_prefix="$this->ATOM_NS">
     128  <workspace>
     129    <$atom_prefix:title>WordPress Workspace</$atom_prefix:title>
     130    <collection href="$entries_url">
     131      <$atom_prefix:title>WordPress Posts</$atom_prefix:title>
     132      <accept>$this->ATOM_CONTENT_TYPE;type=entry</accept>
     133      <categories href="$categories_url" />
     134    </collection>
     135    <collection href="$media_url">
     136      <$atom_prefix:title>WordPress Media</$atom_prefix:title>
     137      $accepted_media_types
     138    </collection>
     139  </workspace>
     140</service>
     141
     142EOD;
     143
     144                $this->output($service_doc, $this->SERVICE_CONTENT_TYPE);
     145        }
     146
     147        function get_categories_xml() {
     148
     149                log_app('function','get_categories_xml()');
     150                $home = attribute_escape(get_bloginfo_rss('home'));
     151
     152                $categories = "";
     153                $cats = get_categories("hierarchical=0&hide_empty=0");
     154                foreach ((array) $cats as $cat) {
     155                        $categories .= "    <category term=\"" . attribute_escape($cat->cat_name) .  "\" />\n";
     156}
     157                $output = <<<EOD
     158<app:categories xmlns:app="$this->ATOMPUB_NS"
     159        xmlns="$this->ATOM_NS"
     160        fixed="yes" scheme="$home">
     161        $categories
     162</app:categories>
     163EOD;
     164        $this->output($output, $this->CATEGORIES_CONTENT_TYPE);
     165}
     166
     167        /*
     168         * Create Post (No arguments)
     169         */
     170        function create_post() {
     171                global $blog_id, $wpdb;
     172                $this->get_accepted_content_type($this->atom_content_types);
     173
     174                $parser = new AtomParser();
     175                if(!$parser->parse()) {
     176                        $this->client_error();
     177                }
     178
     179                $entry = array_pop($parser->feed->entries);
     180               
     181                log_app('Received entry:', print_r($entry,true));
     182               
     183                $catnames = array();
     184                foreach($entry->categories as $cat)
     185                        array_push($catnames, $cat["term"]);
     186               
     187                $wp_cats = get_categories(array('hide_empty' => false));
     188               
     189                $post_category = array();
     190               
     191                foreach($wp_cats as $cat) {
     192                        if(in_array($cat->cat_name, $catnames))
     193                                array_push($post_category, $cat->cat_ID);
     194                }
     195
     196                $publish = (isset($entry->draft) && trim($entry->draft) == 'yes') ? false : true;
     197
     198                $cap = ($publish) ? 'publish_posts' : 'edit_posts';
     199
     200                if(!current_user_can($cap))
     201                        $this->auth_required(__('Sorry, you do not have the right to edit/publish new posts.'));
     202
     203                $blog_ID = (int ) $blog_id;
     204                $post_status = ($publish) ? 'publish' : 'draft';
     205                $post_author = (int) $user->ID;
     206                $post_title = $entry->title[1];
     207                $post_content = $entry->content[1];
     208                $post_excerpt = $entry->summary[1];
     209                $pubtimes = $this->get_publish_time($entry);
     210                $post_date = $pubtimes[0];
     211                $post_date_gmt = $pubtimes[1];
     212               
     213                if ( isset( $_SERVER['HTTP_SLUG'] ) )
     214                        $post_name = $_SERVER['HTTP_SLUG'];
     215
     216                $post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'post_name');
     217
     218                $this->escape($post_data);
     219                log_app('Inserting Post. Data:', print_r($post_data,true));
     220
     221                $postID = wp_insert_post($post_data);
     222
     223                if (!$postID) {
     224                        $this->internal_error(__('Sorry, your entry could not be posted. Something wrong happened.'));
     225                }
     226
     227                // getting warning here about unable to set headers
     228                // because something in the cache is printing to the buffer
     229                // could we clean up wp_set_post_categories or cache to not print
     230                // this could affect our ability to send back the right headers
     231                @wp_set_post_categories($postID, $post_category);
     232
     233                $output = $this->get_entry($postID);
     234
     235                log_app('function',"create_post($postID)");
     236                $this->created($postID, $output);
     237        }
     238
     239        function get_post($postID) {
     240
     241                global $entry;
     242                $this->set_current_entry($postID);
     243                $output = $this->get_entry($postID);
     244                log_app('function',"get_post($postID)");
     245                $this->output($output);
     246
     247        }
     248
     249        function put_post($postID) {
     250                global $wpdb;
     251
     252                // checked for valid content-types (atom+xml)
     253                // quick check and exit
     254                $this->get_accepted_content_type($this->atom_content_types);
     255
     256                $parser = new AtomParser();
     257                if(!$parser->parse()) {
     258                        $this->bad_request();
     259                }
     260
     261                $parsed = array_pop($parser->feed->entries);
     262
     263                log_app('Received UPDATED entry:', print_r($parsed,true));
     264
     265                // check for not found
     266                global $entry;
     267                $entry = $GLOBALS['entry'];
     268                $this->set_current_entry($postID);
     269
     270                if(!current_user_can('edit_post', $entry['ID']))
     271                        $this->auth_required(__('Sorry, you do not have the right to edit this post.'));
     272
     273                $publish = (isset($parsed->draft) && trim($parsed->draft) == 'yes') ? false : true;
     274
     275                extract($entry);
     276
     277                $post_title = $parsed->title[1];
     278                $post_content = $parsed->content[1];
     279                $post_excerpt = $parsed->summary[1];
     280                $pubtimes = $this->get_publish_time($entry);
     281                $post_date = $pubtimes[0];
     282                $post_date_gmt = $pubtimes[1];     
     283
     284                // let's not go backwards and make something draft again.
     285                if(!$publish && $post_status == 'draft') {
     286                        $post_status = ($publish) ? 'publish' : 'draft';
     287                } elseif($publish) {
     288                        $post_status = 'publish';
     289                }
     290
     291                $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'post_date', 'post_date_gmt');
     292                $this->escape($postdata);
     293
     294                $result = wp_update_post($postdata);
     295
     296                if (!$result) {
     297                        $this->internal_error(__('For some strange yet very annoying reason, this post could not be edited.'));
     298                }
     299
     300                log_app('function',"put_post($postID)");
     301                $this->ok();
     302        }
     303
     304        function delete_post($postID) {
     305
     306                // check for not found
     307                global $entry;
     308                $this->set_current_entry($postID);
     309
     310                if(!current_user_can('edit_post', $postID)) {
     311                        $this->auth_required(__('Sorry, you do not have the right to delete this post.'));
     312                }
     313
     314                if ($entry['post_type'] == 'attachment') {
     315                        $this->delete_attachment($postID);
     316                } else {
     317                        $result = wp_delete_post($postID);
     318
     319                        if (!$result) {
     320                                $this->internal_error(__('For some strange yet very annoying reason, this post could not be deleted.'));
     321                        }
     322
     323                        log_app('function',"delete_post($postID)");
     324                        $this->ok();
     325                }
     326
     327        }
     328
     329        function get_attachment($postID = NULL) {
     330
     331                global $entry;
     332                if (!isset($postID)) {
     333                        $this->get_attachments();
     334                } else {
     335                        $this->set_current_entry($postID);
     336                        $output = $this->get_entry($postID, 'attachment');
     337                        log_app('function',"get_attachment($postID)");
     338                        $this->output($output);
     339                }
     340        }
     341
     342        function create_attachment() {
     343                global $wp, $wpdb, $wp_query, $blog_id;
     344
     345                $type = $this->get_accepted_content_type();
     346
     347                if(!current_user_can('upload_files'))
     348                        $this->auth_required(__('You do not have permission to upload files.'));
     349
     350                $fp = fopen("php://input", "rb");
     351                $bits = NULL;
     352                while(!feof($fp)) {
     353                        $bits .= fread($fp, 4096);
     354                }
     355                fclose($fp);
     356
     357                $slug = '';
     358                if ( isset( $_SERVER['HTTP_SLUG'] ) )
     359                        $slug = sanitize_file_name( $_SERVER['HTTP_SLUG'] );
     360                elseif ( isset( $_SERVER['HTTP_TITLE'] ) )
     361                        $slug = sanitize_file_name( $_SERVER['HTTP_TITLE'] );
     362                elseif ( empty( $slug ) ) // just make a random name
     363                        $slug = substr( md5( uniqid( microtime() ) ), 0, 7);
     364                $ext = preg_replace( '|.*/([a-z]+)|', '$1', $_SERVER['CONTENT_TYPE'] );
     365                $slug = "$slug.$ext";
     366                $file = wp_upload_bits( $slug, NULL, $bits);
     367
     368                log_app('wp_upload_bits returns:',print_r($file,true));
     369
     370                $url = $file['url'];
     371                $file = $file['file'];
     372                $filename = basename($file);
     373
     374                $header = apply_filters('wp_create_file_in_uploads', $file); // replicate
     375
     376                // Construct the attachment array
     377                $attachment = array(
     378                        'post_title' => $slug,
     379                        'post_content' => $slug,
     380                        'post_status' => 'attachment',
     381                        'post_parent' => 0,
     382                        'post_mime_type' => $type,
     383                        'guid' => $url
     384                        );
     385
     386                // Save the data
     387                $postID = wp_insert_attachment($attachment, $file, $post);
     388
     389                if (!$postID) {
     390                        $this->internal_error(__('Sorry, your entry could not be posted. Something wrong happened.'));
     391                }
     392
     393                $output = $this->get_entry($postID, 'attachment');
     394
     395                $this->created($postID, $output, 'attachment');
     396                log_app('function',"create_attachment($postID)");
     397        }
     398
     399        function put_attachment($postID) {
     400                global $wpdb;
     401
     402                // checked for valid content-types (atom+xml)
     403                // quick check and exit
     404                $this->get_accepted_content_type($this->atom_content_types);
     405
     406                $parser = new AtomParser();
     407                if(!$parser->parse()) {
     408                        $this->bad_request();
     409                }
     410
     411                $parsed = array_pop($parser->feed->entries);
     412
     413                // check for not found
     414                global $entry;
     415                $this->set_current_entry($postID);
     416
     417                if(!current_user_can('edit_post', $entry['ID']))
     418                        $this->auth_required(__('Sorry, you do not have the right to edit this post.'));
     419
     420                $publish = (isset($parsed->draft) && trim($parsed->draft) == 'yes') ? false : true;
     421
     422                extract($entry);
     423
     424                $post_title = $parsed->title[1];
     425                $post_content = $parsed->content[1];
     426
     427                $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt');
     428                $this->escape($postdata);
     429
     430                $result = wp_update_post($postdata);
     431
     432                if (!$result) {
     433                        $this->internal_error(__('For some strange yet very annoying reason, this post could not be edited.'));
     434                }
     435
     436                log_app('function',"put_attachment($postID)");
     437                $this->ok();
     438        }
     439
     440        function delete_attachment($postID) {
     441                log_app('function',"delete_attachment($postID). File '$location' deleted.");
     442
     443                // check for not found
     444                global $entry;
     445                $this->set_current_entry($postID);
     446
     447                if(!current_user_can('edit_post', $postID)) {
     448                        $this->auth_required(__('Sorry, you do not have the right to delete this post.'));
     449                }
     450
     451                $location = get_post_meta($entry['ID'], '_wp_attached_file', true);
     452
     453                // delete file
     454                @unlink($location);
     455
     456                // delete attachment
     457                $result = wp_delete_post($postID);
     458
     459                if (!$result) {
     460                        $this->internal_error(__('For some strange yet very annoying reason, this post could not be deleted.'));
     461                }
     462
     463                log_app('function',"delete_attachment($postID). File '$location' deleted.");
     464                $this->ok();
     465        }
     466
     467        function get_file($postID) {
     468
     469                // check for not found
     470                global $entry;
     471                $this->set_current_entry($postID);
     472
     473                // then whether user can edit the specific post
     474                if(!current_user_can('edit_post', $postID)) {
     475                        $this->auth_required(__('Sorry, you do not have the right to edit this post.'));
     476                }
     477
     478                $location = get_post_meta($entry['ID'], '_wp_attached_file', true);
     479                $filetype = wp_check_filetype($location);
     480
     481                if(!isset($location) || 'attachment' != $entry['post_type'] || empty($filetype['ext']))
     482                        $this->internal_error(__('Error ocurred while accessing post metadata for file location.'));
     483
     484                status_header('200');
     485                header('Content-Type: ' . $entry['post_mime_type']);
     486                header('Connection: close');
     487
     488                $fp = fopen($location, "rb");
     489                while(!feof($fp)) {
     490                        echo fread($fp, 4096);
     491                }
     492                fclose($fp);
     493
     494                log_app('function',"get_file($postID)");
     495                exit;
     496        }
     497
     498        function put_file($postID) {
     499
     500                $type = $this->get_accepted_content_type();
     501
     502                // first check if user can upload
     503                if(!current_user_can('upload_files'))
     504                        $this->auth_required(__('You do not have permission to upload files.'));
     505
     506                // check for not found
     507                global $entry;
     508                $this->set_current_entry($postID);
     509
     510                // then whether user can edit the specific post
     511                if(!current_user_can('edit_post', $postID)) {
     512                        $this->auth_required(__('Sorry, you do not have the right to edit this post.'));
     513                }
     514
     515                $location = get_post_meta($entry['ID'], '_wp_attached_file', true);
     516                $filetype = wp_check_filetype($location);
     517
     518                if(!isset($location) || 'attachment' != $entry['post_type'] || empty($filetype['ext']))
     519                        $this->internal_error(__('Error ocurred while accessing post metadata for file location.'));
     520
     521                $fp = fopen("php://input", "rb");
     522                $localfp = fopen($location, "w+");
     523                while(!feof($fp)) {
     524                        fwrite($localfp,fread($fp, 4096));
     525                }
     526                fclose($fp);
     527                fclose($localfp);
     528
     529                $ID = $entry['ID'];
     530                $pubtimes = $this->get_publish_time($entry);
     531                $post_date = $pubtimes[0];
     532                $post_date_gmt = $pubtimes[1];
     533
     534                $post_data = compact('ID', 'post_date', 'post_date_gmt');
     535                $result = wp_update_post($post_data);
     536
     537                if (!$result) {
     538                        $this->internal_error(__('Sorry, your entry could not be posted. Something wrong happened.'));
     539                }
     540
     541                log_app('function',"put_file($postID)");
     542                $this->ok();
     543        }
     544
     545        function get_entries_url($page = NULL) {
     546                if($GLOBALS['post_type'] == 'attachment') {
     547                        $path = $this->MEDIA_PATH;
     548                } else {
     549                        $path = $this->ENTRIES_PATH;
     550                }
     551                $url = get_bloginfo('url') . '/' . $this->script_name . '/' . $path;
     552                if(isset($page) && is_int($page)) {
     553                        $url .= "/$page";
     554                }
     555                return $url;
     556        }
     557
     558        function the_entries_url($page = NULL) {
     559                $url = $this->get_entries_url($page);
     560                echo $url;
     561        }
     562
     563        function get_categories_url($page = NULL) {
     564                return get_bloginfo('url') . '/' . $this->script_name . '/' . $this->CATEGORIES_PATH;
     565        }
     566
     567        function the_categories_url() {
     568                $url = $this->get_categories_url();
     569                echo $url;
     570        }
     571
     572        function get_attachments_url($page = NULL) {
     573                $url = get_bloginfo('url') . '/' . $this->script_name . '/' . $this->MEDIA_PATH;
     574                if(isset($page) && is_int($page)) {
     575                        $url .= "/$page";
     576                }
     577                return $url;
     578        }
     579
     580        function the_attachments_url($page = NULL) {
     581                $url = $this->get_attachments_url($page);
     582                echo $url;
     583        }
     584
     585        function get_service_url() {
     586                return get_bloginfo('url') . '/' . $this->script_name . '/' . $this->SERVICE_PATH;
     587        }
     588
     589        function get_entry_url($postID = NULL) {
     590                if(!isset($postID)) {
     591                        global $post;
     592                        $postID = (int) $GLOBALS['post']->ID;
     593                }
     594
     595                $url = get_bloginfo('url') . '/' . $this->script_name . '/' . $this->ENTRY_PATH . "/$postID";
     596
     597                log_app('function',"get_entry_url() = $url");
     598                return $url;
     599        }
     600
     601        function the_entry_url($postID = NULL) {
     602                $url = $this->get_entry_url($postID);
     603                echo $url;
     604        }
     605
     606        function get_media_url($postID = NULL) {
     607                if(!isset($postID)) {
     608                        global $post;
     609                        $postID = (int) $GLOBALS['post']->ID;
     610                }
     611
     612                $url = get_bloginfo('url') . '/' . $this->script_name . '/' . $this->MEDIA_SINGLE_PATH ."/file/$postID";
     613
     614                log_app('function',"get_media_url() = $url");
     615                return $url;
     616        }
     617
     618        function the_media_url($postID = NULL) {
     619                $url = $this->get_media_url($postID);
     620                echo $url;
     621        }
     622
     623        function set_current_entry($postID) {
     624                global $entry;
     625                log_app('function',"set_current_entry($postID)");
     626
     627                if(!isset($postID)) {
     628                        // $this->bad_request();
     629                        $this->not_found();
     630                }
     631
     632                $entry = wp_get_single_post($postID,ARRAY_A);
     633
     634                if(!isset($entry) || !isset($entry['ID']))
     635                        $this->not_found();
     636
     637                return;
     638        }
     639
     640        function get_posts($page = 1, $post_type = 'post') {
     641                        log_app('function',"get_posts($page, '$post_type')");
     642                        $feed = $this->get_feed($page, $post_type);
     643                        $this->output($feed);
     644        }
     645
     646        function get_attachments($page = 1, $post_type = 'attachment') {
     647            log_app('function',"get_attachments($page, '$post_type')");
     648            $GLOBALS['post_type'] = $post_type;
     649            $feed = $this->get_feed($page, $post_type);
     650            $this->output($feed);
     651        }
     652
     653        function get_feed($page = 1, $post_type = 'post') {
     654                global $post, $wp, $wp_query, $posts, $wpdb, $blog_id, $post_cache;
     655                log_app('function',"get_feed($page, '$post_type')");
     656                ob_start();
     657
     658                if(!isset($page)) {
     659                        $page = 1;
     660                }
     661                $page = (int) $page;
     662
     663                $count = get_option('posts_per_rss');
     664
     665                wp('what_to_show=posts&posts_per_page=' . $count . '&offset=' . ($count * ($page-1) ));
     666
     667                $post = $GLOBALS['post'];
     668                $posts = $GLOBALS['posts'];
     669                $wp = $GLOBALS['wp'];
     670                $wp_query = $GLOBALS['wp_query'];
     671                $wpdb = $GLOBALS['wpdb'];
     672                $blog_id = (int) $GLOBALS['blog_id'];
     673                $post_cache = $GLOBALS['post_cache'];
     674                log_app('function',"query_posts(# " . print_r($wp_query, true) . "#)");
     675
     676                log_app('function',"total_count(# $wp_query->max_num_pages #)");
     677                $last_page = $wp_query->max_num_pages;
     678                $next_page = (($page + 1) > $last_page) ? NULL : $page + 1;
     679                $prev_page = ($page - 1) < 1 ? NULL : $page - 1;
     680                $last_page = ((int)$last_page == 1 || (int)$last_page == 0) ? NULL : (int) $last_page;
     681                $self_page = $page > 1 ? $page : NULL;
     682?><feed xmlns="<?php echo $this->ATOM_NS ?>" xmlns:app="<?php echo $this->ATOMPUB_NS ?>" xml:lang="<?php echo get_option('rss_language'); ?>">
     683<id><?php $this->the_entries_url() ?></id>
     684<updated><?php echo mysql2date('Y-m-d\TH:i:s\Z', get_lastpostmodified('GMT')); ?></updated>
     685<title type="text"><?php bloginfo_rss('name') ?></title>
     686<subtitle type="text"><?php bloginfo_rss("description") ?></subtitle>
     687<link rel="first" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url() ?>" />
     688<?php if(isset($prev_page)): ?>
     689<link rel="previous" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url($prev_page) ?>" />
     690<?php endif; ?>
     691<?php if(isset($next_page)): ?>
     692<link rel="next" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url($next_page) ?>" />
     693<?php endif; ?>
     694<link rel="last" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url($last_page) ?>" />
     695<link rel="self" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url($self_page) ?>" />
     696<rights type="text">Copyright <?php echo mysql2date('Y', get_lastpostdate('blog')); ?></rights>
     697<generator uri="http://wordpress.com/" version="1.0.5-dc">WordPress.com Atom API</generator>
     698<?php if ( have_posts() ) {
     699                        while ( have_posts() ) {
     700                                the_post();
     701                                $this->echo_entry();
     702                        }
     703                }
     704?></feed>
     705<?php
     706                $feed = ob_get_contents();
     707                ob_end_clean();
     708                return $feed;
     709        }
     710
     711        function get_entry($postID, $post_type = 'post') {
     712                log_app('function',"get_entry($postID, '$post_type')");
     713                ob_start();
     714                global $posts, $post, $wp_query, $wp, $wpdb, $blog_id, $post_cache;
     715                switch($post_type) {
     716                        case 'post':
     717                                $varname = 'p';
     718                                break;
     719                        case 'attachment':
     720                                $varname = 'attachment_id';
     721                                break;
     722                }
     723                query_posts($varname . '=' . $postID);
     724                if ( have_posts() ) {
     725                        while ( have_posts() ) {
     726                                the_post();
     727                                $this->echo_entry();
     728                                log_app('$post',print_r($GLOBALS['post'],true));
     729                                $entry = ob_get_contents();
     730                                break;
     731                        }
     732                }
     733                ob_end_clean();
     734
     735                log_app('get_entry returning:',$entry);
     736                return $entry;
     737        }
     738
     739        function echo_entry() { ?>
     740<entry xmlns="<?php echo $this->ATOM_NS ?>"
     741       xmlns:app="<?php echo $this->ATOMPUB_NS ?>" xml:lang="<?php echo get_option('rss_language'); ?>">
     742        <id><?php the_guid($GLOBALS['post']->ID); ?></id>
     743<?php list($content_type, $content) = $this->prep_content(get_the_title()); ?>
     744        <title type="<?php echo $content_type ?>"><?php echo $content ?></title>
     745        <updated><?php echo get_post_modified_time('Y-m-d\TH:i:s\Z', true); ?></updated>
     746        <published><?php echo get_post_time('Y-m-d\TH:i:s\Z', true); ?></published>
     747        <app:edited><?php echo get_post_modified_time('Y-m-d\TH:i:s\Z', true); ?></app:edited>
     748        <app:control>
     749                <app:draft><?php echo ($GLOBALS['post']->post_status == 'draft' ? 'yes' : 'no') ?></app:draft>
     750        </app:control>
     751        <author>
     752                <name><?php the_author()?></name>
     753                <email><?php the_author_email()?></email>
     754<?php if (get_the_author_url() && get_the_author_url() != 'http://') { ?>
     755                <uri><?php the_author_url()?></uri>
     756<?php } ?>
     757        </author>
     758<?php if($GLOBALS['post']->post_type == 'attachment') { ?>
     759        <link rel="edit-media" href="<?php $this->the_media_url() ?>" />
     760        <content type="<?php echo $GLOBALS['post']->post_mime_type ?>" src="<?php the_guid(); ?>"/>
     761<?php } else { ?>
     762        <link href="<?php the_permalink_rss() ?>" />
     763<?php if ( strlen( $GLOBALS['post']->post_content ) ) :
     764list($content_type, $content) = $this->prep_content(get_the_content()); ?>
     765        <content type="<?php echo $content_type ?>"><?php echo $content ?></content>
     766<?php endif; ?>
     767<?php } ?>
     768        <link rel="edit" href="<?php $this->the_entry_url() ?>" />
     769<?php foreach(get_the_category() as $category) { ?>
     770        <category scheme="<?php bloginfo_rss('home') ?>" term="<?php echo $category->cat_name?>" />
     771<?php } ?>
     772<?php list($content_type, $content) = $this->prep_content(get_the_excerpt()); ?>
     773        <summary type="<?php echo $content_type ?>"><?php echo $content ?></summary>
     774</entry>
     775<?php }
     776
     777        function prep_content($data) {
     778                if (strpos($data, '<') === false && strpos($data, '&') === false) {
     779                        return array('text', $data);
     780                }
     781
     782                $parser = xml_parser_create();
     783                xml_parse($parser, '<div>' . $data . '</div>', true);
     784                $code = xml_get_error_code($parser);
     785                xml_parser_free($parser);
     786
     787                if (!$code) {
     788                        if (strpos($data, '<') === false) {
     789                                return array('text', $data);
     790                        } else {
     791                                $data = "<div xmlns='http://www.w3.org/1999/xhtml'>$data</div>";
     792                                return array('xhtml', $data);
     793                        }
     794                }
     795
     796                if (strpos($data, ']]>') == false) {
     797                        return array('html', "<![CDATA[$data]]>");
     798                } else {
     799                        return array('html', htmlspecialchars($data));
     800                }
     801        }
     802
     803        function ok() {
     804                log_app('Status','200: OK');
     805                header('Content-Type: text/plain');
     806                status_header('200');
     807                exit;
     808        }
     809
     810        function no_content() {
     811                log_app('Status','204: No Content');
     812                header('Content-Type: text/plain');
     813                status_header('204');
     814                echo "Deleted.";
     815                exit;
     816        }
     817
     818        function internal_error($msg = 'Internal Server Error') {
     819                log_app('Status','500: Server Error');
     820                header('Content-Type: text/plain');
     821                status_header('500');
     822                echo $msg;
     823                exit;
     824        }
     825
     826        function bad_request() {
     827                log_app('Status','400: Bad Request');
     828                header('Content-Type: text/plain');
     829                status_header('400');
     830                exit;
     831        }
     832
     833        function length_required() {
     834                log_app('Status','411: Length Required');
     835                header("HTTP/1.1 411 Length Required");
     836                header('Content-Type: text/plain');
     837                status_header('411');
     838                exit;
     839        }
     840
     841        function invalid_media() {
     842                log_app('Status','415: Unsupported Media Type');
     843                header("HTTP/1.1 415 Unsupported Media Type");
     844                header('Content-Type: text/plain');
     845                exit;
     846        }
     847
     848        function not_found() {
     849                log_app('Status','404: Not Found');
     850                header('Content-Type: text/plain');
     851                status_header('404');
     852                exit;
     853        }
     854
     855        function not_allowed($allow) {
     856                log_app('Status','405: Not Allowed');
     857                header('Allow: ' . join(',', $allow));
     858                status_header('405');
     859                exit;
     860        }
     861
     862        function redirect($url) {
     863
     864                log_app('Status','302: Redirect');
     865                $escaped_url = attribute_escape($url);
     866                $content = <<<EOD
     867<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
     868<html>
     869  <head>
     870    <title>302 Found</title>
     871  </head>
     872<body>
     873  <h1>Found</h1>
     874  <p>The document has moved <a href="$escaped_url">here</a>.</p>
     875  </body>
     876</html>
     877
     878EOD;
     879                header('HTTP/1.1 302 Moved');
     880                header('Content-Type: text/html');
     881                header('Location: ' . $url);
     882                echo $content;
     883                exit;
     884
     885        }
     886
     887
     888        function client_error($msg = 'Client Error') {
     889                log_app('Status','400: Client Error');
     890                header('Content-Type: text/plain');
     891                status_header('400');
     892                exit;
     893        }
     894
     895        function created($post_ID, $content, $post_type = 'post') {
     896                log_app('created()::$post_ID',"$post_ID, $post_type");
     897                $edit = $this->get_entry_url($post_ID);
     898                switch($post_type) {
     899                        case 'post':
     900                                $ctloc = $this->get_entry_url($post_ID);
     901                                break;
     902                        case 'attachment':
     903                                $edit = get_bloginfo('url') . '/' . $this->script_name . "/attachments/$post_ID";
     904                                break;
     905                }
     906                header("Content-Type: $this->ATOM_CONTENT_TYPE");
     907                if(isset($ctloc))
     908                        header('Content-Location: ' . $ctloc);
     909                header('Location: ' . $edit);
     910                status_header('201');
     911                echo $content;
     912                exit;
     913        }
     914
     915        function auth_required($msg) {
     916                log_app('Status','401: Auth Required');
     917                nocache_headers();
     918                header('WWW-Authenticate: Basic realm="WordPress Atom Protocol"');
     919                header("HTTP/1.1 401 $msg");
     920                header('Status: ' . $msg);
     921                header('Content-Type: text/html');
     922                $content = <<<EOD
     923<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
     924<html>
     925  <head>
     926    <title>401 Unauthorized</title>
     927  </head>
     928<body>
     929    <h1>401 Unauthorized</h1>
     930    <p>$msg</p>
     931  </body>
     932</html>
     933
     934EOD;
     935                echo $content;
     936                exit;
     937        }
     938
     939        function output($xml, $ctype = 'application/atom+xml') {
     940                        status_header('200');
     941                        $xml = '<?xml version="1.0" encoding="' . strtolower(get_option('blog_charset')) . '"?>'."\n".$xml;
     942                        header('Connection: close');
     943                        header('Content-Length: '. strlen($xml));
     944                        header('Content-Type: ' . $ctype);
     945                        header('Content-Disposition: attachment; filename=atom.xml');
     946                        header('Date: '. date('r'));
     947                        if($this->do_output)
     948                                echo $xml;
     949                        log_app('function', "output:\n$xml");
     950                        exit;
     951        }
     952
     953        function escape(&$array) {
     954                global $wpdb;
     955
     956                foreach ($array as $k => $v) {
     957                                if (is_array($v)) {
     958                                                $this->escape($array[$k]);
     959                                } else if (is_object($v)) {
     960                                                //skip
     961                                } else {
     962                                                $array[$k] = $wpdb->escape($v);
     963                                }
     964                }
     965        }
     966
     967        /*
     968         * Access credential through various methods and perform login
     969         */
     970        function authenticate() {
     971                $login_data = array();
     972                $already_md5 = false;
     973
     974                log_app("authenticate()",print_r($_ENV, true));
     975
     976                // if using mod_rewrite/ENV hack
     977                // http://www.besthostratings.com/articles/http-auth-php-cgi.html
     978                if(isset($_SERVER['HTTP_AUTHORIZATION'])) {
     979                        list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) =
     980                                explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
     981                }
     982
     983                // If Basic Auth is working...
     984                if(isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
     985                        $login_data = array('login' => $_SERVER['PHP_AUTH_USER'],       'password' => $_SERVER['PHP_AUTH_PW']);
     986                        log_app("Basic Auth",$login_data['login']);
     987                } else {
     988                        // else, do cookie-based authentication
     989                        if (function_exists('wp_get_cookie_login')) {
     990                                $login_data = wp_get_cookie_login();
     991                                $already_md5 = true;
     992                        }
     993                }
     994
     995                // call wp_login and set current user
     996                if (!empty($login_data) && wp_login($login_data['login'], $login_data['password'], $already_md5)) {
     997                         $current_user = new WP_User(0, $login_data['login']);
     998                         wp_set_current_user($current_user->ID);
     999                        log_app("authenticate()",$login_data['login']);
     1000                }
     1001        }
     1002
     1003        function get_accepted_content_type($types = NULL) {
     1004
     1005                if(!isset($types)) {
     1006                        $types = $this->media_content_types;
     1007                }
     1008
     1009                if(!isset($_SERVER['CONTENT_LENGTH']) || !isset($_SERVER['CONTENT_TYPE'])) {
     1010                        $this->length_required();
     1011                }
     1012
     1013                $type = $_SERVER['CONTENT_TYPE'];
     1014                list($type,$subtype) = explode('/',$type);
     1015                list($subtype) = explode(";",$subtype); // strip MIME parameters
     1016                log_app("get_accepted_content_type", "type=$type, subtype=$subtype");
     1017
     1018                foreach($types as $t) {
     1019                        list($acceptedType,$acceptedSubtype) = explode('/',$t);
     1020                        if($acceptedType == '*' || $acceptedType == $type) {
     1021                                if($acceptedSubtype == '*' || $acceptedSubtype == $subtype)
     1022                                        return $type . "/" . $subtype;
     1023                        }
     1024                }
     1025
     1026                $this->invalid_media();
     1027        }
     1028
     1029        function process_conditionals() {
     1030
     1031                if(empty($this->params)) return;
     1032                if($_SERVER['REQUEST_METHOD'] == 'DELETE') return;
     1033
     1034                switch($this->params[0]) {
     1035                        case $this->ENTRY_PATH:
     1036                                global $post;
     1037                                $post = wp_get_single_post($this->params[1]);
     1038                                $wp_last_modified = get_post_modified_time('D, d M Y H:i:s', true);
     1039                                $post = NULL;
     1040                                break;
     1041                        case $this->ENTRIES_PATH:
     1042                                $wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastpostmodified('GMT'), 0).' GMT';
     1043                                break;
     1044                        default:
     1045                                return;
     1046                }
     1047                $wp_etag = md5($wp_last_modified);
     1048                @header("Last-Modified: $wp_last_modified");
     1049                @header("ETag: $wp_etag");
     1050
     1051                // Support for Conditional GET
     1052                if (isset($_SERVER['HTTP_IF_NONE_MATCH']))
     1053                        $client_etag = stripslashes($_SERVER['HTTP_IF_NONE_MATCH']);
     1054                else
     1055                        $client_etag = false;
     1056
     1057                $client_last_modified = trim( $_SERVER['HTTP_IF_MODIFIED_SINCE']);
     1058                // If string is empty, return 0. If not, attempt to parse into a timestamp
     1059                $client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;
     1060
     1061                // Make a timestamp for our most recent modification...
     1062                $wp_modified_timestamp = strtotime($wp_last_modified);
     1063
     1064                if ( ($client_last_modified && $client_etag) ?
     1065                (($client_modified_timestamp >= $wp_modified_timestamp) && ($client_etag == $wp_etag)) :
     1066                (($client_modified_timestamp >= $wp_modified_timestamp) || ($client_etag == $wp_etag)) ) {
     1067                        status_header( 304 );
     1068                        exit;
     1069                }
     1070        }
     1071
     1072        function rfc3339_str2time($str) {
     1073           
     1074            $match = false;
     1075            if(!preg_match("/(\d{4}-\d{2}-\d{2})T(\d{2}\:\d{2}\:\d{2})\.?\d{0,3}(Z|[+-]+\d{2}\:\d{2})/", $str, $match))
     1076                        return false;
     1077       
     1078            if($match[3] == 'Z')
     1079                        $match[3] == '+0000';
     1080       
     1081            return strtotime($match[1] . " " . $match[2] . " " . $match[3]);
     1082        }       
     1083
     1084        function get_publish_time($entry) {
     1085
     1086            $pubtime = $this->rfc3339_str2time($entry->published);
     1087           
     1088            if(!$pubtime) {
     1089                        return array(current_time('mysql'),current_time('mysql',1));
     1090            } else {
     1091                        return array(date("Y-m-d H:i:s", $pubtime), gmdate("Y-m-d H:i:s", $pubtime));
     1092            }
     1093        }
     1094
     1095}
     1096 No newline at end of file