[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/ -> wp-app.php (source)

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


Generated: Sat Feb 4 03:55:55 2012 Hosted by follow the white rabbit.