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