PageRenderTime 59ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/source/mydroid/external/webkit/WebKitSite/blog/wp-app.php

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