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