Changeset 20062
- Timestamp:
- 03/01/2012 09:15:44 PM (14 years ago)
- Location:
- trunk
- Files:
-
- 1 edited
- 1 copied
-
wp-app.php (modified) (2 diffs)
-
wp-includes/class-wp-atom-server.php (copied) (copied from trunk/wp-app.php) (31 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/wp-app.php
r20000 r20062 19 19 require_once(ABSPATH . WPINC . '/atomlib.php'); 20 20 21 /** Atom Server **/ 22 require_once(ABSPATH . WPINC . '/class-wp-atom-server.php'); 23 21 24 /** Admin Image API for metadata updating */ 22 25 require_once(ABSPATH . '/wp-admin/includes/image.php'); 23 26 24 27 $_SERVER['PATH_INFO'] = preg_replace( '/.*\/wp-app\.php/', '', $_SERVER['REQUEST_URI'] ); 25 26 /**27 * Whether to always authenticate user. Permanently set to true.28 *29 * @name always_authenticate30 * @var int|bool31 * @todo Should be an option somewhere32 */33 $always_authenticate = 1;34 28 35 29 /** … … 47 41 _deprecated_function( __FUNCTION__, '3.4', 'error_log()' ); 48 42 if ( ! empty( $GLOBALS['app_logging'] ) ) 49 error_log( $label . ' - ' . $message );43 error_log( $label . ' - ' . $message ); 50 44 } 51 45 52 /** 53 * Filter to add more post statuses. 54 * 55 * @since 2.2.0 56 * 57 * @param string $where SQL statement to filter. 58 * @return string Filtered SQL statement with added post_status for where clause. 59 */ 60 function wa_posts_where_include_drafts_filter($where) { 61 $where = str_replace("post_status = 'publish'","post_status = 'publish' OR post_status = 'future' OR post_status = 'draft' OR post_status = 'inherit'", $where); 62 return $where; 46 // Allow for a plugin to insert a different class to handle requests. 47 $wp_atom_server_class = apply_filters('wp_atom_server_class', 'wp_atom_server'); 48 $wp_atom_server = new $wp_atom_server_class; 63 49 64 } 65 add_filter('posts_where', 'wa_posts_where_include_drafts_filter'); 66 67 /** 68 * WordPress AtomPub API implementation. 69 * 70 * @package WordPress 71 * @subpackage Publishing 72 * @since 2.2.0 73 */ 74 class AtomServer { 75 76 /** 77 * ATOM content type. 78 * 79 * @since 2.2.0 80 * @var string 81 */ 82 var $ATOM_CONTENT_TYPE = 'application/atom+xml'; 83 84 /** 85 * Categories ATOM content type. 86 * 87 * @since 2.2.0 88 * @var string 89 */ 90 var $CATEGORIES_CONTENT_TYPE = 'application/atomcat+xml'; 91 92 /** 93 * Service ATOM content type. 94 * 95 * @since 2.3.0 96 * @var string 97 */ 98 var $SERVICE_CONTENT_TYPE = 'application/atomsvc+xml'; 99 100 /** 101 * ATOM XML namespace. 102 * 103 * @since 2.3.0 104 * @var string 105 */ 106 var $ATOM_NS = 'http://www.w3.org/2005/Atom'; 107 108 /** 109 * ATOMPUB XML namespace. 110 * 111 * @since 2.3.0 112 * @var string 113 */ 114 var $ATOMPUB_NS = 'http://www.w3.org/2007/app'; 115 116 /** 117 * Entries path. 118 * 119 * @since 2.2.0 120 * @var string 121 */ 122 var $ENTRIES_PATH = "posts"; 123 124 /** 125 * Categories path. 126 * 127 * @since 2.2.0 128 * @var string 129 */ 130 var $CATEGORIES_PATH = "categories"; 131 132 /** 133 * Media path. 134 * 135 * @since 2.2.0 136 * @var string 137 */ 138 var $MEDIA_PATH = "attachments"; 139 140 /** 141 * Entry path. 142 * 143 * @since 2.2.0 144 * @var string 145 */ 146 var $ENTRY_PATH = "post"; 147 148 /** 149 * Service path. 150 * 151 * @since 2.2.0 152 * @var string 153 */ 154 var $SERVICE_PATH = "service"; 155 156 /** 157 * Media single path. 158 * 159 * @since 2.2.0 160 * @var string 161 */ 162 var $MEDIA_SINGLE_PATH = "attachment"; 163 164 /** 165 * ATOMPUB parameters. 166 * 167 * @since 2.2.0 168 * @var array 169 */ 170 var $params = array(); 171 172 /** 173 * Supported ATOMPUB media types. 174 * 175 * @since 2.3.0 176 * @var array 177 */ 178 var $media_content_types = array('image/*','audio/*','video/*'); 179 180 /** 181 * ATOMPUB content type(s). 182 * 183 * @since 2.2.0 184 * @var array 185 */ 186 var $atom_content_types = array('application/atom+xml'); 187 188 /** 189 * ATOMPUB methods. 190 * 191 * @since 2.2.0 192 * @var unknown_type 193 */ 194 var $selectors = array(); 195 196 /** 197 * Whether to do output. 198 * 199 * Support for head. 200 * 201 * @since 2.2.0 202 * @var bool 203 */ 204 var $do_output = true; 205 206 /** 207 * Constructor - Sets up object properties. 208 * 209 * @since 2.2.0 210 * @return AtomServer 211 */ 212 function __construct() { 213 214 $var_by_ref = explode( '/', $_SERVER['SCRIPT_NAME'] ); 215 $this->script_name = array_pop( $var_by_ref ); 216 $this->app_base = site_url( $this->script_name . '/' ); 217 218 $this->selectors = array( 219 '@/service$@' => 220 array('GET' => 'get_service'), 221 '@/categories$@' => 222 array('GET' => 'get_categories_xml'), 223 '@/post/(\d+)$@' => 224 array('GET' => 'get_post', 225 'PUT' => 'put_post', 226 'DELETE' => 'delete_post'), 227 '@/posts/?(\d+)?$@' => 228 array('GET' => 'get_posts', 229 'POST' => 'create_post'), 230 '@/attachments/?(\d+)?$@' => 231 array('GET' => 'get_attachment', 232 'POST' => 'create_attachment'), 233 '@/attachment/file/(\d+)$@' => 234 array('GET' => 'get_file', 235 'PUT' => 'put_file', 236 'DELETE' => 'delete_file'), 237 '@/attachment/(\d+)$@' => 238 array('GET' => 'get_attachment', 239 'PUT' => 'put_attachment', 240 'DELETE' => 'delete_attachment'), 241 ); 242 } 243 244 /** 245 * Handle ATOMPUB request. 246 * 247 * @since 2.2.0 248 */ 249 function handle_request() { 250 global $always_authenticate; 251 252 if ( !empty( $_SERVER['ORIG_PATH_INFO'] ) ) 253 $path = $_SERVER['ORIG_PATH_INFO']; 254 else 255 $path = $_SERVER['PATH_INFO']; 256 257 $method = $_SERVER['REQUEST_METHOD']; 258 259 $this->process_conditionals(); 260 //$this->process_conditionals(); 261 262 // exception case for HEAD (treat exactly as GET, but don't output) 263 if ($method == 'HEAD') { 264 $this->do_output = false; 265 $method = 'GET'; 266 } 267 268 // redirect to /service in case no path is found. 269 if (strlen($path) == 0 || $path == '/') 270 $this->redirect($this->get_service_url()); 271 272 // check to see if AtomPub is enabled 273 if ( !get_option( 'enable_app' ) ) 274 $this->forbidden( sprintf( __( 'AtomPub services are disabled on this site. An admin user can enable them at %s' ), admin_url('options-writing.php') ) ); 275 276 // dispatch 277 foreach ( $this->selectors as $regex => $funcs ) { 278 if ( preg_match($regex, $path, $matches) ) { 279 if ( isset($funcs[$method]) ) { 280 281 // authenticate regardless of the operation and set the current 282 // user. each handler will decide if auth is required or not. 283 if ( !$this->authenticate() ) { 284 if ( $always_authenticate ) 285 $this->auth_required('Credentials required.'); 286 } 287 288 array_shift($matches); 289 call_user_func_array(array(&$this,$funcs[$method]), $matches); 290 exit(); 291 } else { 292 // only allow what we have handlers for... 293 $this->not_allowed(array_keys($funcs)); 294 } 295 } 296 } 297 298 // oops, nothing found 299 $this->not_found(); 300 } 301 302 /** 303 * Retrieve XML for ATOMPUB service. 304 * 305 * @since 2.2.0 306 */ 307 function get_service() { 308 if ( !current_user_can( 'edit_posts' ) ) 309 $this->auth_required( __( 'Sorry, you do not have the right to access this site.' ) ); 310 311 $entries_url = esc_attr($this->get_entries_url()); 312 $categories_url = esc_attr($this->get_categories_url()); 313 $media_url = esc_attr($this->get_attachments_url()); 314 $accepted_media_types = ''; 315 foreach ($this->media_content_types as $med) { 316 $accepted_media_types = $accepted_media_types . "<accept>" . $med . "</accept>"; 317 } 318 $atom_prefix="atom"; 319 $atom_blogname = get_bloginfo('name'); 320 $service_doc = <<<EOD 321 <service xmlns="$this->ATOMPUB_NS" xmlns:$atom_prefix="$this->ATOM_NS"> 322 <workspace> 323 <$atom_prefix:title>$atom_blogname Workspace</$atom_prefix:title> 324 <collection href="$entries_url"> 325 <$atom_prefix:title>$atom_blogname Posts</$atom_prefix:title> 326 <accept>$this->ATOM_CONTENT_TYPE;type=entry</accept> 327 <categories href="$categories_url" /> 328 </collection> 329 <collection href="$media_url"> 330 <$atom_prefix:title>$atom_blogname Media</$atom_prefix:title> 331 $accepted_media_types 332 </collection> 333 </workspace> 334 </service> 335 336 EOD; 337 338 $this->output($service_doc, $this->SERVICE_CONTENT_TYPE); 339 } 340 341 /** 342 * Retrieve categories list in XML format. 343 * 344 * @since 2.2.0 345 */ 346 function get_categories_xml() { 347 if ( !current_user_can( 'edit_posts' ) ) 348 $this->auth_required( __( 'Sorry, you do not have the right to access this site.' ) ); 349 350 $home = esc_attr(get_bloginfo_rss('url')); 351 352 $categories = ""; 353 $cats = get_categories(array('hierarchical' => 0, 'hide_empty' => 0)); 354 foreach ( (array) $cats as $cat ) { 355 $categories .= " <category term=\"" . esc_attr($cat->name) . "\" />\n"; 356 } 357 $output = <<<EOD 358 <app:categories xmlns:app="$this->ATOMPUB_NS" 359 xmlns="$this->ATOM_NS" 360 fixed="yes" scheme="$home"> 361 $categories 362 </app:categories> 363 EOD; 364 $this->output($output, $this->CATEGORIES_CONTENT_TYPE); 365 } 366 367 /** 368 * Create new post. 369 * 370 * @since 2.2.0 371 */ 372 function create_post() { 373 global $user_ID; 374 $this->get_accepted_content_type($this->atom_content_types); 375 376 $parser = new AtomParser(); 377 if ( !$parser->parse() ) 378 $this->client_error(); 379 380 $entry = array_pop($parser->feed->entries); 381 382 $catnames = array(); 383 if ( !empty( $entry->categories ) ) { 384 foreach ( $entry->categories as $cat ) { 385 array_push($catnames, $cat["term"]); 386 } 387 } 388 389 $wp_cats = get_categories(array('hide_empty' => false)); 390 391 $post_category = array(); 392 393 foreach ( $wp_cats as $cat ) { 394 if ( in_array($cat->name, $catnames) ) 395 array_push($post_category, $cat->term_id); 396 } 397 398 $publish = ! ( isset( $entry->draft ) && 'yes' == trim( $entry->draft ) ); 399 400 $cap = ($publish) ? 'publish_posts' : 'edit_posts'; 401 402 if ( !current_user_can($cap) ) 403 $this->auth_required(__('Sorry, you do not have the right to edit/publish new posts.')); 404 405 $blog_ID = get_current_blog_id(); 406 $post_status = ($publish) ? 'publish' : 'draft'; 407 $post_author = (int) $user_ID; 408 409 $post_title = ''; 410 $post_content = ''; 411 $post_excerpt = ''; 412 $pubtimes = ''; 413 414 if ( isset( $entry->title ) && is_array( $entry->title ) && !empty( $entry->title[1] ) ) 415 $post_title = (string) $entry->title[1]; 416 if ( isset( $entry->content ) && is_array( $entry->content ) && !empty( $entry->content[1] ) ) 417 $post_content = (string) $entry->content[1]; 418 if ( isset( $entry->summary ) && is_array( $entry->summary ) && !empty( $entry->summary[1] ) ) 419 $post_excerpt = (string) $entry->summary[1]; 420 if ( !empty( $entry->published ) ) 421 $pubtimes = (string) $entry->published; 422 423 $pubtimes = $this->get_publish_time( $pubtimes ); 424 425 $post_date = $pubtimes[0]; 426 $post_date_gmt = $pubtimes[1]; 427 428 if ( isset( $_SERVER['HTTP_SLUG'] ) ) 429 $post_name = $_SERVER['HTTP_SLUG']; 430 431 $post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'post_name'); 432 433 $this->escape($post_data); 434 435 $postID = wp_insert_post($post_data); 436 if ( is_wp_error( $postID ) ) 437 $this->internal_error($postID->get_error_message()); 438 439 if ( !$postID ) 440 $this->internal_error(__('Sorry, your entry could not be posted. Something wrong happened.')); 441 442 // getting warning here about unable to set headers 443 // because something in the cache is printing to the buffer 444 // could we clean up wp_set_post_categories or cache to not print 445 // this could affect our ability to send back the right headers 446 @wp_set_post_categories($postID, $post_category); 447 448 do_action( 'atompub_create_post', $postID, $entry ); 449 450 $output = $this->get_entry($postID); 451 452 $this->created($postID, $output); 453 } 454 455 /** 456 * Retrieve post. 457 * 458 * @since 2.2.0 459 * 460 * @param int $postID Post ID. 461 */ 462 function get_post($postID) { 463 global $entry; 464 465 if ( !current_user_can( 'edit_post', $postID ) ) 466 $this->auth_required( __( 'Sorry, you do not have the right to access this post.' ) ); 467 468 $this->set_current_entry($postID); 469 $output = $this->get_entry($postID); 470 $this->output($output); 471 472 } 473 474 /** 475 * Update post. 476 * 477 * @since 2.2.0 478 * 479 * @param int $postID Post ID. 480 */ 481 function put_post($postID) { 482 // checked for valid content-types (atom+xml) 483 // quick check and exit 484 $this->get_accepted_content_type($this->atom_content_types); 485 486 $parser = new AtomParser(); 487 if ( !$parser->parse() ) 488 $this->bad_request(); 489 490 $parsed = array_pop($parser->feed->entries); 491 492 // check for not found 493 global $entry; 494 $this->set_current_entry($postID); 495 496 if ( !current_user_can('edit_post', $entry['ID']) ) 497 $this->auth_required(__('Sorry, you do not have the right to edit this post.')); 498 499 $publish = ! ( isset($parsed->draft) && 'yes' == trim($parsed->draft) ); 500 $post_status = ($publish) ? 'publish' : 'draft'; 501 502 extract($entry); 503 504 $post_title = $parsed->title[1]; 505 $post_content = $parsed->content[1]; 506 $post_excerpt = $parsed->summary[1]; 507 $pubtimes = $this->get_publish_time($entry->published); 508 $post_date = $pubtimes[0]; 509 $post_date_gmt = $pubtimes[1]; 510 $pubtimes = $this->get_publish_time($parsed->updated); 511 $post_modified = $pubtimes[0]; 512 $post_modified_gmt = $pubtimes[1]; 513 514 $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'post_date', 'post_date_gmt', 'post_modified', 'post_modified_gmt'); 515 $this->escape($postdata); 516 517 $result = wp_update_post($postdata); 518 519 if ( !$result ) 520 $this->internal_error(__('For some strange yet very annoying reason, this post could not be edited.')); 521 522 do_action( 'atompub_put_post', $ID, $parsed ); 523 524 $this->ok(); 525 } 526 527 /** 528 * Remove post. 529 * 530 * @since 2.2.0 531 * 532 * @param int $postID Post ID. 533 */ 534 function delete_post($postID) { 535 536 // check for not found 537 global $entry; 538 $this->set_current_entry($postID); 539 540 if ( !current_user_can('edit_post', $postID) ) 541 $this->auth_required(__('Sorry, you do not have the right to delete this post.')); 542 543 if ( $entry['post_type'] == 'attachment' ) { 544 $this->delete_attachment($postID); 545 } else { 546 $result = wp_delete_post($postID); 547 548 if ( !$result ) { 549 $this->internal_error(__('For some strange yet very annoying reason, this post could not be deleted.')); 550 } 551 552 $this->ok(); 553 } 554 555 } 556 557 /** 558 * Retrieve attachment. 559 * 560 * @since 2.2.0 561 * 562 * @param int $postID Optional. Post ID. 563 */ 564 function get_attachment($postID = null) { 565 if ( !current_user_can( 'upload_files' ) ) 566 $this->auth_required( __( 'Sorry, you do not have permission to upload files.' ) ); 567 568 if ( !isset($postID) ) { 569 $this->get_attachments(); 570 } else { 571 $this->set_current_entry($postID); 572 $output = $this->get_entry($postID, 'attachment'); 573 $this->output($output); 574 } 575 } 576 577 /** 578 * Create new attachment. 579 * 580 * @since 2.2.0 581 */ 582 function create_attachment() { 583 584 $type = $this->get_accepted_content_type(); 585 586 if ( !current_user_can('upload_files') ) 587 $this->auth_required(__('You do not have permission to upload files.')); 588 589 $fp = fopen("php://input", "rb"); 590 $bits = null; 591 while ( !feof($fp) ) { 592 $bits .= fread($fp, 4096); 593 } 594 fclose($fp); 595 596 $slug = ''; 597 if ( isset( $_SERVER['HTTP_SLUG'] ) ) 598 $slug = $_SERVER['HTTP_SLUG']; 599 elseif ( isset( $_SERVER['HTTP_TITLE'] ) ) 600 $slug = $_SERVER['HTTP_TITLE']; 601 elseif ( empty( $slug ) ) // just make a random name 602 $slug = substr( md5( uniqid( microtime() ) ), 0, 7); 603 $ext = preg_replace( '|.*/([a-z0-9]+)|', '$1', $_SERVER['CONTENT_TYPE'] ); 604 $slug = sanitize_file_name( "$slug.$ext" ); 605 $file = wp_upload_bits( $slug, null, $bits); 606 607 $url = $file['url']; 608 $file = $file['file']; 609 610 do_action('wp_create_file_in_uploads', $file); // replicate 611 612 // Construct the attachment array 613 $attachment = array( 614 'post_title' => $slug, 615 'post_content' => $slug, 616 'post_status' => 'attachment', 617 'post_parent' => 0, 618 'post_mime_type' => $type, 619 'guid' => $url 620 ); 621 622 // Save the data 623 $postID = wp_insert_attachment($attachment, $file); 624 625 if (!$postID) 626 $this->internal_error(__('Sorry, your entry could not be posted. Something wrong happened.')); 627 628 $output = $this->get_entry($postID, 'attachment'); 629 630 $this->created($postID, $output, 'attachment'); 631 } 632 633 /** 634 * Update attachment. 635 * 636 * @since 2.2.0 637 * 638 * @param int $postID Post ID. 639 */ 640 function put_attachment($postID) { 641 // checked for valid content-types (atom+xml) 642 // quick check and exit 643 $this->get_accepted_content_type($this->atom_content_types); 644 645 $parser = new AtomParser(); 646 if (!$parser->parse()) { 647 $this->bad_request(); 648 } 649 650 $parsed = array_pop($parser->feed->entries); 651 652 // check for not found 653 global $entry; 654 $this->set_current_entry($postID); 655 656 if ( !current_user_can('edit_post', $entry['ID']) ) 657 $this->auth_required(__('Sorry, you do not have the right to edit this post.')); 658 659 extract($entry); 660 661 $post_title = $parsed->title[1]; 662 $post_content = $parsed->summary[1]; 663 $pubtimes = $this->get_publish_time($parsed->updated); 664 $post_modified = $pubtimes[0]; 665 $post_modified_gmt = $pubtimes[1]; 666 667 $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'post_modified', 'post_modified_gmt'); 668 $this->escape($postdata); 669 670 $result = wp_update_post($postdata); 671 672 if ( !$result ) 673 $this->internal_error(__('For some strange yet very annoying reason, this post could not be edited.')); 674 675 $this->ok(); 676 } 677 678 /** 679 * Remove attachment. 680 * 681 * @since 2.2.0 682 * 683 * @param int $postID Post ID. 684 */ 685 function delete_attachment($postID) { 686 // check for not found 687 global $entry; 688 $this->set_current_entry($postID); 689 690 if ( !current_user_can('edit_post', $postID) ) 691 $this->auth_required(__('Sorry, you do not have the right to delete this post.')); 692 693 $location = get_post_meta($entry['ID'], '_wp_attached_file', true); 694 $filetype = wp_check_filetype($location); 695 696 if ( !isset($location) || 'attachment' != $entry['post_type'] || empty($filetype['ext']) ) 697 $this->internal_error(__('Error occurred while accessing post metadata for file location.')); 698 699 // delete file 700 @unlink($location); 701 702 // delete attachment 703 $result = wp_delete_post($postID); 704 705 if ( !$result ) 706 $this->internal_error(__('For some strange yet very annoying reason, this post could not be deleted.')); 707 708 $this->ok(); 709 } 710 711 /** 712 * Retrieve attachment from post. 713 * 714 * @since 2.2.0 715 * 716 * @param int $postID Post ID. 717 */ 718 function get_file($postID) { 719 720 // check for not found 721 global $entry; 722 $this->set_current_entry($postID); 723 724 // then whether user can edit the specific post 725 if ( !current_user_can('edit_post', $postID) ) 726 $this->auth_required(__('Sorry, you do not have the right to edit this post.')); 727 728 $location = get_post_meta($entry['ID'], '_wp_attached_file', true); 729 $location = get_option ('upload_path') . '/' . $location; 730 $filetype = wp_check_filetype($location); 731 732 if ( !isset($location) || 'attachment' != $entry['post_type'] || empty($filetype['ext']) ) 733 $this->internal_error(__('Error occurred while accessing post metadata for file location.')); 734 735 status_header('200'); 736 header('Content-Type: ' . $entry['post_mime_type']); 737 header('Connection: close'); 738 739 if ( $fp = fopen($location, "rb") ) { 740 status_header('200'); 741 header('Content-Type: ' . $entry['post_mime_type']); 742 header('Connection: close'); 743 744 while ( !feof($fp) ) { 745 echo fread($fp, 4096); 746 } 747 748 fclose($fp); 749 } else { 750 status_header ('404'); 751 } 752 753 exit; 754 } 755 756 /** 757 * Upload file to blog and add attachment to post. 758 * 759 * @since 2.2.0 760 * 761 * @param int $postID Post ID. 762 */ 763 function put_file($postID) { 764 765 // first check if user can upload 766 if ( !current_user_can('upload_files') ) 767 $this->auth_required(__('You do not have permission to upload files.')); 768 769 // check for not found 770 global $entry; 771 $this->set_current_entry($postID); 772 773 // then whether user can edit the specific post 774 if ( !current_user_can('edit_post', $postID) ) 775 $this->auth_required(__('Sorry, you do not have the right to edit this post.')); 776 777 $upload_dir = wp_upload_dir( ); 778 $location = get_post_meta($entry['ID'], '_wp_attached_file', true); 779 $filetype = wp_check_filetype($location); 780 781 $location = "{$upload_dir['basedir']}/{$location}"; 782 783 if (!isset($location) || 'attachment' != $entry['post_type'] || empty($filetype['ext'])) 784 $this->internal_error(__('Error occurred while accessing post metadata for file location.')); 785 786 $fp = fopen("php://input", "rb"); 787 $localfp = fopen($location, "w+"); 788 while ( !feof($fp) ) { 789 fwrite($localfp,fread($fp, 4096)); 790 } 791 fclose($fp); 792 fclose($localfp); 793 794 $ID = $entry['ID']; 795 $pubtimes = $this->get_publish_time($entry->published); 796 $post_date = $pubtimes[0]; 797 $post_date_gmt = $pubtimes[1]; 798 $pubtimes = $this->get_publish_time($parsed->updated); 799 $post_modified = $pubtimes[0]; 800 $post_modified_gmt = $pubtimes[1]; 801 802 $post_data = compact('ID', 'post_date', 'post_date_gmt', 'post_modified', 'post_modified_gmt'); 803 $result = wp_update_post($post_data); 804 805 if ( !$result ) 806 $this->internal_error(__('Sorry, your entry could not be posted. Something wrong happened.')); 807 808 wp_update_attachment_metadata( $postID, wp_generate_attachment_metadata( $postID, $location ) ); 809 810 $this->ok(); 811 } 812 813 /** 814 * Retrieve entries URL. 815 * 816 * @since 2.2.0 817 * 818 * @param int $page Page ID. 819 * @return string 820 */ 821 function get_entries_url($page = null) { 822 if ( isset($GLOBALS['post_type']) && ( $GLOBALS['post_type'] == 'attachment' ) ) 823 $path = $this->MEDIA_PATH; 824 else 825 $path = $this->ENTRIES_PATH; 826 $url = $this->app_base . $path; 827 if ( isset($page) && is_int($page) ) 828 $url .= "/$page"; 829 return $url; 830 } 831 832 /** 833 * Display entries URL. 834 * 835 * @since 2.2.0 836 * 837 * @param int $page Page ID. 838 */ 839 function the_entries_url($page = null) { 840 echo $this->get_entries_url($page); 841 } 842 843 /** 844 * Retrieve categories URL. 845 * 846 * @since 2.2.0 847 * 848 * @param mixed $deprecated Not used. 849 * @return string 850 */ 851 function get_categories_url($deprecated = '') { 852 if ( !empty( $deprecated ) ) 853 _deprecated_argument( __FUNCTION__, '2.5' ); 854 return $this->app_base . $this->CATEGORIES_PATH; 855 } 856 857 /** 858 * Display category URL. 859 * 860 * @since 2.2.0 861 */ 862 function the_categories_url() { 863 echo $this->get_categories_url(); 864 } 865 866 /** 867 * Retrieve attachment URL. 868 * 869 * @since 2.2.0 870 * 871 * @param int $page Page ID. 872 * @return string 873 */ 874 function get_attachments_url($page = null) { 875 $url = $this->app_base . $this->MEDIA_PATH; 876 if (isset($page) && is_int($page)) { 877 $url .= "/$page"; 878 } 879 return $url; 880 } 881 882 /** 883 * Display attachment URL. 884 * 885 * @since 2.2.0 886 * 887 * @param int $page Page ID. 888 */ 889 function the_attachments_url($page = null) { 890 echo $this->get_attachments_url($page); 891 } 892 893 /** 894 * Retrieve service URL. 895 * 896 * @since 2.3.0 897 * 898 * @return string 899 */ 900 function get_service_url() { 901 return $this->app_base . $this->SERVICE_PATH; 902 } 903 904 /** 905 * Retrieve entry URL. 906 * 907 * @since 2.7.0 908 * 909 * @param int $postID Post ID. 910 * @return string 911 */ 912 function get_entry_url($postID = null) { 913 if (!isset($postID)) { 914 global $post; 915 $postID = (int) $post->ID; 916 } 917 918 $url = $this->app_base . $this->ENTRY_PATH . "/$postID"; 919 920 return $url; 921 } 922 923 /** 924 * Display entry URL. 925 * 926 * @since 2.7.0 927 * 928 * @param int $postID Post ID. 929 */ 930 function the_entry_url($postID = null) { 931 echo $this->get_entry_url($postID); 932 } 933 934 /** 935 * Retrieve media URL. 936 * 937 * @since 2.2.0 938 * 939 * @param int $postID Post ID. 940 * @return string 941 */ 942 function get_media_url($postID = null) { 943 if (!isset($postID)) { 944 global $post; 945 $postID = (int) $post->ID; 946 } 947 948 $url = $this->app_base . $this->MEDIA_SINGLE_PATH ."/file/$postID"; 949 950 return $url; 951 } 952 953 /** 954 * Display the media URL. 955 * 956 * @since 2.2.0 957 * 958 * @param int $postID Post ID. 959 */ 960 function the_media_url($postID = null) { 961 echo $this->get_media_url($postID); 962 } 963 964 /** 965 * Set the current entry to post ID. 966 * 967 * @since 2.2.0 968 * 969 * @param int $postID Post ID. 970 */ 971 function set_current_entry($postID) { 972 global $entry; 973 974 if (!isset($postID)) { 975 // $this->bad_request(); 976 $this->not_found(); 977 } 978 979 $entry = wp_get_single_post($postID,ARRAY_A); 980 981 if (!isset($entry) || !isset($entry['ID'])) 982 $this->not_found(); 983 984 return; 985 } 986 987 /** 988 * Display posts XML. 989 * 990 * @since 2.2.0 991 * 992 * @param int $page Optional. Page ID. 993 * @param string $post_type Optional, default is 'post'. Post Type. 994 */ 995 function get_posts($page = 1, $post_type = 'post') { 996 $feed = $this->get_feed($page, $post_type); 997 $this->output($feed); 998 } 999 1000 /** 1001 * Display attachment XML. 1002 * 1003 * @since 2.2.0 1004 * 1005 * @param int $page Page ID. 1006 * @param string $post_type Optional, default is 'attachment'. Post type. 1007 */ 1008 function get_attachments($page = 1, $post_type = 'attachment') { 1009 $GLOBALS['post_type'] = $post_type; 1010 $feed = $this->get_feed($page, $post_type); 1011 $this->output($feed); 1012 } 1013 1014 /** 1015 * Retrieve feed XML. 1016 * 1017 * @since 2.2.0 1018 * 1019 * @param int $page Page ID. 1020 * @param string $post_type Optional, default is post. Post type. 1021 * @return string 1022 */ 1023 function get_feed($page = 1, $post_type = 'post') { 1024 global $post, $wp, $wp_query, $posts, $wpdb, $blog_id; 1025 ob_start(); 1026 1027 $this->ENTRY_PATH = $post_type; 1028 1029 if (!isset($page)) { 1030 $page = 1; 1031 } 1032 $page = (int) $page; 1033 1034 $count = get_option('posts_per_rss'); 1035 1036 wp('posts_per_page=' . $count . '&offset=' . ($count * ($page-1) . '&orderby=modified')); 1037 1038 $post = $GLOBALS['post']; 1039 $posts = $GLOBALS['posts']; 1040 $wp = $GLOBALS['wp']; 1041 $wp_query = $GLOBALS['wp_query']; 1042 $wpdb = $GLOBALS['wpdb']; 1043 $blog_id = (int) $GLOBALS['blog_id']; 1044 1045 $last_page = $wp_query->max_num_pages; 1046 $next_page = (($page + 1) > $last_page) ? null : $page + 1; 1047 $prev_page = ($page - 1) < 1 ? null : $page - 1; 1048 $last_page = ((int)$last_page == 1 || (int)$last_page == 0) ? null : (int) $last_page; 1049 $self_page = $page > 1 ? $page : null; 1050 ?><feed xmlns="<?php echo $this->ATOM_NS ?>" xmlns:app="<?php echo $this->ATOMPUB_NS ?>" xml:lang="<?php bloginfo_rss( 'language' ); ?>" <?php do_action('app_ns'); ?> > 1051 <id><?php $this->the_entries_url() ?></id> 1052 <updated><?php echo mysql2date('Y-m-d\TH:i:s\Z', get_lastpostmodified('GMT'), false); ?></updated> 1053 <title type="text"><?php bloginfo_rss('name') ?></title> 1054 <subtitle type="text"><?php bloginfo_rss("description") ?></subtitle> 1055 <link rel="first" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url() ?>" /> 1056 <?php if (isset($prev_page)): ?> 1057 <link rel="previous" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url($prev_page) ?>" /> 1058 <?php endif; ?> 1059 <?php if (isset($next_page)): ?> 1060 <link rel="next" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url($next_page) ?>" /> 1061 <?php endif; ?> 1062 <link rel="last" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url($last_page) ?>" /> 1063 <link rel="self" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url($self_page) ?>" /> 1064 <rights type="text">Copyright <?php echo date('Y'); ?></rights> 1065 <?php do_action('app_head'); ?> 1066 <?php if ( have_posts() ) { 1067 while ( have_posts() ) { 1068 the_post(); 1069 $this->echo_entry(); 1070 } 1071 } 1072 ?></feed> 1073 <?php 1074 $feed = ob_get_contents(); 1075 ob_end_clean(); 1076 return $feed; 1077 } 1078 1079 /** 1080 * Display entry XML. 1081 * 1082 * @since 2.2.0 1083 * 1084 * @param int $postID Post ID. 1085 * @param string $post_type Optional, default is post. Post type. 1086 * @return string. 1087 */ 1088 function get_entry($postID, $post_type = 'post') { 1089 ob_start(); 1090 switch($post_type) { 1091 case 'post': 1092 $varname = 'p'; 1093 break; 1094 case 'attachment': 1095 $this->ENTRY_PATH = 'attachment'; 1096 $varname = 'attachment_id'; 1097 break; 1098 } 1099 query_posts($varname . '=' . $postID); 1100 if ( have_posts() ) { 1101 while ( have_posts() ) { 1102 the_post(); 1103 $this->echo_entry(); 1104 $entry = ob_get_contents(); 1105 break; 1106 } 1107 } 1108 ob_end_clean(); 1109 1110 return $entry; 1111 } 1112 1113 /** 1114 * Display post content XML. 1115 * 1116 * @since 2.3.0 1117 */ 1118 function echo_entry() { ?> 1119 <entry xmlns="<?php echo $this->ATOM_NS ?>" 1120 xmlns:app="<?php echo $this->ATOMPUB_NS ?>" xml:lang="<?php bloginfo_rss( 'language' ); ?>"> 1121 <id><?php the_guid( $GLOBALS['post']->ID ); ?></id> 1122 <?php list($content_type, $content) = prep_atom_text_construct(get_the_title()); ?> 1123 <title type="<?php echo $content_type ?>"><?php echo $content ?></title> 1124 <updated><?php echo get_post_modified_time('Y-m-d\TH:i:s\Z', true); ?></updated> 1125 <published><?php echo get_post_time('Y-m-d\TH:i:s\Z', true); ?></published> 1126 <app:edited><?php echo get_post_modified_time('Y-m-d\TH:i:s\Z', true); ?></app:edited> 1127 <app:control> 1128 <app:draft><?php echo ($GLOBALS['post']->post_status == 'draft' ? 'yes' : 'no') ?></app:draft> 1129 </app:control> 1130 <author> 1131 <name><?php the_author()?></name> 1132 <?php if ( get_the_author_meta('url') && get_the_author_meta('url') != 'http://' ) { ?> 1133 <uri><?php the_author_meta('url') ?></uri> 1134 <?php } ?> 1135 </author> 1136 <?php if ($GLOBALS['post']->post_type == 'attachment') { ?> 1137 <link rel="edit-media" href="<?php $this->the_media_url() ?>" /> 1138 <content type="<?php echo $GLOBALS['post']->post_mime_type ?>" src="<?php the_guid() ; ?>"/> 1139 <?php } else { ?> 1140 <link href="<?php the_permalink_rss() ?>" /> 1141 <?php if ( strlen( $GLOBALS['post']->post_content ) ) : 1142 list($content_type, $content) = prep_atom_text_construct(get_the_content()); ?> 1143 <content type="<?php echo $content_type ?>"><?php echo $content ?></content> 1144 <?php endif; ?> 1145 <?php } ?> 1146 <link rel="edit" href="<?php $this->the_entry_url() ?>" /> 1147 <?php the_category_rss( 'atom' ); ?> 1148 <?php list($content_type, $content) = prep_atom_text_construct(get_the_excerpt()); ?> 1149 <summary type="<?php echo $content_type ?>"><?php echo $content ?></summary> 1150 <?php do_action('app_entry'); ?> 1151 </entry> 1152 <?php } 1153 1154 /** 1155 * Set 'OK' (200) status header. 1156 * 1157 * @since 2.2.0 1158 */ 1159 function ok() { 1160 header('Content-Type: text/plain'); 1161 status_header('200'); 1162 exit; 1163 } 1164 1165 /** 1166 * Set 'No Content' (204) status header. 1167 * 1168 * @since 2.2.0 1169 */ 1170 function no_content() { 1171 header('Content-Type: text/plain'); 1172 status_header('204'); 1173 echo "Moved to Trash."; 1174 exit; 1175 } 1176 1177 /** 1178 * Display 'Internal Server Error' (500) status header. 1179 * 1180 * @since 2.2.0 1181 * 1182 * @param string $msg Optional. Status string. 1183 */ 1184 function internal_error($msg = 'Internal Server Error') { 1185 header('Content-Type: text/plain'); 1186 status_header('500'); 1187 echo $msg; 1188 exit; 1189 } 1190 1191 /** 1192 * Set 'Bad Request' (400) status header. 1193 * 1194 * @since 2.2.0 1195 */ 1196 function bad_request() { 1197 header('Content-Type: text/plain'); 1198 status_header('400'); 1199 exit; 1200 } 1201 1202 /** 1203 * Set 'Length Required' (411) status header. 1204 * 1205 * @since 2.2.0 1206 */ 1207 function length_required() { 1208 header("HTTP/1.1 411 Length Required"); 1209 header('Content-Type: text/plain'); 1210 status_header('411'); 1211 exit; 1212 } 1213 1214 /** 1215 * Set 'Unsupported Media Type' (415) status header. 1216 * 1217 * @since 2.2.0 1218 */ 1219 function invalid_media() { 1220 header("HTTP/1.1 415 Unsupported Media Type"); 1221 header('Content-Type: text/plain'); 1222 exit; 1223 } 1224 1225 /** 1226 * Set 'Forbidden' (403) status header. 1227 * 1228 * @since 2.6.0 1229 */ 1230 function forbidden($reason='') { 1231 header('Content-Type: text/plain'); 1232 status_header('403'); 1233 echo $reason; 1234 exit; 1235 } 1236 1237 /** 1238 * Set 'Not Found' (404) status header. 1239 * 1240 * @since 2.2.0 1241 */ 1242 function not_found() { 1243 header('Content-Type: text/plain'); 1244 status_header('404'); 1245 exit; 1246 } 1247 1248 /** 1249 * Set 'Not Allowed' (405) status header. 1250 * 1251 * @since 2.2.0 1252 */ 1253 function not_allowed($allow) { 1254 header('Allow: ' . join(',', $allow)); 1255 status_header('405'); 1256 exit; 1257 } 1258 1259 /** 1260 * Display Redirect (302) content and set status headers. 1261 * 1262 * @since 2.3.0 1263 */ 1264 function redirect($url) { 1265 $escaped_url = esc_attr($url); 1266 $content = <<<EOD 1267 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> 1268 <html> 1269 <head> 1270 <title>302 Found</title> 1271 </head> 1272 <body> 1273 <h1>Found</h1> 1274 <p>The document has moved <a href="$escaped_url">here</a>.</p> 1275 </body> 1276 </html> 1277 1278 EOD; 1279 header('HTTP/1.1 302 Moved'); 1280 header('Content-Type: text/html'); 1281 header('Location: ' . $url); 1282 echo $content; 1283 exit; 1284 1285 } 1286 1287 /** 1288 * Set 'Client Error' (400) status header. 1289 * 1290 * @since 2.2.0 1291 */ 1292 function client_error($msg = 'Client Error') { 1293 header('Content-Type: text/plain'); 1294 status_header('400'); 1295 exit; 1296 } 1297 1298 /** 1299 * Set created status headers (201). 1300 * 1301 * Sets the 'content-type', 'content-location', and 'location'. 1302 * 1303 * @since 2.2.0 1304 */ 1305 function created($post_ID, $content, $post_type = 'post') { 1306 $edit = $this->get_entry_url($post_ID); 1307 switch($post_type) { 1308 case 'post': 1309 $ctloc = $this->get_entry_url($post_ID); 1310 break; 1311 case 'attachment': 1312 $edit = $this->app_base . "attachments/$post_ID"; 1313 break; 1314 } 1315 header("Content-Type: $this->ATOM_CONTENT_TYPE"); 1316 if (isset($ctloc)) 1317 header('Content-Location: ' . $ctloc); 1318 header('Location: ' . $edit); 1319 status_header('201'); 1320 echo $content; 1321 exit; 1322 } 1323 1324 /** 1325 * Set 'Auth Required' (401) headers. 1326 * 1327 * @since 2.2.0 1328 * 1329 * @param string $msg Status header content and HTML content. 1330 */ 1331 function auth_required($msg) { 1332 nocache_headers(); 1333 header('WWW-Authenticate: Basic realm="WordPress Atom Protocol"'); 1334 header("HTTP/1.1 401 $msg"); 1335 header('Status: 401 ' . $msg); 1336 header('Content-Type: text/html'); 1337 $content = <<<EOD 1338 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> 1339 <html> 1340 <head> 1341 <title>401 Unauthorized</title> 1342 </head> 1343 <body> 1344 <h1>401 Unauthorized</h1> 1345 <p>$msg</p> 1346 </body> 1347 </html> 1348 1349 EOD; 1350 echo $content; 1351 exit; 1352 } 1353 1354 /** 1355 * Display XML and set headers with content type. 1356 * 1357 * @since 2.2.0 1358 * 1359 * @param string $xml Display feed content. 1360 * @param string $ctype Optional, default is 'atom+xml'. Feed content type. 1361 */ 1362 function output($xml, $ctype = 'application/atom+xml') { 1363 status_header('200'); 1364 $xml = '<?xml version="1.0" encoding="' . strtolower(get_option('blog_charset')) . '"?>'."\n".$xml; 1365 header('Connection: close'); 1366 header('Content-Length: '. strlen($xml)); 1367 header('Content-Type: ' . $ctype); 1368 header('Content-Disposition: attachment; filename=atom.xml'); 1369 header('Date: '. date('r')); 1370 if ($this->do_output) 1371 echo $xml; 1372 exit; 1373 } 1374 1375 /** 1376 * Sanitize content for database usage. 1377 * 1378 * @since 2.2.0 1379 * 1380 * @param array $array Sanitize array and multi-dimension array. 1381 */ 1382 function escape(&$array) { 1383 global $wpdb; 1384 1385 foreach ($array as $k => $v) { 1386 if (is_array($v)) { 1387 $this->escape($array[$k]); 1388 } else if (is_object($v)) { 1389 //skip 1390 } else { 1391 $array[$k] = $wpdb->escape($v); 1392 } 1393 } 1394 } 1395 1396 /** 1397 * Access credential through various methods and perform login. 1398 * 1399 * @since 2.2.0 1400 * 1401 * @return bool 1402 */ 1403 function authenticate() { 1404 // if using mod_rewrite/ENV hack 1405 // http://www.besthostratings.com/articles/http-auth-php-cgi.html 1406 if (isset($_SERVER['HTTP_AUTHORIZATION'])) { 1407 list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = 1408 explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6))); 1409 } else if (isset($_SERVER['REDIRECT_REMOTE_USER'])) { 1410 // Workaround for setups that do not forward HTTP_AUTHORIZATION 1411 // See http://trac.wordpress.org/ticket/7361 1412 list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = 1413 explode(':', base64_decode(substr($_SERVER['REDIRECT_REMOTE_USER'], 6))); 1414 } 1415 1416 // If Basic Auth is working... 1417 if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) { 1418 $user = wp_authenticate($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']); 1419 if ( $user && !is_wp_error($user) ) { 1420 wp_set_current_user($user->ID); 1421 return true; 1422 } 1423 } 1424 1425 return false; 1426 } 1427 1428 /** 1429 * Retrieve accepted content types. 1430 * 1431 * @since 2.2.0 1432 * 1433 * @param array $types Optional. Content Types. 1434 * @return string 1435 */ 1436 function get_accepted_content_type($types = null) { 1437 1438 if (!isset($types)) { 1439 $types = $this->media_content_types; 1440 } 1441 1442 if (!isset($_SERVER['CONTENT_LENGTH']) || !isset($_SERVER['CONTENT_TYPE'])) { 1443 $this->length_required(); 1444 } 1445 1446 $type = $_SERVER['CONTENT_TYPE']; 1447 list($type,$subtype) = explode('/',$type); 1448 list($subtype) = explode(";",$subtype); // strip MIME parameters 1449 1450 foreach($types as $t) { 1451 list($acceptedType,$acceptedSubtype) = explode('/',$t); 1452 if ($acceptedType == '*' || $acceptedType == $type) { 1453 if ($acceptedSubtype == '*' || $acceptedSubtype == $subtype) 1454 return $type . "/" . $subtype; 1455 } 1456 } 1457 1458 $this->invalid_media(); 1459 } 1460 1461 /** 1462 * Process conditionals for posts. 1463 * 1464 * @since 2.2.0 1465 */ 1466 function process_conditionals() { 1467 1468 if (empty($this->params)) return; 1469 if ($_SERVER['REQUEST_METHOD'] == 'DELETE') return; 1470 1471 switch($this->params[0]) { 1472 case $this->ENTRY_PATH: 1473 global $post; 1474 $post = wp_get_single_post($this->params[1]); 1475 $wp_last_modified = get_post_modified_time('D, d M Y H:i:s', true); 1476 $post = null; 1477 break; 1478 case $this->ENTRIES_PATH: 1479 $wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastpostmodified('GMT'), 0).' GMT'; 1480 break; 1481 default: 1482 return; 1483 } 1484 $wp_etag = md5($wp_last_modified); 1485 @header("Last-Modified: $wp_last_modified"); 1486 @header("ETag: $wp_etag"); 1487 1488 // Support for Conditional GET 1489 if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) 1490 $client_etag = stripslashes($_SERVER['HTTP_IF_NONE_MATCH']); 1491 else 1492 $client_etag = false; 1493 1494 $client_last_modified = trim( $_SERVER['HTTP_IF_MODIFIED_SINCE']); 1495 // If string is empty, return 0. If not, attempt to parse into a timestamp 1496 $client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0; 1497 1498 // Make a timestamp for our most recent modification... 1499 $wp_modified_timestamp = strtotime($wp_last_modified); 1500 1501 if ( ($client_last_modified && $client_etag) ? 1502 (($client_modified_timestamp >= $wp_modified_timestamp) && ($client_etag == $wp_etag)) : 1503 (($client_modified_timestamp >= $wp_modified_timestamp) || ($client_etag == $wp_etag)) ) { 1504 status_header( 304 ); 1505 exit; 1506 } 1507 } 1508 1509 /** 1510 * Convert RFC3339 time string to timestamp. 1511 * 1512 * @since 2.3.0 1513 * 1514 * @param string $str String to time. 1515 * @return bool|int false if format is incorrect. 1516 */ 1517 function rfc3339_str2time($str) { 1518 1519 $match = false; 1520 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)) 1521 return false; 1522 1523 if ($match[3] == 'Z') 1524 $match[3] = '+0000'; 1525 1526 return strtotime($match[1] . " " . $match[2] . " " . $match[3]); 1527 } 1528 1529 /** 1530 * Retrieve published time to display in XML. 1531 * 1532 * @since 2.3.0 1533 * 1534 * @param string $published Time string. 1535 * @return string 1536 */ 1537 function get_publish_time($published) { 1538 1539 $pubtime = $this->rfc3339_str2time($published); 1540 1541 if (!$pubtime) { 1542 return array(current_time('mysql'),current_time('mysql',1)); 1543 } else { 1544 return array(date("Y-m-d H:i:s", $pubtime), gmdate("Y-m-d H:i:s", $pubtime)); 1545 } 1546 } 1547 1548 } 1549 1550 /** 1551 * AtomServer 1552 * @var AtomServer 1553 * @global object $server 1554 */ 1555 $server = new AtomServer(); 1556 $server->handle_request(); 50 // Handle the request 51 $wp_atom_server->handle_request(); -
trunk/wp-includes/class-wp-atom-server.php
r20059 r20062 1 1 <?php 2 /**3 * Atom Publishing Protocol support for WordPress4 *5 * @version 1.0.5-dc6 */7 8 /**9 * WordPress is handling an Atom Publishing Protocol request.10 *11 * @var bool12 */13 define('APP_REQUEST', true);14 15 /** Set up WordPress environment */16 require_once('./wp-load.php');17 18 /** Atom Publishing Protocol Class */19 require_once(ABSPATH . WPINC . '/atomlib.php');20 21 /** Admin Image API for metadata updating */22 require_once(ABSPATH . '/wp-admin/includes/image.php');23 24 $_SERVER['PATH_INFO'] = preg_replace( '/.*\/wp-app\.php/', '', $_SERVER['REQUEST_URI'] );25 26 /**27 * Whether to always authenticate user. Permanently set to true.28 *29 * @name always_authenticate30 * @var int|bool31 * @todo Should be an option somewhere32 */33 $always_authenticate = 1;34 35 /**36 * Writes logging info to a file.37 *38 * @since 2.2.039 * @deprecated 3.4.040 * @deprecated Use error_log()41 * @link http://www.php.net/manual/en/function.error-log.php42 *43 * @param string $label Type of logging44 * @param string $msg Information describing logging reason.45 */46 function log_app( $label, $msg ) {47 _deprecated_function( __FUNCTION__, '3.4', 'error_log()' );48 if ( ! empty( $GLOBALS['app_logging'] ) )49 error_log( $label . ' - ' . $message );50 }51 52 /**53 * Filter to add more post statuses.54 *55 * @since 2.2.056 *57 * @param string $where SQL statement to filter.58 * @return string Filtered SQL statement with added post_status for where clause.59 */60 function wa_posts_where_include_drafts_filter($where) {61 $where = str_replace("post_status = 'publish'","post_status = 'publish' OR post_status = 'future' OR post_status = 'draft' OR post_status = 'inherit'", $where);62 return $where;63 64 }65 add_filter('posts_where', 'wa_posts_where_include_drafts_filter');66 2 67 3 /** … … 72 8 * @since 2.2.0 73 9 */ 74 class AtomServer {10 class wp_atom_server { 75 11 76 12 /** … … 240 176 'DELETE' => 'delete_attachment'), 241 177 ); 178 179 add_filter( 'wp_die_handler', array( $this, 'return_atom_die_handler' ) ); 180 } 181 182 /** 183 * Override die handler 184 * @return callback 185 */ 186 public function return_atom_die_handler() { 187 return array( $this, 'atom_die_handler' ); 188 } 189 190 /** 191 * Die with a message. Only accept strings, no WP_Error objects yet 192 * @param string $message 193 * @return void 194 */ 195 public function atom_die_handler( $message ) { 196 if ( is_scalar( $message ) ) 197 die( (string) $message ); 198 die(); 242 199 } 243 200 … … 248 205 */ 249 206 function handle_request() { 250 global $always_authenticate;251 207 252 208 if ( !empty( $_SERVER['ORIG_PATH_INFO'] ) ) … … 282 238 // user. each handler will decide if auth is required or not. 283 239 if ( !$this->authenticate() ) { 284 if ( $always_authenticate ) 285 $this->auth_required('Credentials required.'); 240 $this->auth_required('Credentials required.'); 286 241 } 287 242 288 243 array_shift($matches); 289 call_user_func_array(array( &$this,$funcs[$method]), $matches);290 exit();244 call_user_func_array(array($this,$funcs[$method]), $matches); 245 wp_die(); 291 246 } else { 292 247 // only allow what we have handlers for... … … 306 261 */ 307 262 function get_service() { 263 308 264 if ( !current_user_can( 'edit_posts' ) ) 309 265 $this->auth_required( __( 'Sorry, you do not have the right to access this site.' ) ); … … 345 301 */ 346 302 function get_categories_xml() { 303 347 304 if ( !current_user_can( 'edit_posts' ) ) 348 305 $this->auth_required( __( 'Sorry, you do not have the right to access this site.' ) ); … … 411 368 $post_excerpt = ''; 412 369 $pubtimes = ''; 413 370 414 371 if ( isset( $entry->title ) && is_array( $entry->title ) && !empty( $entry->title[1] ) ) 415 372 $post_title = (string) $entry->title[1]; … … 420 377 if ( !empty( $entry->published ) ) 421 378 $pubtimes = (string) $entry->published; 422 379 423 380 $pubtimes = $this->get_publish_time( $pubtimes ); 424 381 … … 684 641 */ 685 642 function delete_attachment($postID) { 643 686 644 // check for not found 687 645 global $entry; … … 751 709 } 752 710 753 exit;711 wp_die(); 754 712 } 755 713 … … 994 952 */ 995 953 function get_posts($page = 1, $post_type = 'post') { 996 $feed = $this->get_feed($page, $post_type);997 $this->output($feed);954 $feed = $this->get_feed($page, $post_type); 955 $this->output($feed); 998 956 } 999 957 … … 1034 992 $count = get_option('posts_per_rss'); 1035 993 1036 wp('posts_per_page=' . $count . '&offset=' . ($count * ($page-1) . '&orderby=modified'));994 wp('posts_per_page=' . $count . '&offset=' . ($count * ($page-1)) . '&orderby=modified&post_status=any'); 1037 995 1038 996 $post = $GLOBALS['post']; … … 1160 1118 header('Content-Type: text/plain'); 1161 1119 status_header('200'); 1162 exit;1120 wp_die(); 1163 1121 } 1164 1122 … … 1172 1130 status_header('204'); 1173 1131 echo "Moved to Trash."; 1174 exit;1132 wp_die(); 1175 1133 } 1176 1134 … … 1186 1144 status_header('500'); 1187 1145 echo $msg; 1188 exit;1146 wp_die(); 1189 1147 } 1190 1148 … … 1197 1155 header('Content-Type: text/plain'); 1198 1156 status_header('400'); 1199 exit;1157 wp_die(); 1200 1158 } 1201 1159 … … 1209 1167 header('Content-Type: text/plain'); 1210 1168 status_header('411'); 1211 exit;1169 wp_die(); 1212 1170 } 1213 1171 … … 1220 1178 header("HTTP/1.1 415 Unsupported Media Type"); 1221 1179 header('Content-Type: text/plain'); 1222 exit;1180 wp_die(); 1223 1181 } 1224 1182 … … 1232 1190 status_header('403'); 1233 1191 echo $reason; 1234 exit;1192 wp_die(); 1235 1193 } 1236 1194 … … 1243 1201 header('Content-Type: text/plain'); 1244 1202 status_header('404'); 1245 exit;1203 wp_die(); 1246 1204 } 1247 1205 … … 1254 1212 header('Allow: ' . join(',', $allow)); 1255 1213 status_header('405'); 1256 exit;1214 wp_die(); 1257 1215 } 1258 1216 … … 1281 1239 header('Location: ' . $url); 1282 1240 echo $content; 1283 exit;1241 wp_die(); 1284 1242 1285 1243 } … … 1293 1251 header('Content-Type: text/plain'); 1294 1252 status_header('400'); 1295 exit;1253 wp_die(); 1296 1254 } 1297 1255 … … 1319 1277 status_header('201'); 1320 1278 echo $content; 1321 exit;1279 wp_die(); 1322 1280 } 1323 1281 … … 1349 1307 EOD; 1350 1308 echo $content; 1351 exit;1309 wp_die(); 1352 1310 } 1353 1311 … … 1361 1319 */ 1362 1320 function output($xml, $ctype = 'application/atom+xml') { 1363 status_header('200');1364 $xml = '<?xml version="1.0" encoding="' . strtolower(get_option('blog_charset')) . '"?>'."\n".$xml;1365 header('Connection: close');1366 header('Content-Length: '. strlen($xml));1367 header('Content-Type: ' . $ctype);1368 header('Content-Disposition: attachment; filename=atom.xml');1369 header('Date: '. date('r'));1370 if ($this->do_output)1371 echo $xml;1372 exit;1321 status_header('200'); 1322 $xml = '<?xml version="1.0" encoding="' . strtolower(get_option('blog_charset')) . '"?>'."\n".$xml; 1323 header('Connection: close'); 1324 header('Content-Length: '. strlen($xml)); 1325 header('Content-Type: ' . $ctype); 1326 header('Content-Disposition: attachment; filename=atom.xml'); 1327 header('Date: '. date('r')); 1328 if ($this->do_output) 1329 echo $xml; 1330 wp_die(); 1373 1331 } 1374 1332 … … 1402 1360 */ 1403 1361 function authenticate() { 1362 1404 1363 // if using mod_rewrite/ENV hack 1405 1364 // http://www.besthostratings.com/articles/http-auth-php-cgi.html … … 1416 1375 // If Basic Auth is working... 1417 1376 if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) { 1377 1418 1378 $user = wp_authenticate($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']); 1419 1379 if ( $user && !is_wp_error($user) ) { … … 1503 1463 (($client_modified_timestamp >= $wp_modified_timestamp) || ($client_etag == $wp_etag)) ) { 1504 1464 status_header( 304 ); 1505 exit;1465 wp_die(); 1506 1466 } 1507 1467 } … … 1547 1507 1548 1508 } 1549 1550 /**1551 * AtomServer1552 * @var AtomServer1553 * @global object $server1554 */1555 $server = new AtomServer();1556 $server->handle_request();
Note: See TracChangeset
for help on using the changeset viewer.