/** * Converts an ATOM encoded Salmon post to a SalmonEntry. * @param string $atom_string The raw POST to the Salmon endpoint. * @return SalmonEntry An object representing the information in the POST. */ public static function from_atom($atom_string) { $xml_parser = xml_parser_create(''); $xml_values = array(); $xml_tags = array(); if (!$xml_parser) { return false; } xml_parser_set_option($xml_parser, XML_OPTION_TARGET_ENCODING, 'UTF-8'); xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 0); xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, 1); xml_parse_into_struct($xml_parser, trim($atom_string), $xml_values); xml_parser_free($xml_parser); $entry = new SalmonEntry(); $breadcrumbs = array(); for ($i = 0; $atom = $xml_values[$i]; $i++) { // Only process one entry. This could be generalized to a feed later. if (strtolower($atom['tag']) == 'entry' && strtolower($atom['type']) == 'close') { break; } // Keep a "breadcrumb" list of the tag hierarchy we're currently in. $breadcrumbs[$atom['level']] = $atom['tag']; // Parse individual attributes one at a time. switch (strtolower($atom['tag'])) { case 'id': $entry->id = $atom['value']; break; case 'name': if (SalmonEntry::parent_is($atom, 'author', $breadcrumbs)) { $entry->author_name = $atom['value']; } break; case 'uri': if (SalmonEntry::parent_is($atom, 'author', $breadcrumbs)) { $entry->author_uri = $atom['value']; } break; case 'thr:in-reply-to': $entry->thr_in_reply_to = $atom['value']; break; case 'content': $entry->content = $atom['value']; break; case 'title': $entry->title = $atom['value']; break; case 'updated': $entry->updated = $atom['value']; break; case 'sal:signature': $entry->salmon_signature = $atom['value']; break; } } $entry->webfinger = WebFingerAccount::from_acct_string($entry->author_uri); return $entry; }
/** * Attempts to parse data sent to the Salmon endpoint and post it as a * comment for the current blog. */ public static function parse_salmon_post() { // Allow cross domain JavaScript requests, from salmon-playground. if (strtoupper($_SERVER['REQUEST_METHOD']) == "OPTIONS" && strtoupper($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']) == "POST") { // See https://developer.mozilla.org/En/HTTP_access_control header('HTTP/1.1 200 OK'); header('Access-Control-Allow-Origin: * '); die; } //TODO(kurrik): Check that this always works, even if always_populate_raw_post_data is Off $request_body = @file_get_contents('php://input'); $array = MagicSig::parse($request_body); $entry = SalmonEntry::from_atom($array['data']); // Validate the request if the option is set. if (get_option('salmonpress_validate')) { if ($entry->validate() === false) { header('HTTP/1.1 403 Forbidden'); print "The posted Salmon entry's signature did not validate."; die; } } $commentdata = $entry->to_commentdata(); if ($commentdata === false) { header('HTTP/1.1 400 Bad Request'); print "The posted Salmon entry was malformed."; } else { if (!isset($commentdata['user_id'])) { if (get_option('comment_registration')) { header('HTTP/1.1 403 Forbidden'); print "The blog settings only allow registered users to post comments."; die; } } else { wp_new_comment($commentdata); header('HTTP/1.1 201 Created'); print "The Salmon entry was posted."; } } die; }