[ Index ]

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


Generated: Tue Mar 17 22:41:04 2009 Cross-referenced by PHPXref 0.7