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