-
+ 3B68B68D14741223EB9B113A9DDFC3DE34A91A8A44490465A17DC825B415BD4C3691FC2A95D071E1DA89183C09D03F1AE81361CB084DD06DC8B9D44F3B05089D
mp-wp/wp-app.php
(0 . 0)(1 . 1624)
63223 <?php
63224 /**
63225 * Atom Publishing Protocol support for WordPress
63226 *
63227 * @author Original by Elias Torres <http://torrez.us/archives/2006/08/31/491/>
63228 * @author Modified by Dougal Campbell <http://dougal.gunters.org/>
63229 * @version 1.0.5-dc
63230 */
63231
63232 /**
63233 * WordPress is handling an Atom Publishing Protocol request.
63234 *
63235 * @var bool
63236 */
63237 define('APP_REQUEST', true);
63238
63239 /** Set up WordPress environment */
63240 require_once('./wp-load.php');
63241
63242 /** Post Template API */
63243 require_once(ABSPATH . WPINC . '/post-template.php');
63244
63245 /** Atom Publishing Protocol Class */
63246 require_once(ABSPATH . WPINC . '/atomlib.php');
63247
63248 /** Feed Handling API */
63249 require_once(ABSPATH . WPINC . '/feed.php');
63250
63251 $_SERVER['PATH_INFO'] = preg_replace( '/.*\/wp-app\.php/', '', $_SERVER['REQUEST_URI'] );
63252
63253 /**
63254 * Whether to enable Atom Publishing Protocol Logging.
63255 *
63256 * @name app_logging
63257 * @var int|bool
63258 */
63259 $app_logging = 0;
63260
63261 /**
63262 * Whether to always authenticate user. Permanently set to true.
63263 *
63264 * @name always_authenticate
63265 * @var int|bool
63266 * @todo Should be an option somewhere
63267 */
63268 $always_authenticate = 1;
63269
63270 /**
63271 * Writes logging info to a file.
63272 *
63273 * @since 2.2.0
63274 * @uses $app_logging
63275 * @package WordPress
63276 * @subpackage Logging
63277 *
63278 * @param string $label Type of logging
63279 * @param string $msg Information describing logging reason.
63280 */
63281 function log_app($label,$msg) {
63282 global $app_logging;
63283 if ($app_logging) {
63284 $fp = fopen( 'wp-app.log', 'a+');
63285 $date = gmdate( 'Y-m-d H:i:s' );
63286 fwrite($fp, "\n\n$date - $label\n$msg\n");
63287 fclose($fp);
63288 }
63289 }
63290
63291 if ( !function_exists('wp_set_current_user') ) :
63292 /**
63293 * @ignore
63294 */
63295 function wp_set_current_user($id, $name = '') {
63296 global $current_user;
63297
63298 if ( isset($current_user) && ($id == $current_user->ID) )
63299 return $current_user;
63300
63301 $current_user = new WP_User($id, $name);
63302
63303 return $current_user;
63304 }
63305 endif;
63306
63307 /**
63308 * Filter to add more post statuses.
63309 *
63310 * @since 2.2.0
63311 *
63312 * @param string $where SQL statement to filter.
63313 * @return string Filtered SQL statement with added post_status for where clause.
63314 */
63315 function wa_posts_where_include_drafts_filter($where) {
63316 $where = str_replace("post_status = 'publish'","post_status = 'publish' OR post_status = 'future' OR post_status = 'draft' OR post_status = 'inherit'", $where);
63317 return $where;
63318
63319 }
63320 add_filter('posts_where', 'wa_posts_where_include_drafts_filter');
63321
63322 /**
63323 * WordPress AtomPub API implementation.
63324 *
63325 * @package WordPress
63326 * @subpackage Publishing
63327 * @since 2.2.0
63328 */
63329 class AtomServer {
63330
63331 /**
63332 * ATOM content type.
63333 *
63334 * @since 2.2.0
63335 * @var string
63336 */
63337 var $ATOM_CONTENT_TYPE = 'application/atom+xml';
63338
63339 /**
63340 * Categories ATOM content type.
63341 *
63342 * @since 2.2.0
63343 * @var string
63344 */
63345 var $CATEGORIES_CONTENT_TYPE = 'application/atomcat+xml';
63346
63347 /**
63348 * Service ATOM content type.
63349 *
63350 * @since 2.3.0
63351 * @var string
63352 */
63353 var $SERVICE_CONTENT_TYPE = 'application/atomsvc+xml';
63354
63355 /**
63356 * ATOM XML namespace.
63357 *
63358 * @since 2.3.0
63359 * @var string
63360 */
63361 var $ATOM_NS = 'http://www.w3.org/2005/Atom';
63362
63363 /**
63364 * ATOMPUB XML namespace.
63365 *
63366 * @since 2.3.0
63367 * @var string
63368 */
63369 var $ATOMPUB_NS = 'http://www.w3.org/2007/app';
63370
63371 /**
63372 * Entries path.
63373 *
63374 * @since 2.2.0
63375 * @var string
63376 */
63377 var $ENTRIES_PATH = "posts";
63378
63379 /**
63380 * Categories path.
63381 *
63382 * @since 2.2.0
63383 * @var string
63384 */
63385 var $CATEGORIES_PATH = "categories";
63386
63387 /**
63388 * Media path.
63389 *
63390 * @since 2.2.0
63391 * @var string
63392 */
63393 var $MEDIA_PATH = "attachments";
63394
63395 /**
63396 * Entry path.
63397 *
63398 * @since 2.2.0
63399 * @var string
63400 */
63401 var $ENTRY_PATH = "post";
63402
63403 /**
63404 * Service path.
63405 *
63406 * @since 2.2.0
63407 * @var string
63408 */
63409 var $SERVICE_PATH = "service";
63410
63411 /**
63412 * Media single path.
63413 *
63414 * @since 2.2.0
63415 * @var string
63416 */
63417 var $MEDIA_SINGLE_PATH = "attachment";
63418
63419 /**
63420 * ATOMPUB parameters.
63421 *
63422 * @since 2.2.0
63423 * @var array
63424 */
63425 var $params = array();
63426
63427 /**
63428 * Supported ATOMPUB media types.
63429 *
63430 * @since 2.3.0
63431 * @var array
63432 */
63433 var $media_content_types = array('image/*','audio/*','video/*');
63434
63435 /**
63436 * ATOMPUB content type(s).
63437 *
63438 * @since 2.2.0
63439 * @var array
63440 */
63441 var $atom_content_types = array('application/atom+xml');
63442
63443 /**
63444 * ATOMPUB methods.
63445 *
63446 * @since 2.2.0
63447 * @var unknown_type
63448 */
63449 var $selectors = array();
63450
63451 /**
63452 * Whether to do output.
63453 *
63454 * Support for head.
63455 *
63456 * @since 2.2.0
63457 * @var bool
63458 */
63459 var $do_output = true;
63460
63461 /**
63462 * PHP4 constructor - Sets up object properties.
63463 *
63464 * @since 2.2.0
63465 * @return AtomServer
63466 */
63467 function AtomServer() {
63468
63469 $this->script_name = array_pop(explode('/',$_SERVER['SCRIPT_NAME']));
63470 $this->app_base = get_bloginfo('url') . '/' . $this->script_name . '/';
63471 if ( isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ) {
63472 $this->app_base = preg_replace( '/^http:\/\//', 'https://', $this->app_base );
63473 }
63474
63475 $this->selectors = array(
63476 '@/service$@' =>
63477 array('GET' => 'get_service'),
63478 '@/categories$@' =>
63479 array('GET' => 'get_categories_xml'),
63480 '@/post/(\d+)$@' =>
63481 array('GET' => 'get_post',
63482 'PUT' => 'put_post',
63483 'DELETE' => 'delete_post'),
63484 '@/posts/?(\d+)?$@' =>
63485 array('GET' => 'get_posts',
63486 'POST' => 'create_post'),
63487 '@/attachments/?(\d+)?$@' =>
63488 array('GET' => 'get_attachment',
63489 'POST' => 'create_attachment'),
63490 '@/attachment/file/(\d+)$@' =>
63491 array('GET' => 'get_file',
63492 'PUT' => 'put_file',
63493 'DELETE' => 'delete_file'),
63494 '@/attachment/(\d+)$@' =>
63495 array('GET' => 'get_attachment',
63496 'PUT' => 'put_attachment',
63497 'DELETE' => 'delete_attachment'),
63498 );
63499 }
63500
63501 /**
63502 * Handle ATOMPUB request.
63503 *
63504 * @since 2.2.0
63505 */
63506 function handle_request() {
63507 global $always_authenticate;
63508
63509 if( !empty( $_SERVER['ORIG_PATH_INFO'] ) )
63510 $path = $_SERVER['ORIG_PATH_INFO'];
63511 else
63512 $path = $_SERVER['PATH_INFO'];
63513
63514 $method = $_SERVER['REQUEST_METHOD'];
63515
63516 log_app('REQUEST',"$method $path\n================");
63517
63518 $this->process_conditionals();
63519 //$this->process_conditionals();
63520
63521 // exception case for HEAD (treat exactly as GET, but don't output)
63522 if($method == 'HEAD') {
63523 $this->do_output = false;
63524 $method = 'GET';
63525 }
63526
63527 // redirect to /service in case no path is found.
63528 if(strlen($path) == 0 || $path == '/') {
63529 $this->redirect($this->get_service_url());
63530 }
63531
63532 // check to see if AtomPub is enabled
63533 if( !get_option( 'enable_app' ) )
63534 $this->forbidden( sprintf( __( 'AtomPub services are disabled on this blog. An admin user can enable them at %s' ), admin_url('options-writing.php') ) );
63535
63536 // dispatch
63537 foreach($this->selectors as $regex => $funcs) {
63538 if(preg_match($regex, $path, $matches)) {
63539 if(isset($funcs[$method])) {
63540
63541 // authenticate regardless of the operation and set the current
63542 // user. each handler will decide if auth is required or not.
63543 if(!$this->authenticate()) {
63544 if ($always_authenticate) {
63545 $this->auth_required('Credentials required.');
63546 }
63547 }
63548
63549 array_shift($matches);
63550 call_user_func_array(array(&$this,$funcs[$method]), $matches);
63551 exit();
63552 } else {
63553 // only allow what we have handlers for...
63554 $this->not_allowed(array_keys($funcs));
63555 }
63556 }
63557 }
63558
63559 // oops, nothing found
63560 $this->not_found();
63561 }
63562
63563 /**
63564 * Retrieve XML for ATOMPUB service.
63565 *
63566 * @since 2.2.0
63567 */
63568 function get_service() {
63569 log_app('function','get_service()');
63570
63571 if( !current_user_can( 'edit_posts' ) )
63572 $this->auth_required( __( 'Sorry, you do not have the right to access this blog.' ) );
63573
63574 $entries_url = attribute_escape($this->get_entries_url());
63575 $categories_url = attribute_escape($this->get_categories_url());
63576 $media_url = attribute_escape($this->get_attachments_url());
63577 foreach ($this->media_content_types as $med) {
63578 $accepted_media_types = $accepted_media_types . "<accept>" . $med . "</accept>";
63579 }
63580 $atom_prefix="atom";
63581 $atom_blogname=get_bloginfo('name');
63582 $service_doc = <<<EOD
63583 <service xmlns="$this->ATOMPUB_NS" xmlns:$atom_prefix="$this->ATOM_NS">
63584 <workspace>
63585 <$atom_prefix:title>$atom_blogname Workspace</$atom_prefix:title>
63586 <collection href="$entries_url">
63587 <$atom_prefix:title>$atom_blogname Posts</$atom_prefix:title>
63588 <accept>$this->ATOM_CONTENT_TYPE;type=entry</accept>
63589 <categories href="$categories_url" />
63590 </collection>
63591 <collection href="$media_url">
63592 <$atom_prefix:title>$atom_blogname Media</$atom_prefix:title>
63593 $accepted_media_types
63594 </collection>
63595 </workspace>
63596 </service>
63597
63598 EOD;
63599
63600 $this->output($service_doc, $this->SERVICE_CONTENT_TYPE);
63601 }
63602
63603 /**
63604 * Retrieve categories list in XML format.
63605 *
63606 * @since 2.2.0
63607 */
63608 function get_categories_xml() {
63609 log_app('function','get_categories_xml()');
63610
63611 if( !current_user_can( 'edit_posts' ) )
63612 $this->auth_required( __( 'Sorry, you do not have the right to access this blog.' ) );
63613
63614 $home = attribute_escape(get_bloginfo_rss('home'));
63615
63616 $categories = "";
63617 $cats = get_categories("hierarchical=0&hide_empty=0");
63618 foreach ((array) $cats as $cat) {
63619 $categories .= " <category term=\"" . attribute_escape($cat->name) . "\" />\n";
63620 }
63621 $output = <<<EOD
63622 <app:categories xmlns:app="$this->ATOMPUB_NS"
63623 xmlns="$this->ATOM_NS"
63624 fixed="yes" scheme="$home">
63625 $categories
63626 </app:categories>
63627 EOD;
63628 $this->output($output, $this->CATEGORIES_CONTENT_TYPE);
63629 }
63630
63631 /**
63632 * Create new post.
63633 *
63634 * @since 2.2.0
63635 */
63636 function create_post() {
63637 global $blog_id, $user_ID;
63638 $this->get_accepted_content_type($this->atom_content_types);
63639
63640 $parser = new AtomParser();
63641 if(!$parser->parse()) {
63642 $this->client_error();
63643 }
63644
63645 $entry = array_pop($parser->feed->entries);
63646
63647 log_app('Received entry:', print_r($entry,true));
63648
63649 $catnames = array();
63650 foreach($entry->categories as $cat)
63651 array_push($catnames, $cat["term"]);
63652
63653 $wp_cats = get_categories(array('hide_empty' => false));
63654
63655 $post_category = array();
63656
63657 foreach($wp_cats as $cat) {
63658 if(in_array($cat->name, $catnames))
63659 array_push($post_category, $cat->term_id);
63660 }
63661
63662 $publish = (isset($entry->draft) && trim($entry->draft) == 'yes') ? false : true;
63663
63664 $cap = ($publish) ? 'publish_posts' : 'edit_posts';
63665
63666 if(!current_user_can($cap))
63667 $this->auth_required(__('Sorry, you do not have the right to edit/publish new posts.'));
63668
63669 $blog_ID = (int ) $blog_id;
63670 $post_status = ($publish) ? 'publish' : 'draft';
63671 $post_author = (int) $user_ID;
63672 $post_title = $entry->title[1];
63673 $post_content = $entry->content[1];
63674 $post_excerpt = $entry->summary[1];
63675 $pubtimes = $this->get_publish_time($entry->published);
63676 $post_date = $pubtimes[0];
63677 $post_date_gmt = $pubtimes[1];
63678
63679 if ( isset( $_SERVER['HTTP_SLUG'] ) )
63680 $post_name = $_SERVER['HTTP_SLUG'];
63681
63682 $post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'post_name');
63683
63684 $this->escape($post_data);
63685 log_app('Inserting Post. Data:', print_r($post_data,true));
63686
63687 $postID = wp_insert_post($post_data);
63688 if ( is_wp_error( $postID ) )
63689 $this->internal_error($postID->get_error_message());
63690
63691 if (!$postID)
63692 $this->internal_error(__('Sorry, your entry could not be posted. Something wrong happened.'));
63693
63694 // getting warning here about unable to set headers
63695 // because something in the cache is printing to the buffer
63696 // could we clean up wp_set_post_categories or cache to not print
63697 // this could affect our ability to send back the right headers
63698 @wp_set_post_categories($postID, $post_category);
63699
63700 $output = $this->get_entry($postID);
63701
63702 log_app('function',"create_post($postID)");
63703 $this->created($postID, $output);
63704 }
63705
63706 /**
63707 * Retrieve post.
63708 *
63709 * @since 2.2.0
63710 *
63711 * @param int $postID Post ID.
63712 */
63713 function get_post($postID) {
63714 global $entry;
63715
63716 if( !current_user_can( 'edit_post', $postID ) )
63717 $this->auth_required( __( 'Sorry, you do not have the right to access this post.' ) );
63718
63719 $this->set_current_entry($postID);
63720 $output = $this->get_entry($postID);
63721 log_app('function',"get_post($postID)");
63722 $this->output($output);
63723
63724 }
63725
63726 /**
63727 * Update post.
63728 *
63729 * @since 2.2.0
63730 *
63731 * @param int $postID Post ID.
63732 */
63733 function put_post($postID) {
63734 // checked for valid content-types (atom+xml)
63735 // quick check and exit
63736 $this->get_accepted_content_type($this->atom_content_types);
63737
63738 $parser = new AtomParser();
63739 if(!$parser->parse()) {
63740 $this->bad_request();
63741 }
63742
63743 $parsed = array_pop($parser->feed->entries);
63744
63745 log_app('Received UPDATED entry:', print_r($parsed,true));
63746
63747 // check for not found
63748 global $entry;
63749 $this->set_current_entry($postID);
63750
63751 if(!current_user_can('edit_post', $entry['ID']))
63752 $this->auth_required(__('Sorry, you do not have the right to edit this post.'));
63753
63754 $publish = (isset($parsed->draft) && trim($parsed->draft) == 'yes') ? false : true;
63755 $post_status = ($publish) ? 'publish' : 'draft';
63756
63757 extract($entry);
63758
63759 $post_title = $parsed->title[1];
63760 $post_content = $parsed->content[1];
63761 $post_excerpt = $parsed->summary[1];
63762 $pubtimes = $this->get_publish_time($entry->published);
63763 $post_date = $pubtimes[0];
63764 $post_date_gmt = $pubtimes[1];
63765 $pubtimes = $this->get_publish_time($parsed->updated);
63766 $post_modified = $pubtimes[0];
63767 $post_modified_gmt = $pubtimes[1];
63768
63769 $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'post_date', 'post_date_gmt', 'post_modified', 'post_modified_gmt');
63770 $this->escape($postdata);
63771
63772 $result = wp_update_post($postdata);
63773
63774 if (!$result) {
63775 $this->internal_error(__('For some strange yet very annoying reason, this post could not be edited.'));
63776 }
63777
63778 log_app('function',"put_post($postID)");
63779 $this->ok();
63780 }
63781
63782 /**
63783 * Remove post.
63784 *
63785 * @since 2.2.0
63786 *
63787 * @param int $postID Post ID.
63788 */
63789 function delete_post($postID) {
63790
63791 // check for not found
63792 global $entry;
63793 $this->set_current_entry($postID);
63794
63795 if(!current_user_can('edit_post', $postID)) {
63796 $this->auth_required(__('Sorry, you do not have the right to delete this post.'));
63797 }
63798
63799 if ($entry['post_type'] == 'attachment') {
63800 $this->delete_attachment($postID);
63801 } else {
63802 $result = wp_delete_post($postID);
63803
63804 if (!$result) {
63805 $this->internal_error(__('For some strange yet very annoying reason, this post could not be deleted.'));
63806 }
63807
63808 log_app('function',"delete_post($postID)");
63809 $this->ok();
63810 }
63811
63812 }
63813
63814 /**
63815 * Retrieve attachment.
63816 *
63817 * @since 2.2.0
63818 *
63819 * @param int $postID Optional. Post ID.
63820 */
63821 function get_attachment($postID = null) {
63822 if( !current_user_can( 'upload_files' ) )
63823 $this->auth_required( __( 'Sorry, you do not have permission to upload files.' ) );
63824
63825 if (!isset($postID)) {
63826 $this->get_attachments();
63827 } else {
63828 $this->set_current_entry($postID);
63829 $output = $this->get_entry($postID, 'attachment');
63830 log_app('function',"get_attachment($postID)");
63831 $this->output($output);
63832 }
63833 }
63834
63835 /**
63836 * Create new attachment.
63837 *
63838 * @since 2.2.0
63839 */
63840 function create_attachment() {
63841
63842 $type = $this->get_accepted_content_type();
63843
63844 if(!current_user_can('upload_files'))
63845 $this->auth_required(__('You do not have permission to upload files.'));
63846
63847 $fp = fopen("php://input", "rb");
63848 $bits = null;
63849 while(!feof($fp)) {
63850 $bits .= fread($fp, 4096);
63851 }
63852 fclose($fp);
63853
63854 $slug = '';
63855 if ( isset( $_SERVER['HTTP_SLUG'] ) )
63856 $slug = sanitize_file_name( $_SERVER['HTTP_SLUG'] );
63857 elseif ( isset( $_SERVER['HTTP_TITLE'] ) )
63858 $slug = sanitize_file_name( $_SERVER['HTTP_TITLE'] );
63859 elseif ( empty( $slug ) ) // just make a random name
63860 $slug = substr( md5( uniqid( microtime() ) ), 0, 7);
63861 $ext = preg_replace( '|.*/([a-z0-9]+)|', '$1', $_SERVER['CONTENT_TYPE'] );
63862 $slug = "$slug.$ext";
63863 $file = wp_upload_bits( $slug, NULL, $bits);
63864
63865 log_app('wp_upload_bits returns:',print_r($file,true));
63866
63867 $url = $file['url'];
63868 $file = $file['file'];
63869
63870 do_action('wp_create_file_in_uploads', $file); // replicate
63871
63872 // Construct the attachment array
63873 $attachment = array(
63874 'post_title' => $slug,
63875 'post_content' => $slug,
63876 'post_status' => 'attachment',
63877 'post_parent' => 0,
63878 'post_mime_type' => $type,
63879 'guid' => $url
63880 );
63881
63882 // Save the data
63883 $postID = wp_insert_attachment($attachment, $file);
63884
63885 if (!$postID)
63886 $this->internal_error(__('Sorry, your entry could not be posted. Something wrong happened.'));
63887
63888 $output = $this->get_entry($postID, 'attachment');
63889
63890 $this->created($postID, $output, 'attachment');
63891 log_app('function',"create_attachment($postID)");
63892 }
63893
63894 /**
63895 * Update attachment.
63896 *
63897 * @since 2.2.0
63898 *
63899 * @param int $postID Post ID.
63900 */
63901 function put_attachment($postID) {
63902 // checked for valid content-types (atom+xml)
63903 // quick check and exit
63904 $this->get_accepted_content_type($this->atom_content_types);
63905
63906 $parser = new AtomParser();
63907 if(!$parser->parse()) {
63908 $this->bad_request();
63909 }
63910
63911 $parsed = array_pop($parser->feed->entries);
63912
63913 // check for not found
63914 global $entry;
63915 $this->set_current_entry($postID);
63916
63917 if(!current_user_can('edit_post', $entry['ID']))
63918 $this->auth_required(__('Sorry, you do not have the right to edit this post.'));
63919
63920 extract($entry);
63921
63922 $post_title = $parsed->title[1];
63923 $post_content = $parsed->content[1];
63924 $pubtimes = $this->get_publish_time($parsed->updated);
63925 $post_modified = $pubtimes[0];
63926 $post_modified_gmt = $pubtimes[1];
63927
63928 $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'post_modified', 'post_modified_gmt');
63929 $this->escape($postdata);
63930
63931 $result = wp_update_post($postdata);
63932
63933 if (!$result) {
63934 $this->internal_error(__('For some strange yet very annoying reason, this post could not be edited.'));
63935 }
63936
63937 log_app('function',"put_attachment($postID)");
63938 $this->ok();
63939 }
63940
63941 /**
63942 * Remove attachment.
63943 *
63944 * @since 2.2.0
63945 *
63946 * @param int $postID Post ID.
63947 */
63948 function delete_attachment($postID) {
63949 log_app('function',"delete_attachment($postID). File '$location' deleted.");
63950
63951 // check for not found
63952 global $entry;
63953 $this->set_current_entry($postID);
63954
63955 if(!current_user_can('edit_post', $postID)) {
63956 $this->auth_required(__('Sorry, you do not have the right to delete this post.'));
63957 }
63958
63959 $location = get_post_meta($entry['ID'], '_wp_attached_file', true);
63960 $filetype = wp_check_filetype($location);
63961
63962 if(!isset($location) || 'attachment' != $entry['post_type'] || empty($filetype['ext']))
63963 $this->internal_error(__('Error ocurred while accessing post metadata for file location.'));
63964
63965 // delete file
63966 @unlink($location);
63967
63968 // delete attachment
63969 $result = wp_delete_post($postID);
63970
63971 if (!$result) {
63972 $this->internal_error(__('For some strange yet very annoying reason, this post could not be deleted.'));
63973 }
63974
63975 log_app('function',"delete_attachment($postID). File '$location' deleted.");
63976 $this->ok();
63977 }
63978
63979 /**
63980 * Retrieve attachment from post.
63981 *
63982 * @since 2.2.0
63983 *
63984 * @param int $postID Post ID.
63985 */
63986 function get_file($postID) {
63987
63988 // check for not found
63989 global $entry;
63990 $this->set_current_entry($postID);
63991
63992 // then whether user can edit the specific post
63993 if(!current_user_can('edit_post', $postID)) {
63994 $this->auth_required(__('Sorry, you do not have the right to edit this post.'));
63995 }
63996
63997 $location = get_post_meta($entry['ID'], '_wp_attached_file', true);
63998 $filetype = wp_check_filetype($location);
63999
64000 if(!isset($location) || 'attachment' != $entry['post_type'] || empty($filetype['ext']))
64001 $this->internal_error(__('Error ocurred while accessing post metadata for file location.'));
64002
64003 status_header('200');
64004 header('Content-Type: ' . $entry['post_mime_type']);
64005 header('Connection: close');
64006
64007 $fp = fopen($location, "rb");
64008 while(!feof($fp)) {
64009 echo fread($fp, 4096);
64010 }
64011 fclose($fp);
64012
64013 log_app('function',"get_file($postID)");
64014 exit;
64015 }
64016
64017 /**
64018 * Upload file to blog and add attachment to post.
64019 *
64020 * @since 2.2.0
64021 *
64022 * @param int $postID Post ID.
64023 */
64024 function put_file($postID) {
64025
64026 // first check if user can upload
64027 if(!current_user_can('upload_files'))
64028 $this->auth_required(__('You do not have permission to upload files.'));
64029
64030 // check for not found
64031 global $entry;
64032 $this->set_current_entry($postID);
64033
64034 // then whether user can edit the specific post
64035 if(!current_user_can('edit_post', $postID)) {
64036 $this->auth_required(__('Sorry, you do not have the right to edit this post.'));
64037 }
64038
64039 $location = get_post_meta($entry['ID'], '_wp_attached_file', true);
64040 $filetype = wp_check_filetype($location);
64041
64042 if(!isset($location) || 'attachment' != $entry['post_type'] || empty($filetype['ext']))
64043 $this->internal_error(__('Error ocurred while accessing post metadata for file location.'));
64044
64045 $fp = fopen("php://input", "rb");
64046 $localfp = fopen($location, "w+");
64047 while(!feof($fp)) {
64048 fwrite($localfp,fread($fp, 4096));
64049 }
64050 fclose($fp);
64051 fclose($localfp);
64052
64053 $ID = $entry['ID'];
64054 $pubtimes = $this->get_publish_time($entry->published);
64055 $post_date = $pubtimes[0];
64056 $post_date_gmt = $pubtimes[1];
64057 $pubtimes = $this->get_publish_time($parsed->updated);
64058 $post_modified = $pubtimes[0];
64059 $post_modified_gmt = $pubtimes[1];
64060
64061 $post_data = compact('ID', 'post_date', 'post_date_gmt', 'post_modified', 'post_modified_gmt');
64062 $result = wp_update_post($post_data);
64063
64064 if (!$result) {
64065 $this->internal_error(__('Sorry, your entry could not be posted. Something wrong happened.'));
64066 }
64067
64068 log_app('function',"put_file($postID)");
64069 $this->ok();
64070 }
64071
64072 /**
64073 * Retrieve entries URL.
64074 *
64075 * @since 2.2.0
64076 *
64077 * @param int $page Page ID.
64078 * @return string
64079 */
64080 function get_entries_url($page = null) {
64081 if($GLOBALS['post_type'] == 'attachment') {
64082 $path = $this->MEDIA_PATH;
64083 } else {
64084 $path = $this->ENTRIES_PATH;
64085 }
64086 $url = $this->app_base . $path;
64087 if(isset($page) && is_int($page)) {
64088 $url .= "/$page";
64089 }
64090 return $url;
64091 }
64092
64093 /**
64094 * Display entries URL.
64095 *
64096 * @since 2.2.0
64097 *
64098 * @param int $page Page ID.
64099 */
64100 function the_entries_url($page = null) {
64101 echo $this->get_entries_url($page);
64102 }
64103
64104 /**
64105 * Retrieve categories URL.
64106 *
64107 * @since 2.2.0
64108 *
64109 * @param mixed $deprecated Optional, not used.
64110 * @return string
64111 */
64112 function get_categories_url($deprecated = '') {
64113 return $this->app_base . $this->CATEGORIES_PATH;
64114 }
64115
64116 /**
64117 * Display category URL.
64118 *
64119 * @since 2.2.0
64120 */
64121 function the_categories_url() {
64122 echo $this->get_categories_url();
64123 }
64124
64125 /**
64126 * Retrieve attachment URL.
64127 *
64128 * @since 2.2.0
64129 *
64130 * @param int $page Page ID.
64131 * @return string
64132 */
64133 function get_attachments_url($page = null) {
64134 $url = $this->app_base . $this->MEDIA_PATH;
64135 if(isset($page) && is_int($page)) {
64136 $url .= "/$page";
64137 }
64138 return $url;
64139 }
64140
64141 /**
64142 * Display attachment URL.
64143 *
64144 * @since 2.2.0
64145 *
64146 * @param int $page Page ID.
64147 */
64148 function the_attachments_url($page = null) {
64149 echo $this->get_attachments_url($page);
64150 }
64151
64152 /**
64153 * Retrieve service URL.
64154 *
64155 * @since 2.3.0
64156 *
64157 * @return string
64158 */
64159 function get_service_url() {
64160 return $this->app_base . $this->SERVICE_PATH;
64161 }
64162
64163 /**
64164 * Retrieve entry URL.
64165 *
64166 * @since 2.7.0
64167 *
64168 * @param int $postID Post ID.
64169 * @return string
64170 */
64171 function get_entry_url($postID = null) {
64172 if(!isset($postID)) {
64173 global $post;
64174 $postID = (int) $post->ID;
64175 }
64176
64177 $url = $this->app_base . $this->ENTRY_PATH . "/$postID";
64178
64179 log_app('function',"get_entry_url() = $url");
64180 return $url;
64181 }
64182
64183 /**
64184 * Display entry URL.
64185 *
64186 * @since 2.7.0
64187 *
64188 * @param int $postID Post ID.
64189 */
64190 function the_entry_url($postID = null) {
64191 echo $this->get_entry_url($postID);
64192 }
64193
64194 /**
64195 * Retrieve media URL.
64196 *
64197 * @since 2.2.0
64198 *
64199 * @param int $postID Post ID.
64200 * @return string
64201 */
64202 function get_media_url($postID = null) {
64203 if(!isset($postID)) {
64204 global $post;
64205 $postID = (int) $post->ID;
64206 }
64207
64208 $url = $this->app_base . $this->MEDIA_SINGLE_PATH ."/file/$postID";
64209
64210 log_app('function',"get_media_url() = $url");
64211 return $url;
64212 }
64213
64214 /**
64215 * Display the media URL.
64216 *
64217 * @since 2.2.0
64218 *
64219 * @param int $postID Post ID.
64220 */
64221 function the_media_url($postID = null) {
64222 echo $this->get_media_url($postID);
64223 }
64224
64225 /**
64226 * Set the current entry to post ID.
64227 *
64228 * @since 2.2.0
64229 *
64230 * @param int $postID Post ID.
64231 */
64232 function set_current_entry($postID) {
64233 global $entry;
64234 log_app('function',"set_current_entry($postID)");
64235
64236 if(!isset($postID)) {
64237 // $this->bad_request();
64238 $this->not_found();
64239 }
64240
64241 $entry = wp_get_single_post($postID,ARRAY_A);
64242
64243 if(!isset($entry) || !isset($entry['ID']))
64244 $this->not_found();
64245
64246 return;
64247 }
64248
64249 /**
64250 * Display posts XML.
64251 *
64252 * @since 2.2.0
64253 *
64254 * @param int $page Optional. Page ID.
64255 * @param string $post_type Optional, default is 'post'. Post Type.
64256 */
64257 function get_posts($page = 1, $post_type = 'post') {
64258 log_app('function',"get_posts($page, '$post_type')");
64259 $feed = $this->get_feed($page, $post_type);
64260 $this->output($feed);
64261 }
64262
64263 /**
64264 * Display attachment XML.
64265 *
64266 * @since 2.2.0
64267 *
64268 * @param int $page Page ID.
64269 * @param string $post_type Optional, default is 'attachment'. Post type.
64270 */
64271 function get_attachments($page = 1, $post_type = 'attachment') {
64272 log_app('function',"get_attachments($page, '$post_type')");
64273 $GLOBALS['post_type'] = $post_type;
64274 $feed = $this->get_feed($page, $post_type);
64275 $this->output($feed);
64276 }
64277
64278 /**
64279 * Retrieve feed XML.
64280 *
64281 * @since 2.2.0
64282 *
64283 * @param int $page Page ID.
64284 * @param string $post_type Optional, default is post. Post type.
64285 * @return string
64286 */
64287 function get_feed($page = 1, $post_type = 'post') {
64288 global $post, $wp, $wp_query, $posts, $wpdb, $blog_id;
64289 log_app('function',"get_feed($page, '$post_type')");
64290 ob_start();
64291
64292 if(!isset($page)) {
64293 $page = 1;
64294 }
64295 $page = (int) $page;
64296
64297 $count = get_option('posts_per_rss');
64298
64299 wp('what_to_show=posts&posts_per_page=' . $count . '&offset=' . ($count * ($page-1) . '&orderby=modified'));
64300
64301 $post = $GLOBALS['post'];
64302 $posts = $GLOBALS['posts'];
64303 $wp = $GLOBALS['wp'];
64304 $wp_query = $GLOBALS['wp_query'];
64305 $wpdb = $GLOBALS['wpdb'];
64306 $blog_id = (int) $GLOBALS['blog_id'];
64307 log_app('function',"query_posts(# " . print_r($wp_query, true) . "#)");
64308
64309 log_app('function',"total_count(# $wp_query->max_num_pages #)");
64310 $last_page = $wp_query->max_num_pages;
64311 $next_page = (($page + 1) > $last_page) ? NULL : $page + 1;
64312 $prev_page = ($page - 1) < 1 ? NULL : $page - 1;
64313 $last_page = ((int)$last_page == 1 || (int)$last_page == 0) ? NULL : (int) $last_page;
64314 $self_page = $page > 1 ? $page : NULL;
64315 ?><feed xmlns="<?php echo $this->ATOM_NS ?>" xmlns:app="<?php echo $this->ATOMPUB_NS ?>" xml:lang="<?php echo get_option('rss_language'); ?>">
64316 <id><?php $this->the_entries_url() ?></id>
64317 <updated><?php echo mysql2date('Y-m-d\TH:i:s\Z', get_lastpostmodified('GMT')); ?></updated>
64318 <title type="text"><?php bloginfo_rss('name') ?></title>
64319 <subtitle type="text"><?php bloginfo_rss("description") ?></subtitle>
64320 <link rel="first" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url() ?>" />
64321 <?php if(isset($prev_page)): ?>
64322 <link rel="previous" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url($prev_page) ?>" />
64323 <?php endif; ?>
64324 <?php if(isset($next_page)): ?>
64325 <link rel="next" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url($next_page) ?>" />
64326 <?php endif; ?>
64327 <link rel="last" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url($last_page) ?>" />
64328 <link rel="self" type="<?php echo $this->ATOM_CONTENT_TYPE ?>" href="<?php $this->the_entries_url($self_page) ?>" />
64329 <rights type="text">Copyright <?php echo mysql2date('Y', get_lastpostdate('blog')); ?></rights>
64330 <?php the_generator( 'atom' ); ?>
64331 <?php if ( have_posts() ) {
64332 while ( have_posts() ) {
64333 the_post();
64334 $this->echo_entry();
64335 }
64336 }
64337 ?></feed>
64338 <?php
64339 $feed = ob_get_contents();
64340 ob_end_clean();
64341 return $feed;
64342 }
64343
64344 /**
64345 * Display entry XML.
64346 *
64347 * @since 2.2.0
64348 *
64349 * @param int $postID Post ID.
64350 * @param string $post_type Optional, default is post. Post type.
64351 * @return string.
64352 */
64353 function get_entry($postID, $post_type = 'post') {
64354 log_app('function',"get_entry($postID, '$post_type')");
64355 ob_start();
64356 switch($post_type) {
64357 case 'post':
64358 $varname = 'p';
64359 break;
64360 case 'attachment':
64361 $varname = 'attachment_id';
64362 break;
64363 }
64364 query_posts($varname . '=' . $postID);
64365 if ( have_posts() ) {
64366 while ( have_posts() ) {
64367 the_post();
64368 $this->echo_entry();
64369 log_app('$post',print_r($GLOBALS['post'],true));
64370 $entry = ob_get_contents();
64371 break;
64372 }
64373 }
64374 ob_end_clean();
64375
64376 log_app('get_entry returning:',$entry);
64377 return $entry;
64378 }
64379
64380 /**
64381 * Display post content XML.
64382 *
64383 * @since 2.3.0
64384 */
64385 function echo_entry() { ?>
64386 <entry xmlns="<?php echo $this->ATOM_NS ?>"
64387 xmlns:app="<?php echo $this->ATOMPUB_NS ?>" xml:lang="<?php echo get_option('rss_language'); ?>">
64388 <id><?php the_guid($GLOBALS['post']->ID); ?></id>
64389 <?php list($content_type, $content) = prep_atom_text_construct(get_the_title()); ?>
64390 <title type="<?php echo $content_type ?>"><?php echo $content ?></title>
64391 <updated><?php echo get_post_modified_time('Y-m-d\TH:i:s\Z', true); ?></updated>
64392 <published><?php echo get_post_time('Y-m-d\TH:i:s\Z', true); ?></published>
64393 <app:edited><?php echo get_post_modified_time('Y-m-d\TH:i:s\Z', true); ?></app:edited>
64394 <app:control>
64395 <app:draft><?php echo ($GLOBALS['post']->post_status == 'draft' ? 'yes' : 'no') ?></app:draft>
64396 </app:control>
64397 <author>
64398 <name><?php the_author()?></name>
64399 <?php if (get_the_author_url() && get_the_author_url() != 'http://') { ?>
64400 <uri><?php the_author_url()?></uri>
64401 <?php } ?>
64402 </author>
64403 <?php if($GLOBALS['post']->post_type == 'attachment') { ?>
64404 <link rel="edit-media" href="<?php $this->the_media_url() ?>" />
64405 <content type="<?php echo $GLOBALS['post']->post_mime_type ?>" src="<?php the_guid(); ?>"/>
64406 <?php } else { ?>
64407 <link href="<?php the_permalink_rss() ?>" />
64408 <?php if ( strlen( $GLOBALS['post']->post_content ) ) :
64409 list($content_type, $content) = prep_atom_text_construct(get_the_content()); ?>
64410 <content type="<?php echo $content_type ?>"><?php echo $content ?></content>
64411 <?php endif; ?>
64412 <?php } ?>
64413 <link rel="edit" href="<?php $this->the_entry_url() ?>" />
64414 <?php foreach(get_the_category() as $category) { ?>
64415 <category scheme="<?php bloginfo_rss('home') ?>" term="<?php echo $category->name?>" />
64416 <?php } ?>
64417 <?php list($content_type, $content) = prep_atom_text_construct(get_the_excerpt()); ?>
64418 <summary type="<?php echo $content_type ?>"><?php echo $content ?></summary>
64419 </entry>
64420 <?php }
64421
64422 /**
64423 * Set 'OK' (200) status header.
64424 *
64425 * @since 2.2.0
64426 */
64427 function ok() {
64428 log_app('Status','200: OK');
64429 header('Content-Type: text/plain');
64430 status_header('200');
64431 exit;
64432 }
64433
64434 /**
64435 * Set 'No Content' (204) status header.
64436 *
64437 * @since 2.2.0
64438 */
64439 function no_content() {
64440 log_app('Status','204: No Content');
64441 header('Content-Type: text/plain');
64442 status_header('204');
64443 echo "Deleted.";
64444 exit;
64445 }
64446
64447 /**
64448 * Display 'Internal Server Error' (500) status header.
64449 *
64450 * @since 2.2.0
64451 *
64452 * @param string $msg Optional. Status string.
64453 */
64454 function internal_error($msg = 'Internal Server Error') {
64455 log_app('Status','500: Server Error');
64456 header('Content-Type: text/plain');
64457 status_header('500');
64458 echo $msg;
64459 exit;
64460 }
64461
64462 /**
64463 * Set 'Bad Request' (400) status header.
64464 *
64465 * @since 2.2.0
64466 */
64467 function bad_request() {
64468 log_app('Status','400: Bad Request');
64469 header('Content-Type: text/plain');
64470 status_header('400');
64471 exit;
64472 }
64473
64474 /**
64475 * Set 'Length Required' (411) status header.
64476 *
64477 * @since 2.2.0
64478 */
64479 function length_required() {
64480 log_app('Status','411: Length Required');
64481 header("HTTP/1.1 411 Length Required");
64482 header('Content-Type: text/plain');
64483 status_header('411');
64484 exit;
64485 }
64486
64487 /**
64488 * Set 'Unsupported Media Type' (415) status header.
64489 *
64490 * @since 2.2.0
64491 */
64492 function invalid_media() {
64493 log_app('Status','415: Unsupported Media Type');
64494 header("HTTP/1.1 415 Unsupported Media Type");
64495 header('Content-Type: text/plain');
64496 exit;
64497 }
64498
64499 /**
64500 * Set 'Forbidden' (403) status header.
64501 *
64502 * @since 2.6.0
64503 */
64504 function forbidden($reason='') {
64505 log_app('Status','403: Forbidden');
64506 header('Content-Type: text/plain');
64507 status_header('403');
64508 echo $reason;
64509 exit;
64510 }
64511
64512 /**
64513 * Set 'Not Found' (404) status header.
64514 *
64515 * @since 2.2.0
64516 */
64517 function not_found() {
64518 log_app('Status','404: Not Found');
64519 header('Content-Type: text/plain');
64520 status_header('404');
64521 exit;
64522 }
64523
64524 /**
64525 * Set 'Not Allowed' (405) status header.
64526 *
64527 * @since 2.2.0
64528 */
64529 function not_allowed($allow) {
64530 log_app('Status','405: Not Allowed');
64531 header('Allow: ' . join(',', $allow));
64532 status_header('405');
64533 exit;
64534 }
64535
64536 /**
64537 * Display Redirect (302) content and set status headers.
64538 *
64539 * @since 2.3.0
64540 */
64541 function redirect($url) {
64542
64543 log_app('Status','302: Redirect');
64544 $escaped_url = attribute_escape($url);
64545 $content = <<<EOD
64546 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
64547 <html>
64548 <head>
64549 <title>302 Found</title>
64550 </head>
64551 <body>
64552 <h1>Found</h1>
64553 <p>The document has moved <a href="$escaped_url">here</a>.</p>
64554 </body>
64555 </html>
64556
64557 EOD;
64558 header('HTTP/1.1 302 Moved');
64559 header('Content-Type: text/html');
64560 header('Location: ' . $url);
64561 echo $content;
64562 exit;
64563
64564 }
64565
64566 /**
64567 * Set 'Client Error' (400) status header.
64568 *
64569 * @since 2.2.0
64570 */
64571 function client_error($msg = 'Client Error') {
64572 log_app('Status','400: Client Error');
64573 header('Content-Type: text/plain');
64574 status_header('400');
64575 exit;
64576 }
64577
64578 /**
64579 * Set created status headers (201).
64580 *
64581 * Sets the 'content-type', 'content-location', and 'location'.
64582 *
64583 * @since 2.2.0
64584 */
64585 function created($post_ID, $content, $post_type = 'post') {
64586 log_app('created()::$post_ID',"$post_ID, $post_type");
64587 $edit = $this->get_entry_url($post_ID);
64588 switch($post_type) {
64589 case 'post':
64590 $ctloc = $this->get_entry_url($post_ID);
64591 break;
64592 case 'attachment':
64593 $edit = $this->app_base . "attachments/$post_ID";
64594 break;
64595 }
64596 header("Content-Type: $this->ATOM_CONTENT_TYPE");
64597 if(isset($ctloc))
64598 header('Content-Location: ' . $ctloc);
64599 header('Location: ' . $edit);
64600 status_header('201');
64601 echo $content;
64602 exit;
64603 }
64604
64605 /**
64606 * Set 'Auth Required' (401) headers.
64607 *
64608 * @since 2.2.0
64609 *
64610 * @param string $msg Status header content and HTML content.
64611 */
64612 function auth_required($msg) {
64613 log_app('Status','401: Auth Required');
64614 nocache_headers();
64615 header('WWW-Authenticate: Basic realm="WordPress Atom Protocol"');
64616 header("HTTP/1.1 401 $msg");
64617 header('Status: 401 ' . $msg);
64618 header('Content-Type: text/html');
64619 $content = <<<EOD
64620 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
64621 <html>
64622 <head>
64623 <title>401 Unauthorized</title>
64624 </head>
64625 <body>
64626 <h1>401 Unauthorized</h1>
64627 <p>$msg</p>
64628 </body>
64629 </html>
64630
64631 EOD;
64632 echo $content;
64633 exit;
64634 }
64635
64636 /**
64637 * Display XML and set headers with content type.
64638 *
64639 * @since 2.2.0
64640 *
64641 * @param string $xml Display feed content.
64642 * @param string $ctype Optional, default is 'atom+xml'. Feed content type.
64643 */
64644 function output($xml, $ctype = 'application/atom+xml') {
64645 status_header('200');
64646 $xml = '<?xml version="1.0" encoding="' . strtolower(get_option('blog_charset')) . '"?>'."\n".$xml;
64647 header('Connection: close');
64648 header('Content-Length: '. strlen($xml));
64649 header('Content-Type: ' . $ctype);
64650 header('Content-Disposition: attachment; filename=atom.xml');
64651 header('Date: '. date('r'));
64652 if($this->do_output)
64653 echo $xml;
64654 log_app('function', "output:\n$xml");
64655 exit;
64656 }
64657
64658 /**
64659 * Sanitize content for database usage.
64660 *
64661 * @since 2.2.0
64662 *
64663 * @param array $array Sanitize array and multi-dimension array.
64664 */
64665 function escape(&$array) {
64666 global $wpdb;
64667
64668 foreach ($array as $k => $v) {
64669 if (is_array($v)) {
64670 $this->escape($array[$k]);
64671 } else if (is_object($v)) {
64672 //skip
64673 } else {
64674 $array[$k] = $wpdb->escape($v);
64675 }
64676 }
64677 }
64678
64679 /**
64680 * Access credential through various methods and perform login.
64681 *
64682 * @since 2.2.0
64683 *
64684 * @return bool
64685 */
64686 function authenticate() {
64687 log_app("authenticate()",print_r($_ENV, true));
64688
64689 // if using mod_rewrite/ENV hack
64690 // http://www.besthostratings.com/articles/http-auth-php-cgi.html
64691 if(isset($_SERVER['HTTP_AUTHORIZATION'])) {
64692 list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) =
64693 explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
64694 } else if (isset($_SERVER['REDIRECT_REMOTE_USER'])) {
64695 // Workaround for setups that do not forward HTTP_AUTHORIZATION
64696 // See http://trac.wordpress.org/ticket/7361
64697 list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) =
64698 explode(':', base64_decode(substr($_SERVER['REDIRECT_REMOTE_USER'], 6)));
64699 }
64700
64701 // If Basic Auth is working...
64702 if(isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
64703 log_app("Basic Auth",$_SERVER['PHP_AUTH_USER']);
64704 $user = wp_authenticate($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
64705 if ( $user && !is_wp_error($user) ) {
64706 wp_set_current_user($user->ID);
64707 log_app("authenticate()", $_SERVER['PHP_AUTH_USER']);
64708 return true;
64709 }
64710 }
64711
64712 return false;
64713 }
64714
64715 /**
64716 * Retrieve accepted content types.
64717 *
64718 * @since 2.2.0
64719 *
64720 * @param array $types Optional. Content Types.
64721 * @return string
64722 */
64723 function get_accepted_content_type($types = null) {
64724
64725 if(!isset($types)) {
64726 $types = $this->media_content_types;
64727 }
64728
64729 if(!isset($_SERVER['CONTENT_LENGTH']) || !isset($_SERVER['CONTENT_TYPE'])) {
64730 $this->length_required();
64731 }
64732
64733 $type = $_SERVER['CONTENT_TYPE'];
64734 list($type,$subtype) = explode('/',$type);
64735 list($subtype) = explode(";",$subtype); // strip MIME parameters
64736 log_app("get_accepted_content_type", "type=$type, subtype=$subtype");
64737
64738 foreach($types as $t) {
64739 list($acceptedType,$acceptedSubtype) = explode('/',$t);
64740 if($acceptedType == '*' || $acceptedType == $type) {
64741 if($acceptedSubtype == '*' || $acceptedSubtype == $subtype)
64742 return $type . "/" . $subtype;
64743 }
64744 }
64745
64746 $this->invalid_media();
64747 }
64748
64749 /**
64750 * Process conditionals for posts.
64751 *
64752 * @since 2.2.0
64753 */
64754 function process_conditionals() {
64755
64756 if(empty($this->params)) return;
64757 if($_SERVER['REQUEST_METHOD'] == 'DELETE') return;
64758
64759 switch($this->params[0]) {
64760 case $this->ENTRY_PATH:
64761 global $post;
64762 $post = wp_get_single_post($this->params[1]);
64763 $wp_last_modified = get_post_modified_time('D, d M Y H:i:s', true);
64764 $post = NULL;
64765 break;
64766 case $this->ENTRIES_PATH:
64767 $wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastpostmodified('GMT'), 0).' GMT';
64768 break;
64769 default:
64770 return;
64771 }
64772 $wp_etag = md5($wp_last_modified);
64773 @header("Last-Modified: $wp_last_modified");
64774 @header("ETag: $wp_etag");
64775
64776 // Support for Conditional GET
64777 if (isset($_SERVER['HTTP_IF_NONE_MATCH']))
64778 $client_etag = stripslashes($_SERVER['HTTP_IF_NONE_MATCH']);
64779 else
64780 $client_etag = false;
64781
64782 $client_last_modified = trim( $_SERVER['HTTP_IF_MODIFIED_SINCE']);
64783 // If string is empty, return 0. If not, attempt to parse into a timestamp
64784 $client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;
64785
64786 // Make a timestamp for our most recent modification...
64787 $wp_modified_timestamp = strtotime($wp_last_modified);
64788
64789 if ( ($client_last_modified && $client_etag) ?
64790 (($client_modified_timestamp >= $wp_modified_timestamp) && ($client_etag == $wp_etag)) :
64791 (($client_modified_timestamp >= $wp_modified_timestamp) || ($client_etag == $wp_etag)) ) {
64792 status_header( 304 );
64793 exit;
64794 }
64795 }
64796
64797 /**
64798 * Convert RFC3339 time string to timestamp.
64799 *
64800 * @since 2.3.0
64801 *
64802 * @param string $str String to time.
64803 * @return bool|int false if format is incorrect.
64804 */
64805 function rfc3339_str2time($str) {
64806
64807 $match = false;
64808 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))
64809 return false;
64810
64811 if($match[3] == 'Z')
64812 $match[3] == '+0000';
64813
64814 return strtotime($match[1] . " " . $match[2] . " " . $match[3]);
64815 }
64816
64817 /**
64818 * Retrieve published time to display in XML.
64819 *
64820 * @since 2.3.0
64821 *
64822 * @param string $published Time string.
64823 * @return string
64824 */
64825 function get_publish_time($published) {
64826
64827 $pubtime = $this->rfc3339_str2time($published);
64828
64829 if(!$pubtime) {
64830 return array(current_time('mysql'),current_time('mysql',1));
64831 } else {
64832 return array(date("Y-m-d H:i:s", $pubtime), gmdate("Y-m-d H:i:s", $pubtime));
64833 }
64834 }
64835
64836 }
64837
64838 /**
64839 * AtomServer
64840 * @var AtomServer
64841 * @global object $server
64842 */
64843 $server = new AtomServer();
64844 $server->handle_request();
64845
64846 ?>