[ Root ] [ Index ]

PHP Cross Reference of WordPress 2.8.6

Provided by Yoast

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


Generated: Fri Dec 4 21:26:20 2009 Cross-referenced by PHPXref 0.7