Example #1
0
 /**
  * returns a filter object to use for this
  *
  * @param string $name
  * @return InputFilter
  */
 public final function filter($name)
 {
     if ($this->_input_filter !== null) {
         return $this->_input_filter->filter($name);
     }
     App::getInstance()->includeFile('Sonic/InputFilter.php');
     $this->_input_filter = new InputFilter($this->request());
     return $this->_input_filter->filter($name);
 }
 function test_complete_filtering_run()
 {
     $this->assert_equal(InputFilter::filter('<p>I am <div><script src=\\"ohnoes\\" /><a>not a paragraph.</a><p CLASS=old><span> Or am I?</span>'), '<p>I am <div><a>not a paragraph.</a><p><span> Or am I?</span>');
     $this->assert_equal(InputFilter::filter('<p onClick=\\"window.alert(\'stole yer cookies!\');\\">Do not click here.</p>\\n<script>alert(\\"See this?\\")</script>'), '<p>Do not click here.</p>\\n');
     // http://ha.ckers.org/blog/20070124/stopping-xss-but-allowing-html-is-hard/
     $this->assert_equal(InputFilter::filter('<IMG src=\\"http://ha.ckers.org/\\" style\\"=\\"style=\\"a/onerror=alert(String.fromCharCode(88,83,83))//\\" &ampgt;`&gt'), 'onerror=alert(String.fromCharCode(88,83,83))//\\" &`&gt');
     $this->assert_equal(InputFilter::filter('<b>Hello world</b>\\n\\nThis is a <test>test</test> post.\\n\\nHere\'s a first XSS attack. <<SCRIPT>alert(\'XSS\');//<</SCRIPT>\\n\\nHere\'s a second try at a <a href=\\"#\\">second link</a>.\\n\\nHere\'s a second XSS attack. <IMG SRC=\\" &#14;  javascript:alert(\'XSS\');\\">\\n\\nHere\'s a third link hopefully <a href=\\"#\\">it won\'t get removed</a>.\\n\\n<em>Thanks!</em>'), '<b>Hello world</b>\\n\\nThis is a  post.\\n\\nHere\'s a first XSS attack. ');
     $this->assert_equal(InputFilter::filter('<<test>script>alert(\'boom\');</test>'), '');
     $this->assert_equal(InputFilter::filter('<<test></test>script>alert(\'boom\');'), '');
     $this->assert_equal(InputFilter::filter('<<test><</test>script>alert(\'boom\');'), '');
     $this->assert_equal(InputFilter::filter('<ScRIpT>alert(\'whee\');</SCRiPT>'), '');
 }
 protected static function fetch_backtype($url)
 {
     $backtype = array();
     $cacheName = "backtype-{$url}";
     if (Cache::has($cacheName)) {
         foreach (Cache::get($cacheName) as $cachedBacktype) {
             $cachedBacktype->date = HabariDateTime::date_create($cachedBacktype->date);
             $backtype[] = $cachedBacktype;
         }
         return $backtype;
     }
     $connectData = json_decode(file_get_contents("http://api.backtype.com/comments/connect.json?url={$url}&key=key&itemsperpage=10000"));
     if (isset($connectData->comments)) {
         foreach ($connectData->comments as $dat) {
             $comment = new StdClass();
             switch ($dat->entry_type) {
                 case 'tweet':
                     $comment->id = 'backtype-twitter-' . $dat->tweet_id;
                     $comment->url = 'http://twitter.com/' . $dat->tweet_from_user . '/status/' . $dat->tweet_id;
                     $comment->name = '@' . $dat->tweet_from_user . ' (via Backtype: Twitter)';
                     $comment->content_out = InputFilter::filter($dat->tweet_text);
                     $comment->date = $dat->tweet_created_at;
                     break;
                 case 'comment':
                     $comment->id = 'backtype-comment-' . $dat->comment->id;
                     $comment->url = $dat->comment->url;
                     $comment->name = $dat->author->name . ' (via Backtype: ' . InputFilter::filter($dat->blog->title) . ')';
                     $comment->content_out = InputFilter::filter($dat->comment->content);
                     $comment->date = $dat->comment->date;
                     break;
             }
             if (!$comment) {
                 continue;
             }
             $comment->status = Comment::STATUS_APPROVED;
             $comment->type = Comment::TRACKBACK;
             $comment->email = null;
             $backtype[] = $comment;
         }
     }
     Cache::set($cacheName, $backtype);
     return $backtype;
 }
Example #4
0
	/**
	 * function act_comment_insert_before
	 * This function is executed when the action "comment_insert_before"
	 * is invoked from a Comment object.
	 * The parent class, Plugin, handles registering the action
	 * and hook name using the name of the function to determine
	 * where it will be applied.
	 * You can still register functions as hooks without using
	 * this method, but boy, is it handy.
	 * @param Comment The comment that will be processed before storing it in the database.
	 **/
	function action_comment_insert_before ( $comment )
	{
		// This plugin ignores non-comments
		if ($comment->type != Comment::COMMENT) {
			return;
		}

		$spamcheck = array();

		// <script> is bad, mmmkay?
		$comment->content = InputFilter::filter($comment->content);

		// first, check the commenter's name
		// if it's only digits, then we can discard this comment
		if ( preg_match( "/^\d+$/", $comment->name ) ) {
			$comment->status = Comment::STATUS_SPAM;
			$spamcheck[] = _t('Commenters with numeric names are spammy.');
		}

		// now look at the comment text
		// if it's digits only, discard it
		$textonly = strip_tags( $comment->content );

		if ( preg_match( "/^\d+$/", $textonly ) ) {
			$comment->status = Comment::STATUS_SPAM;
			$spamcheck[] = _t('Comments that are only numeric are spammy.');
		}

		// is the content whitespaces only?
		if ( preg_match( "/\A\s+\z/", $textonly ) ) {
			$comment->status = Comment::STATUS_SPAM;
			$spamcheck[] = _t('Comments that are only whitespace characters are spammy.');
		}

		// is the content the single word "array"?
		if ( 'array' == strtolower( $textonly ) ) {
			$comment->status = Comment::STATUS_SPAM;
			$spamcheck[] = _t('Comments that are only "array" are spammy.');
		}

		// is the content the same as the name?
		if ( strtolower( $textonly ) == strtolower( $comment->name ) ) {
			$comment->status = Comment::STATUS_SPAM;
			$spamcheck[] = _t('Comments that consist of only the commenters name are spammy.');
		}

		// a lot of spam starts with "<strong>some text...</strong>"
		if ( preg_match( "#^<strong>[^.]+\.\.\.</strong>#", $comment->content ) )
		{
			$comment->status = Comment::STATUS_SPAM;
			$spamcheck[] = _t('Comments that start with strong text are spammy.');
		}

		// are there more than 3 URLs posted?  If so, it's almost certainly spam
		if ( preg_match_all( "#https?://#", strtolower( $comment->content ), $matches, PREG_SET_ORDER ) > 3 ) {
			$comment->status = Comment::STATUS_SPAM;
			$spamcheck[] = _t('There is a 3 URL limit in comments.');
		}

		// are there more than 3 URLencoded characters in the content?
		if ( preg_match_all( "/%[0-9a-f]{2}/", strtolower( $comment->content ), $matches, PREG_SET_ORDER ) > 3 ) {
			$comment->status = Comment::STATUS_SPAM;
			$spamcheck[] = _t('There is a 3 URL-encoded character limit in comments.');
		}

		// Was the tcount high enough?
		/* // This only works with special javascript running on comment form
		if ( empty($handlervars['tcount']) || $handlervars['tcount'] < 10 ) {
			$comment->status = Comment::STATUS_SPAM;
			$spamcheck[] = _t('Commenter did not actually type content.');
		}
		*/

		// We don't allow bbcode here, silly
		if ( stripos($comment->content, '[url=') !== false ) {
			$comment->status = Comment::STATUS_SPAM;
			$spamcheck[] = _t('We do not accept BBCode here.');
		}

		// Must have less than half link content
		$nonacontent = strip_tags(preg_replace('/<a.*?<\/a/i', '', $comment->content));
		$text_length = strlen( $textonly );
		if ( strlen($nonacontent) / ( $text_length == 0 ? 1 : $text_length) < 0.5 ) {
			$comment->status = Comment::STATUS_SPAM;
			$spamcheck[] = _t('Too much text that is a link compared to that which is not.');
		}

		// Only do db checks if it's not already spam
		if ($comment->status != Comment::STATUS_SPAM) {
			$spams = DB::get_value('SELECT count(*) FROM ' . DB::table('comments') . ' WHERE status = ? AND ip = ?', array(Comment::STATUS_SPAM, $comment->ip));
			// If you've already got two spams on your IP address, all you ever do is spam
			if ($spams > 1) {
				$comment->status = Comment::STATUS_SPAM;
				$spamcheck[] = sprintf(_t('Too many existing spams from this IP: %s'), $comment->ip);
			}
		}

		// Any commenter that takes longer than the session timeout is automatically moderated
		if (!isset($_SESSION['comments_allowed']) || ! in_array(Controller::get_var('ccode'), $_SESSION['comments_allowed'])) {
			$comment->status = Comment::STATUS_UNAPPROVED;
			$spamcheck[] = _t("The commenter's session timed out.");
		}

		if ( isset($comment->info->spamcheck) && is_array($comment->info->spamcheck)) {
			$comment->info->spamcheck = array_unique(array_merge($comment->info->spamcheck, $spamcheck));
		}
		else {
			$comment->info->spamcheck = $spamcheck;
		}

		// otherwise everything looks good
		// so continue processing the comment
		return;
	}
Example #5
0
	/**
	 * Receive a Pingback via XMLRPC
	 * @param array $params An array of XMLRPC parameters from the remote call
	 * @return string The success state of the pingback
	 */
	public function xmlrpc_pingback__ping( $params )
	{
		try {
			list( $source_uri, $target_uri )= $params;

			// This should really be done by an Habari core function
			$target_parse = InputFilter::parse_url( $target_uri );
			$target_stub = $target_parse['path'];
			$base_url = Site::get_path( 'base', true );

			if ( '/' != $base_url) {
				$target_stub = str_replace( $base_url, '', $target_stub );
			}

			$target_stub = trim( $target_stub, '/' );

			if ( strpos( $target_stub, '?' ) !== false ) {
				list( $target_stub, $query_string )= explode( '?', $target_stub );
			}

			// Can this be used as a target?
			$target_slug = URL::parse( $target_stub )->named_arg_values['slug'];

			if ( $target_slug === false ) {
				throw new XMLRPCException( 33 );
			}

			// Does the target exist?
			$target_post = Post::get( array( 'slug' => $target_slug ) );

			if ( $target_post === false ) {
				throw new XMLRPCException( 32 );
			}

			// Is comment allowed?
			if ( $target_post->info->comments_disabled ) {
				throw new XMLRPCException( 33 );
			}

			// Is this Pingback already registered?
			if ( Comments::get( array( 'post_id' => $target_post->id, 'url' => $source_uri, 'type' => Comment::PINGBACK ) )->count() > 0 ) {
				throw new XMLRPCException( 48 );
			}

			// Retrieve source contents
			try {
				$rr = new RemoteRequest( $source_uri );
				$rr->execute();
				if ( ! $rr->executed() ) {
					throw new XMLRPCException( 16 );
				}
				$source_contents = $rr->get_response_body();
				$headers = $rr->get_response_headers();
			}
			catch ( XMLRPCException $e ) {
				// catch our special type of exception and re-throw it
				throw $e;
			}
			catch ( Exception $e ) {
				throw new XMLRPCException( -32300 );
			}

			// Encoding is converted into internal encoding.
			// First, detect the source string's encoding
			$habari_encoding = strtoupper( MultiByte::hab_encoding() );
			$source_encoding = 'Windows-1252';
			// Is the charset in the headers?
			if ( isset( $headers['Content-Type'] ) && strpos( $headers['Content-Type'], 'charset' ) !== false ) {
				// This regex should be changed to meet the HTTP spec at some point
				if ( preg_match("/charset[\x09\x0A\x0C\x0D\x20]*=[\x09\x0A\x0C\x0D\x20]*('?)([A-Za-z0-9\-\_]+)\1/i", $headers['Content-Type'], $matches ) ) {
					$source_encoding = strtoupper( $matches[2] );
				}
			}
			// Can we tell the charset from the stream itself?
			else if ( ( $enc = MultiByte::detect_bom_encoding( $source_contents ) ) !== false ) {
				$source_encoding = $enc;
			}
			// Is the charset in a meta tag?
			else if ( preg_match( "/<meta[^>]+charset[\x09\x0A\x0C\x0D\x20]*=[\x09\x0A\x0C\x0D\x20]*([\"']?)([A-Za-z0-9\-\_]+)\1/i", $source_contents, $matches ) ) {
				$source_encoding = strtoupper( $matches[2] );
				if (in_array($source_encoding, array("UTF-16", "UTF-16BE", "UTF-16LE"))) {
					$source_encoding = "UTF-8";
				}
			}
			// Then, convert the string
			$ret = MultiByte::convert_encoding( $source_contents, $habari_encoding, $source_encoding );
			if ( $ret !== false ) {
				$source_contents = $ret;
			}

			// Find the page's title
			preg_match( '/<title>(.*)<\/title>/is', $source_contents, $matches );
			$source_title = $matches[1];

			// Find the reciprocal links and their context
			preg_match( '/<body[^>]*>(.+)<\/body>/is', $source_contents, $matches );
			$source_contents_filtered = preg_replace( '/\s{2,}/is', ' ', strip_tags( $matches[1], '<a>' ) );

			// Get rid of all the non-recriprocal links
			$ht = new HTMLTokenizer( trim( $source_contents_filtered ) );
			$set = $ht->parse();
			$all_links = $set->slice( 'a', array() );
			$keep_links = $set->slice( 'a', array( 'href' => $target_uri ) );
			$bad_links = array_diff( $all_links, $keep_links );
			foreach( $bad_links as $link ) {
				$link->tokenize_replace( '' );
				$set->replace_slice( $link );
			}
			$source_contents_filtered = (string)$set;

			// Get the excerpt
			if ( !preg_match( '%.{0,100}?<a[^>]*?href\\s*=\\s*("|\'|)' . $target_uri . '\\1[^>]*?'.'>(.+?)</a>.{0,100}%s', $source_contents_filtered, $source_excerpt ) ) {
				throw new XMLRPCException( 17 );
			}

			/** Sanitize Data */
			$source_excerpt = '&hellip;' . InputFilter::filter( $source_excerpt[0] ) . '&hellip;';
			$source_title = InputFilter::filter($source_title);
			$source_uri = InputFilter::filter($source_uri);

			/* Sanitize the URL */
			if (!empty($source_uri)) {
				$parsed = InputFilter::parse_url( $source_uri );
				if ( $parsed['is_relative'] ) {
					// guess if they meant to use an absolute link
					$parsed = InputFilter::parse_url( 'http://' . $source_uri );
					if ( ! $parsed['is_error'] ) {
						$source_uri = InputFilter::glue_url( $parsed );
					}
					else {
						// disallow relative URLs
						$source_uri = '';
					}
				}
				if ( $parsed['is_pseudo'] || ( $parsed['scheme'] !== 'http' && $parsed['scheme'] !== 'https' ) ) {
					// allow only http(s) URLs
					$source_uri = '';
				}
				else {
					// reconstruct the URL from the error-tolerant parsing
					// http:moeffju.net/blog/ -> http://moeffju.net/blog/
					$source_uri = InputFilter::glue_url( $parsed );
				}
			}

			// Add a new pingback comment
			$pingback = new Comment( array(
				'post_id'	=>	$target_post->id,
				'name'		=>	$source_title,
				'email'		=>	'',
				'url'		=>	$source_uri,
				'ip'		=>	Utils::get_ip(),
				'content'	=>	$source_excerpt,
				'status'	=>	Comment::STATUS_UNAPPROVED,
				'date'		=>	HabariDateTime::date_create(),
				'type' 		=> 	Comment::PINGBACK,
				) );

			$pingback->insert();

			// Respond to the Pingback
			return 'The pingback has been registered';
		}
		catch ( XMLRPCException $e ) {
			$e->output_fault_xml();
		}
	}
Example #6
0
 /**
  * action: ajax_amazon_search
  *
  * @access public
  * @return void
  */
 public function action_before_act_admin_ajax()
 {
     $handler_vars = Controller::get_handler_vars();
     switch ($handler_vars['context']) {
         case 'amazon_search':
             if (empty($handler_vars['keywords'])) {
                 echo json_encode(array('errorMessage' => _t('please specify keywords.')));
                 die;
             }
             if (empty($handler_vars['search_index'])) {
                 echo json_encode(array('errorMessage' => _t('please specify searchIndex.')));
                 die;
             }
             $keywords = InputFilter::filter($handler_vars['keywords']);
             $search_index = InputFilter::filter($handler_vars['search_index']);
             if (empty($handler_vars['page'])) {
                 $page = 1;
             } else {
                 $page = InputFilter::filter($handler_vars['page']);
             }
             $result = $this->item_search($keywords, $search_index, $page);
             $xml = simplexml_load_string($result);
             if ((string) $xml->Items->Request->IsValid != 'True') {
                 echo json_encode(array('errorMessage' => _t('following error reply existed from the server: ', 'amazon') . (string) $xml->Items->Request->Errors->Error->Message));
                 die;
             }
             if ((int) $xml->Items->TotalResults == 0) {
                 echo json_encode(array('errorMessage' => _t('did not match any items.', 'amazon')));
                 die;
             }
             $output = array();
             $output['TotalResults'] = (int) $xml->Items->TotalResults;
             $output['TotalPages'] = (int) $xml->Items->TotalPages;
             $output['CurrentPage'] = $page;
             $output['Start'] = ($page - 1) * 10 + 1;
             $output['End'] = $output['Start'] + 10;
             if ($output['End'] > $output['TotalResults']) {
                 $output['End'] = $output['TotalResults'];
             }
             $output['HasPrev'] = false;
             $output['HasNext'] = false;
             if ($page != 1) {
                 $output['HasPrev'] = true;
             }
             if ($page < $output['TotalPages']) {
                 $output['HasNext'] = true;
             }
             $output['Items'] = array();
             for ($i = 0; $i < count($xml->Items->Item); $i++) {
                 $item = array();
                 $item['ASIN'] = (string) $xml->Items->Item[$i]->ASIN;
                 $item['DetailPageURL'] = (string) $xml->Items->Item[$i]->DetailPageURL;
                 $item['SmallImageURL'] = (string) $xml->Items->Item[$i]->SmallImage->URL;
                 $item['SmallImageWidth'] = (int) $xml->Items->Item[$i]->SmallImage->Width;
                 $item['SmallImageHeight'] = (int) $xml->Items->Item[$i]->SmallImage->Height;
                 $item['Title'] = (string) $xml->Items->Item[$i]->ItemAttributes->Title;
                 $item['Price'] = (string) $xml->Items->Item[$i]->ItemAttributes->ListPrice->FormattedPrice;
                 $item['Binding'] = (string) $xml->Items->Item[$i]->ItemAttributes->Binding;
                 $output['Items'][] = $item;
             }
             echo json_encode($output);
             die;
         case 'amazon_insert':
             if (empty($handler_vars['asin'])) {
                 echo json_encode(array('errorMessage' => _t('please specify ASIN.', 'amazon')));
                 die;
             }
             $asin = InputFilter::filter($handler_vars['asin']);
             $result = $this->item_lookup($asin);
             $xml = simplexml_load_string($result);
             if ((string) $xml->Items->Request->IsValid != 'True') {
                 echo json_encode(array('errorMessage' => _t('following error reply existed from the server: ', 'amazon') . (string) $xml->Items->Request->Errors->Error->Message));
                 die;
             }
             $item =& $xml->Items->Item;
             ob_start();
             $template = preg_replace('/[^A-Za-z0-9\\-\\_]/', '', Options::get('amazon__template'));
             include dirname($this->get_file()) . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR . $template . '.php';
             $output['html'] = ob_get_contents();
             ob_end_clean();
             echo json_encode($output);
             //echo $output['html'];
             die;
         default:
             break;
     }
 }
Example #7
0
 /**
  * Add a comment to the site
  *
  * @param mixed $post A Post object instance or Post object id
  * @param string $name The commenter's name
  * @param string $email The commenter's email address
  * @param string $url The commenter's website URL
  * @param string $content The comment content
  * @param array $extra An associative array of extra values that should be considered
  */
 function add_comment($post, $name = null, $email = null, $url = null, $content = null, $extra = null)
 {
     if (is_numeric($post)) {
         $post = Post::get(array('id' => $post));
     }
     if (!$post instanceof Post) {
         // Not sure what you're trying to pull here, but that's no good
         header('HTTP/1.1 403 Forbidden', true, 403);
         die;
     }
     // let's do some basic sanity checking on the submission
     if (1 == Options::get('comments_require_id') && (empty($name) || empty($email))) {
         Session::error(_t('Both name and e-mail address must be provided.'));
     }
     if (empty($content)) {
         Session::error(_t('You did not provide any content for your comment!'));
     }
     if (Session::has_errors()) {
         // save whatever was provided in session data
         Session::add_to_set('comment', $name, 'name');
         Session::add_to_set('comment', $email, 'email');
         Session::add_to_set('comment', $url, 'url');
         Session::add_to_set('comment', $content, 'content');
         // now send them back to the form
         Utils::redirect($post->permalink . '#respond');
     }
     if ($post->info->comments_disabled) {
         // comments are disabled, so let's just send
         // them back to the post's permalink
         Session::error(_t('Comments on this post are disabled!'));
         Utils::redirect($post->permalink);
     }
     /* Sanitize data */
     foreach (array('name', 'url', 'email', 'content') as $k) {
         ${$k} = InputFilter::filter(${$k});
     }
     /* Sanitize the URL */
     if (!empty($url)) {
         $parsed = InputFilter::parse_url($url);
         if ($parsed['is_relative']) {
             // guess if they meant to use an absolute link
             $parsed = InputFilter::parse_url('http://' . $url);
             if (!$parsed['is_error']) {
                 $url = InputFilter::glue_url($parsed);
             } else {
                 // disallow relative URLs
                 $url = '';
             }
         }
         if ($parsed['is_pseudo'] || $parsed['scheme'] !== 'http' && $parsed['scheme'] !== 'https') {
             // allow only http(s) URLs
             $url = '';
         } else {
             // reconstruct the URL from the error-tolerant parsing
             // http:moeffju.net/blog/ -> http://moeffju.net/blog/
             $url = InputFilter::glue_url($parsed);
         }
     }
     if (preg_match('/^\\p{Z}*$/u', $content)) {
         Session::error(_t('Comment contains only whitespace/empty comment'));
         Utils::redirect($post->permalink);
     }
     /* Create comment object*/
     $comment = new Comment(array('post_id' => $post->id, 'name' => $name, 'email' => $email, 'url' => $url, 'ip' => sprintf("%u", ip2long($_SERVER['REMOTE_ADDR'])), 'content' => $content, 'status' => Comment::STATUS_UNAPPROVED, 'date' => HabariDateTime::date_create(), 'type' => Comment::COMMENT));
     // Should this really be here or in a default filter?
     // In any case, we should let plugins modify the status after we set it here.
     $user = User::identify();
     if ($user->loggedin && $comment->email == $user->email) {
         $comment->status = Comment::STATUS_APPROVED;
     }
     // Users need to have permission to add comments
     if (!$user->can('comment')) {
         Session::error(_t('You do not have permission to create comments.'));
         Utils::redirect($post->permalink);
     }
     // Allow themes to work with comment hooks
     Themes::create();
     // Allow plugins to change comment data and add commentinfo based on plugin-added form fields
     Plugins::act('comment_accepted', $comment, $this->handler_vars, $extra);
     $spam_rating = 0;
     $spam_rating = Plugins::filter('spam_filter', $spam_rating, $comment, $this->handler_vars, $extra);
     $comment->insert();
     $anchor = '';
     // If the comment was saved
     if ($comment->id && $comment->status != Comment::STATUS_SPAM) {
         $anchor = '#comment-' . $comment->id;
         // store in the user's session that this comment is pending moderation
         if ($comment->status == Comment::STATUS_UNAPPROVED) {
             Session::notice(_t('Your comment is pending moderation.'), 'comment_' . $comment->id);
         }
         // if no cookie exists, we should set one
         // but only if the user provided some details
         $cookie = 'comment_' . Options::get('GUID');
         if (!User::identify()->loggedin && !isset($_COOKIE[$cookie]) && (!empty($name) || !empty($email) || !empty($url))) {
             $cookie_content = $comment->name . '#' . $comment->email . '#' . $comment->url;
             $site_url = Site::get_path('base', true);
             setcookie($cookie, $cookie_content, time() + 31536000, $site_url);
         }
     }
     // Return the commenter to the original page.
     Utils::redirect($post->permalink . $anchor);
 }
Example #8
0
 /**
  * Recursively filter array values and strings using InputFilter::filter()
  *
  * @param mixed $value A value to filter
  * @return mixes The filtered value
  */
 protected function base_filter($value)
 {
     if (is_array($value)) {
         return array_map(array($this, 'base_filter'), $value);
     } elseif (is_string($value)) {
         return InputFilter::filter($value);
     } else {
         return $value;
     }
 }
Example #9
0
 /**
  * Receive a Pingback via XMLRPC
  * @param array $params An array of XMLRPC parameters from the remote call
  * @return string The success state of the pingback
  */
 public function xmlrpc_pingback__ping($params)
 {
     try {
         list($source_uri, $target_uri) = $params;
         // This should really be done by an Habari core function
         $target_parse = InputFilter::parse_url($target_uri);
         $target_stub = $target_parse['path'];
         $base_url = Site::get_path('base', TRUE);
         if ('/' != $base_url) {
             $target_stub = str_replace($base_url, '', $target_stub);
         }
         $target_stub = trim($target_stub, '/');
         if (strpos($target_stub, '?') !== FALSE) {
             list($target_stub, $query_string) = explode('?', $target_stub);
         }
         // Can this be used as a target?
         $target_slug = URL::parse($target_stub)->named_arg_values['slug'];
         if ($target_slug === FALSE) {
             throw new XMLRPCException(33);
         }
         // Does the target exist?
         $target_post = Post::get(array('slug' => $target_slug));
         if ($target_post === FALSE) {
             throw new XMLRPCException(32);
         }
         // Is comment allowed?
         if ($target_post->info->comments_disabled) {
             throw new XMLRPCException(33);
         }
         // Is this Pingback already registered?
         if (Comments::get(array('post_id' => $target_post->id, 'url' => $source_uri, 'type' => Comment::PINGBACK))->count() > 0) {
             throw new XMLRPCException(48);
         }
         // Retrieve source contents
         $rr = new RemoteRequest($source_uri);
         $rr->execute();
         if (!$rr->executed()) {
             throw new XMLRPCException(16);
         }
         $source_contents = $rr->get_response_body();
         // encoding is converted into internal encoding.
         // @todo check BOM at beginning of file before checking for a charset attribute
         $habari_encoding = MultiByte::hab_encoding();
         if (preg_match("/<meta[^>]+charset=([A-Za-z0-9\\-\\_]+)/i", $source_contents, $matches) !== FALSE && strtolower($habari_encoding) != strtolower($matches[1])) {
             $ret = MultiByte::convert_encoding($source_contents, $habari_encoding, $matches[1]);
             if ($ret !== FALSE) {
                 $source_contents = $ret;
             }
         }
         // Find the page's title
         preg_match('/<title>(.*)<\\/title>/is', $source_contents, $matches);
         $source_title = $matches[1];
         // Find the reciprocal links and their context
         preg_match('/<body[^>]*>(.+)<\\/body>/is', $source_contents, $matches);
         $source_contents_filtered = preg_replace('/\\s{2,}/is', ' ', strip_tags($matches[1], '<a>'));
         if (!preg_match('%.{0,100}?<a[^>]*?href\\s*=\\s*("|\'|)' . $target_uri . '\\1[^>]*?' . '>(.+?)</a>.{0,100}%s', $source_contents_filtered, $source_excerpt)) {
             throw new XMLRPCException(17);
         }
         /** Sanitize Data */
         $source_excerpt = '...' . InputFilter::filter($source_excerpt[0]) . '...';
         $source_title = InputFilter::filter($source_title);
         $source_uri = InputFilter::filter($source_uri);
         /* Sanitize the URL */
         if (!empty($source_uri)) {
             $parsed = InputFilter::parse_url($source_uri);
             if ($parsed['is_relative']) {
                 // guess if they meant to use an absolute link
                 $parsed = InputFilter::parse_url('http://' . $source_uri);
                 if (!$parsed['is_error']) {
                     $source_uri = InputFilter::glue_url($parsed);
                 } else {
                     // disallow relative URLs
                     $source_uri = '';
                 }
             }
             if ($parsed['is_pseudo'] || $parsed['scheme'] !== 'http' && $parsed['scheme'] !== 'https') {
                 // allow only http(s) URLs
                 $source_uri = '';
             } else {
                 // reconstruct the URL from the error-tolerant parsing
                 // http:moeffju.net/blog/ -> http://moeffju.net/blog/
                 $source_uri = InputFilter::glue_url($parsed);
             }
         }
         // Add a new pingback comment
         $pingback = new Comment(array('post_id' => $target_post->id, 'name' => $source_title, 'email' => '', 'url' => $source_uri, 'ip' => sprintf("%u", ip2long($_SERVER['REMOTE_ADDR'])), 'content' => $source_excerpt, 'status' => Comment::STATUS_UNAPPROVED, 'date' => HabariDateTime::date_create(), 'type' => Comment::PINGBACK));
         $pingback->insert();
         // Respond to the Pingback
         return 'The pingback has been registered';
     } catch (XMLRPCException $e) {
         $e->output_fault_xml();
     }
 }
 /**
  * Prevent certain published content from causing problems.
  **/
 function filter_post_content($content)
 {
     $newcontent = InputFilter::filter($content);
     if ($content != $newcontent) {
         Session::notice('Certain content is filtered from posts to maintain the integrity of the demo.', 'lockdown_plugin');
     }
     return $newcontent;
 }
Example #11
0
 /**
  * function add_comment
  * adds a comment to a post, if the comment content is not NULL
  * @param array An associative array of content found in the $_POST array
  */
 public function act_add_comment()
 {
     Utils::check_request_method(array('POST'));
     $defaults = array('name' => '', 'email' => '', 'url' => '', 'content' => '');
     // We need to get the post anyway to redirect back to the post page.
     $post = Post::get(array('id' => $this->handler_vars['id']));
     if (!$post) {
         // trying to comment on a non-existent post?  Weirdo.
         header('HTTP/1.1 403 Forbidden', true, 403);
         die;
     }
     // make sure all our default values are set so we don't throw undefined index errors
     foreach ($defaults as $k => $v) {
         if (!isset($this->handler_vars[$k])) {
             $this->handler_vars[$k] = $v;
         }
     }
     // let's do some basic sanity checking on the submission
     if (1 == Options::get('comments_require_id') && (empty($this->handler_vars['name']) || empty($this->handler_vars['email']))) {
         Session::error(_t('Both name and e-mail address must be provided.'));
     }
     if (empty($this->handler_vars['content'])) {
         Session::error(_t('You did not provide any content for your comment!'));
     }
     if (Session::has_errors()) {
         // save whatever was provided in session data
         Session::add_to_set('comment', $this->handler_vars['name'], 'name');
         Session::add_to_set('comment', $this->handler_vars['email'], 'email');
         Session::add_to_set('comment', $this->handler_vars['url'], 'url');
         Session::add_to_set('comment', $this->handler_vars['content'], 'content');
         // now send them back to the form
         Utils::redirect($post->permalink . '#respond');
     }
     if ($post->info->comments_disabled) {
         // comments are disabled, so let's just send
         // them back to the post's permalink
         Session::error(_t('Comments on this post are disabled!'));
         Utils::redirect($post->permalink);
     }
     /* Sanitize data */
     foreach ($defaults as $k => $v) {
         $this->handler_vars[$k] = InputFilter::filter($this->handler_vars[$k]);
     }
     /* Sanitize the URL */
     if (!empty($this->handler_vars['url'])) {
         $url = $this->handler_vars['url'];
         $parsed = InputFilter::parse_url($url);
         if ($parsed['is_relative']) {
             // guess if they meant to use an absolute link
             $parsed = InputFilter::parse_url('http://' . $url);
             if (!$parsed['is_error']) {
                 $url = InputFilter::glue_url($parsed);
             } else {
                 // disallow relative URLs
                 $url = '';
             }
         }
         if ($parsed['is_pseudo'] || $parsed['scheme'] !== 'http' && $parsed['scheme'] !== 'https') {
             // allow only http(s) URLs
             $url = '';
         } else {
             // reconstruct the URL from the error-tolerant parsing
             // http:moeffju.net/blog/ -> http://moeffju.net/blog/
             $url = InputFilter::glue_url($parsed);
         }
         $this->handler_vars['url'] = $url;
     }
     if (preg_match('/^\\p{Z}*$/u', $this->handler_vars['content'])) {
         Session::error(_t('Comment contains only whitespace/empty comment'));
         Utils::redirect($post->permalink);
     }
     /* Create comment object*/
     $comment = new Comment(array('post_id' => $this->handler_vars['id'], 'name' => $this->handler_vars['name'], 'email' => $this->handler_vars['email'], 'url' => $this->handler_vars['url'], 'ip' => sprintf("%u", ip2long($_SERVER['REMOTE_ADDR'])), 'content' => $this->handler_vars['content'], 'status' => Comment::STATUS_UNAPPROVED, 'date' => HabariDateTime::date_create(), 'type' => Comment::COMMENT));
     // Should this really be here or in a default filter?
     // In any case, we should let plugins modify the status after we set it here.
     $user = User::identify();
     if ($user->loggedin && $comment->email == $user->email) {
         $comment->status = Comment::STATUS_APPROVED;
     }
     // Allow themes to work with comment hooks
     Themes::create();
     $spam_rating = 0;
     $spam_rating = Plugins::filter('spam_filter', $spam_rating, $comment, $this->handler_vars);
     $comment->insert();
     $anchor = '';
     // If the comment was saved
     if ($comment->id) {
         $anchor = '#comment-' . $comment->id;
         // store in the user's session that this comment is pending moderation
         if ($comment->status == Comment::STATUS_UNAPPROVED) {
             Session::notice(_t('Your comment is pending moderation.'), 'comment_' . $comment->id);
         }
         // if no cookie exists, we should set one
         // but only if the user provided some details
         $cookie = 'comment_' . Options::get('GUID');
         if (!isset($_COOKIE[$cookie]) && (!empty($this->handler_vars['name']) || !empty($this->handler_vars['email']) || !empty($this->handler_vars['url']))) {
             $cookie_content = $comment->name . '#' . $comment->email . '#' . $comment->url;
             $site_url = Site::get_path('base', true);
             setcookie($cookie, $cookie_content, time() + 31536000, $site_url);
         }
     }
     // Return the commenter to the original page.
     Utils::redirect($post->permalink . $anchor);
 }
 public static function comment_safe_markdown($content)
 {
     // filter the HTML, just as a normal comment would be filtered before saving to the database
     return InputFilter::filter(self::markdown($content));
 }
 /**
  * Import the <outline> data from simplexml obj. $xml->body.
  * @todo support tags/categories
  * @todo don't be strict on duplicate matching.
  */
 private function import_opml(\SimpleXMLElement $xml)
 {
     if (!$xml->outline) {
         throw new \Exception('Not a valid OPML resource');
     }
     $count = 0;
     foreach ($xml->outline as $outline) {
         $atts = (array) $outline->attributes();
         $params = $this->map_opml_atts($atts['@attributes']);
         if (isset($params['url']) && isset($params['title'])) {
             if (count(Posts::get(array('all:info' => array('url' => $params['url'])))) >= 1) {
                 continue;
             }
             $params = array_map(function ($a) {
                 return InputFilter::filter($a);
             }, $params);
             extract($params);
             $user = User::identify();
             $params = array('title' => $title, 'pubdate' => isset($pubdate) ? HabariDateTime::date_create($pubdate) : HabariDateTime::date_create(), 'updated' => isset($updated) ? HabariDateTime::date_create($updated) : HabariDateTime::date_create(), 'content' => isset($content) ? $content : '', 'status' => Post::status('published'), 'content_type' => Post::type(self::CONTENT_TYPE), 'user_id' => $user->id);
             $blog = Post::create($params);
             foreach ($this->info_fields as $field) {
                 if (isset(${$field}) && ${$field}) {
                     $blog->info->{$field} = ${$field};
                 }
             }
             $blog->update();
             $count++;
         }
         if ($outline->outline) {
             $count += $this->import_opml($outline);
         }
     }
     return $count;
 }
Example #14
0
 /**
  * Add a comment to the site
  *
  * @param mixed $post A Post object instance or Post object id
  * @param string $name The commenter's name
  * @param string $email The commenter's email address
  * @param string $url The commenter's website URL
  * @param string $content The comment content
  * @param array $extra An associative array of extra values that should be considered
  */
 function add_comment($post, $name = null, $email = null, $url = null, $content = null, $extra = null)
 {
     if (is_numeric($post)) {
         $post = Post::get(array('id' => $post));
     }
     if (!$post instanceof Post) {
         // Not sure what you're trying to pull here, but that's no good
         header('HTTP/1.1 403 Forbidden', true, 403);
         die;
     }
     /* Sanitize data */
     foreach (array('name', 'url', 'email', 'content') as $k) {
         ${$k} = InputFilter::filter(${$k});
     }
     // there should never be any HTML in the name, so do some extra filtering on it
     $name = strip_tags(html_entity_decode($name, ENT_QUOTES, 'UTF-8'));
     /* Sanitize the URL */
     if (!empty($url)) {
         $parsed = InputFilter::parse_url($url);
         if ($parsed['is_relative']) {
             // guess if they meant to use an absolute link
             $parsed = InputFilter::parse_url('http://' . $url);
             if (!$parsed['is_error']) {
                 $url = InputFilter::glue_url($parsed);
             } else {
                 // disallow relative URLs
                 $url = '';
             }
         }
         if ($parsed['is_pseudo'] || $parsed['scheme'] !== 'http' && $parsed['scheme'] !== 'https') {
             // allow only http(s) URLs
             $url = '';
         } else {
             // reconstruct the URL from the error-tolerant parsing
             // http:moeffju.net/blog/ -> http://moeffju.net/blog/
             $url = InputFilter::glue_url($parsed);
         }
     }
     /* Create comment object*/
     $comment = new Comment(array('post_id' => $post->id, 'name' => $name, 'email' => $email, 'url' => $url, 'ip' => Utils::get_ip(), 'content' => $content, 'status' => Comment::status('approved'), 'date' => DateTime::create(), 'type' => Comment::type('comment')));
     // Should this really be here or in a default filter?
     // In any case, we should let plugins modify the status after we set it here.
     $user = User::identify();
     if ($user->loggedin && $comment->email == $user->email) {
         $comment->status = 'approved';
     }
     // Allow themes to work with comment hooks
     Themes::create();
     // Allow plugins to change comment data and add commentinfo based on plugin-added form fields
     Plugins::act('comment_accepted', $comment, $this->handler_vars, $extra);
     $spam_rating = 0;
     $spam_rating = Plugins::filter('spam_filter', $spam_rating, $comment, $this->handler_vars, $extra);
     if ($spam_rating >= Options::get('spam_percentage', 100)) {
         $comment->status = 'spam';
     }
     $comment->insert();
     $anchor = '';
     // If the comment was saved
     if ($comment->id && $comment->status != 'spam') {
         $anchor = '#comment-' . $comment->id;
         // store in the user's session that this comment is pending moderation
         if ($comment->status == 'unapproved') {
             Session::notice(_t('Your comment is pending moderation.'), 'comment_' . $comment->id);
         }
         // if no cookie exists, we should set one
         // but only if the user provided some details
         $cookie_name = 'comment_' . Options::get('public-GUID');
         // build the string we store for the cookie
         $cookie_content = implode('#', array($comment->name, $comment->email, $comment->url));
         // if the user is not logged in and there is no cookie OR the cookie differs from the current set
         if (User::identify()->loggedin == false && (!isset($_COOKIE[$cookie_name]) || $_COOKIE[$cookie_name] != $cookie_content)) {
             // update the cookie
             setcookie($cookie_name, $cookie_content, time() + DateTime::YEAR, Site::get_path('base', true));
         }
     }
     // Return the commenter to the original page.
     Utils::redirect($post->permalink . $anchor);
 }
Example #15
-1
 public function filter_post_content($content, Post $post)
 {
     if ($post->info->password) {
         // if user logged in, show post
         // make sure it's not just the anonymous user!
         $user = User::identify();
         if ($user instanceof User && $user != User::anonymous()) {
             return $content;
         }
         $session = Session::get_set('post_passwords', false);
         $token = Utils::crypt('42' . $post->info->password . $post->id . Options::get('GUID'));
         // if password was submitted verify it
         if (Controller::get_var('post_password') && Controller::get_var('post_password_id') == $post->id) {
             $pass = InputFilter::filter(Controller::get_var('post_password'));
             if (Utils::crypt($pass, $post->info->password)) {
                 Session::add_to_set('post_passwords', $token, $post->id);
                 $session[$post->id] = $token;
             } else {
                 Session::error(_t('That password was incorrect.', 'postpass'));
             }
         }
         // if password is stored in session verify it
         if (isset($session[$post->id]) && $session[$post->id] == $token) {
             return $content;
         } else {
             $theme = Themes::create();
             $theme->post = $post;
             return $theme->fetch('post_password_form');
         }
     } else {
         return $content;
     }
 }