[ Index ]

PHP Cross Reference of Wordpress 2.9.1

title

Body

[close]

/ -> wp-app.php (source)

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


Generated: Fri Jan 8 00:19:48 2010 Cross-referenced by PHPXref 0.7