/** * Match a URL/URI against the rewrite rules stored in the DB. * This method is used by the Controller class for parsing * requests, and by other classes, such as Pingback, which * uses it to determine the post slug for a given URL. * * Returns the matched RewriteRule object, or false. * * @param string $from_url URL string to parse * @return \Habari\RewriteRule matched rule, or false */ public static function parse($from_url) { $base_url = Site::get_path('base', true); /* * Strip out the base URL from the requested URL * but only if the base URL isn't / */ if (strpos($from_url, $base_url) === 0) { $from_url = MultiByte::substr($from_url, MultiByte::strlen($base_url)); } /* Trim off any leading or trailing slashes */ $from_url = trim($from_url, '/'); /* Remove the querystring from the URL */ if (MultiByte::strpos($from_url, '?') !== false) { list($from_url, ) = explode('?', $from_url); } $url = URL::instance(); $url->load_rules(); // Cached in singleton /* * Run the stub through the regex matcher */ self::$stub = $from_url; /** @var RewriteRule $rule */ foreach ($url->rules as $rule) { if ($rule->match($from_url)) { $url->matched_rule = $rule; /* Stop processing at first matched rule... */ return $rule; } } return false; }
/** * Initialize the session handlers */ static function init() { // the default path for the session cookie is /, but let's make that potentially more restrictive so no one steals our cookehs // we also can't use 'null' when we set a secure-only value, because that doesn't mean the same as the default like it should $path = Site::get_path('base', true); // the default is not to require a secure session $secure = false; // if we want to always require secure if (Config::get('force_secure_session') == true) { $secure = true; } // if this is an HTTPS connection by default we will // IIS sets HTTPS == 'off', so we have to check the value too if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') { $secure = true; } // but if we have explicitly disabled it, don't // note the ===. not setting it (ie: null) should not be the same as setting it to false if (Config::get('force_secure_session') === false) { $secure = false; } // now we've got a path and secure, so set the cookie values session_set_cookie_params(null, $path, null, $secure); // figure out the session lifetime and let plugins change it $lifetime = ini_get('session.gc_maxlifetime'); self::$lifetime = Plugins::filter('session_lifetime', $lifetime); session_set_save_handler(array('Session', 'open'), array('Session', 'close'), array('Session', 'read'), array('Session', 'write'), array('Session', 'destroy'), array('Session', 'gc')); // session::write gets called after object destruction, so our class isn't available // fix that by registering it as a shutdown function, before objects are destroyed register_shutdown_function('session_write_close'); if (!isset($_SESSION)) { session_start(); } return true; }
/** * Initialize some internal values when plugin initializes */ public function action_init() { $user_path = HABARI_PATH . '/' . Site::get_path('user', true); $this->root = $user_path . 'files'; //Options::get('simple_file_root'); $this->url = Options::get('s3_url'); $this->bucket = Options::get('s3_bucket'); $this->key = Options::get('s3_key'); $this->private_key = Options::get('s3_secret'); }
private function default_paths($force = false) { // If either the upload directory or the upload URL is empty, fallback to the defaults // This behavior can also be forced when needed (for example, resetting the configuration) if ($force || empty($this->upload_dir) || empty($this->upload_url)) { // By default, we use the same directory as the Habari media silo (user/files) $user_path = HABARI_PATH . '/' . Site::get_path('user', true); Options::set('metaweblog__upload_dir', $user_path . 'files'); Options::set('metaweblog__upload_url', Site::get_url('user', true) . 'files'); // Also, check if the upload directory exist and are writable $this->check_upload_dir(); } }
/** * Connect to SQLite * Overrides the DatabaseConnection to return false if the SQLite file doesn't exist. * * @param connection_string string a PDO connection string * @param db_user string the database user name * @param db_pass string the database user password * @return boolean True if connection succeeded, false if not. */ public function connect($connect_string, $db_user, $db_pass) { list($type, $file) = explode(':', $connect_string, 2); if ($file == basename($file)) { if (file_exists(HABARI_PATH . '/' . $file)) { $file = HABARI_PATH . '/' . $file; } else { $file = HABARI_PATH . '/' . Site::get_path('user', TRUE) . $file; } $connect_string = implode(':', array($type, $file)); } $conn = parent::connect($connect_string, $db_user, $db_pass); $this->exec('PRAGMA synchronous = OFF'); return $conn; }
/** * * Checks if files directory is usable */ private function check_files() { $user_path = HABARI_PATH . '/' . Site::get_path('user', true); $this->root = $user_path . 'files'; //Options::get('simple_file_root'); $this->url = Site::get_url('user', true) . 'files'; //Options::get('simple_file_url'); if ( !is_dir( $this->root ) ) { if ( is_writable( $user_path ) ) { mkdir( $this->root, 0755 ); } else { return false; } } return true; }
protected function getTemplateHelperSets() { // strip the subdirectory out of the theme path, as that will already be part of the base URL $themePath = substr(Site::get_path('theme') . '/web', strlen(Site::get_path('base'))); $sets = array(new sfTemplateHelperAssets($themePath, Site::get_url('habari')), new sfTemplateHelperJavascripts(), new sfTemplateHelperStylesheets()); $dirs = array($this->themeDirectory . '/lib/helper', dirname(__FILE__) . '/helper'); foreach ($dirs as $dir) { foreach (glob($dir . '/*.php') as $helperPath) { include_once $helperPath; $helperFilename = basename($helperPath); $className = substr($helperFilename, 0, strpos($helperFilename, '.')); $sets[] = new $className(); } } return $sets; }
public function action_template_header() { $modified = Stack::get_sorted_stack('template_header_javascript'); foreach ($modified as $key => $value) { Stack::remove('template_header_javascript', $key); } Stack::add('template_header_javascript', Site::get_url('user') . "/files/minified.js", 'Minified'); if (!Cache::has(self::$cache_name . '_js') || !Cache::has(self::$cache_name . '_css')) { set_include_path(dirname(__FILE__) . '/min/lib' . PATH_SEPARATOR . get_include_path()); require_once 'Minify/Source.php'; require_once 'Minify/HTML.php'; require_once 'Minify/CSS.php'; require_once 'Minify/HTML.php'; require_once 'Minify.php'; require_once 'Minify/Cache/File.php'; } if (!Cache::has(self::$cache_name . '_js')) { $js_stack = array(); foreach ($modified as $js) { $js_stack[] = Site::get_path('base') . str_replace(Site::get_url('habari') . '/', '', $js); } $options = array('files' => $js_stack, 'encodeOutput' => false, 'quiet' => true, 'maxAge' => 86400); $result = Minify::serve('Files', $options); file_put_contents(site::get_dir('user') . '/files/minified.js', $result['content']); Cache::set(self::$cache_name . '_js', 'true'); } /* CSS */ $modified = Stack::get_sorted_stack('template_stylesheet'); $tmp = array(); foreach ($modified as $key => $value) { $tmp[] = $value[0]; Stack::remove('template_stylesheet', $key); } Stack::add('template_stylesheet', array(Site::get_url('user') . "/files/minified.css", 'screen'), 'style'); if (!Cache::has(self::$cache_name . '_css')) { $css_stack = array(); foreach ($tmp as $css) { $css_stack[] = Site::get_path('base') . str_replace(Site::get_url('habari') . '/', '', $css); } $options = array('files' => $css_stack, 'encodeOutput' => false, 'quiet' => true, 'maxAge' => 86400); // handle request $result = Minify::serve('Files', $options); file_put_contents(site::get_dir('user') . '/files/minified.css', $result['content']); Cache::set(self::$cache_name . '_css', 'true'); } }
/** * Connect to SQLite * Overrides the DatabaseConnection to return false if the SQLite file doesn't exist. * * @param connection_string string a PDO connection string * @param db_user string the database user name * @param db_pass string the database user password * @return boolean True if connection succeeded, false if not. */ public function connect($connect_string, $db_user, $db_pass) { list($type, $file) = explode(':', $connect_string, 2); if ($file == basename($file)) { if (file_exists(HABARI_PATH . '/' . $file)) { $file = HABARI_PATH . '/' . $file; } else { $file = HABARI_PATH . '/' . Site::get_path('user', true) . $file; } $connect_string = implode(':', array($type, $file)); } if (file_exists($file) && !is_writable($file)) { die(_t('Database file "%s" must be writable.', array($file))); } $conn = parent::connect($connect_string, $db_user, $db_pass); $this->exec('PRAGMA synchronous = OFF'); return $conn; }
/** * Loads a theme's metadata from an XML file in theme's * directory. * * @param theme Name of theme to retrieve metadata about */ public function info($theme) { $xml_file = Site::get_path('user') . '/themes/' . $theme . '/theme.xml'; if ($xml_content = file_get_contents($xml_file)) { $theme_data = new SimpleXMLElement($xml_file); // Is it a valid theme xml file? if (isset($theme_data->theme)) { $valid_named_elements = array('name', 'version', 'template_engine', 'theme_dir'); // Assigns based on wether or not it's a valid named element. foreach ($theme_data->theme->children() as $key => $value) { $key = strtolower($key); if (in_array($key, $valid_named_elements)) { $this->{$key} = $value; } else { $this->config_vars[$key] = $value; } } } } }
/** * Initialize the session handlers */ public static function init() { // the default path for the session cookie is /, but let's make that potentially more restrictive so no one steals our cookehs // we also can't use 'null' when we set a secure-only value, because that doesn't mean the same as the default like it should $path = Site::get_path('base', true); // the default is not to require a secure session $secure = false; // if we want to always require secure if (Config::get('force_secure_session') == true) { $secure = true; } // if this is an HTTPS connection by default we will // IIS sets HTTPS == 'off', so we have to check the value too if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') { $secure = true; } // but if we have explicitly disabled it, don't // note the ===. not setting it (ie: null) should not be the same as setting it to false if (Config::get('force_secure_session') === false) { $secure = false; } // now we've got a path and secure, so set the cookie values session_set_cookie_params(null, $path, null, $secure); // figure out the session lifetime and let plugins change it $lifetime = ini_get('session.gc_maxlifetime'); self::$lifetime = Plugins::filter('session_lifetime', $lifetime); //$_SESSION = new SessionStorage(); if (isset($_COOKIE[self::HABARI_SESSION_COOKIE_NAME])) { self::$session_id = $_COOKIE[self::HABARI_SESSION_COOKIE_NAME]; self::read(); self::$stored_session_hash = self::session_data_hash(); } // make sure we check whether or not we should write the session after the page is rendered register_shutdown_function(Method::create('\\Habari\\Session', 'shutdown')); // process the write queue register_shutdown_function(Method::create('\\Habari\\Session', 'process_queue')); return true; }
/** * 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); }
function upload( $photo, $title = '', $description = '', $tags = '', $perms = '', $async = 1, &$info = null ) { $store = HABARI_PATH . '/' . Site::get_path( 'user' ) . '/cache'; if ( !is_dir( $store ) ){ mkdir( $store, 0777 ); } $params = array( 'auth_token' => $this->cachedToken() ); $url = InputFilter::parse_url( 'file://' . $photo ); if ( isset( $url['scheme'] ) ){ $localphoto = fopen( HABARI_PATH . '/' . $photo, 'r' ); $store = tempnam( $store, 'G2F' ); file_put_contents( $store, $localphoto ); fclose( $localphoto ); $params['photo'] = $store; } else{ $params['photo'] = $photo; } $info = filesize( $params['photo'] ); if ( $title ){ $params['title'] = $title; } if ( $description ){ $params['description'] = $description; } if ( $tags ){ $params['tags'] = $tags; } if ( $perms ){ if ( isset( $perms['is_public'] ) ){ $params['is_public'] = $perms['is_public']; } if ( isset( $perms['is_friend'] ) ){ $params['is_friend'] = $perms['is_friend']; } if ( isset( $perms['is_family'] ) ){ $params['is_family'] = $perms['is_family']; } } if ( $async ){ $params['async'] = $async; } // call the upload method. $xml = $this->call( 'upload', $params ); if ( $store ){ unlink( $store ); } if ( Error::is_error( $xml ) ){ throw $xml; } if ( $async ){ return( (string)$xml->ticketid ); } else{ return( (string)$xml->photoid ); } }
public function action_template_header() { //Cache::expire( self::$cache_name . '_js' ); //Cache::expire( self::$cache_name . '_css' ); // try to disable output_compression (may not have an effect) ini_set('zlib.output_compression', '0'); $modified_js = Stack::get_sorted_stack('template_header_javascript'); foreach ($modified_js as $key => $value) { Stack::remove('template_header_javascript', $key); } Stack::add('template_header_javascript', Site::get_url('user') . '/files/minified.js', 'Minified'); $modified_css = Stack::get_sorted_stack('template_stylesheet'); $css = array(); foreach ($modified_css as $key => $value) { $css[] = $value[0]; Stack::remove('template_stylesheet', $key); } Stack::add('template_stylesheet', array(Site::get_url('user') . "/files/minified.css", 'screen'), 'style'); /* * If we have the files or the cache havent expired don't create new files. */ if (!file_exists(site::get_dir('user') . '/files/minified.css') || !file_exists(site::get_dir('user') . '/files/minified.js') || (!Cache::has(self::$cache_name . '_js') || !Cache::has(self::$cache_name . '_css'))) { /* Taken from min/index.php */ define('MINIFY_MIN_DIR', dirname(__FILE__) . '/min/'); // load config require MINIFY_MIN_DIR . '/config.php'; // setup include path set_include_path($min_libPath . PATH_SEPARATOR . get_include_path()); require 'Minify.php'; Minify::$uploaderHoursBehind = $min_uploaderHoursBehind; Minify::setCache(isset($min_cachePath) ? $min_cachePath : '', $min_cacheFileLocking); if ($min_documentRoot) { $_SERVER['DOCUMENT_ROOT'] = $min_documentRoot; } elseif (0 === stripos(PHP_OS, 'win')) { Minify::setDocRoot(); // IIS may need help } $min_serveOptions['minifierOptions']['text/css']['symlinks'] = $min_symlinks; // Using jsmin+ 1.3 $min_serveOptions['minifiers']['application/x-javascript'] = array('JSMinPlus', 'minify'); /* Javascript */ if (!Cache::has(self::$cache_name . '_js') || !file_exists(site::get_dir('user') . '/files/minified.js')) { $js_stack = array(); foreach ($modified_js as $js) { $js_stack[] = Site::get_path('base') . str_replace(Site::get_url('habari') . '/', '', $js); } $options = array('files' => $js_stack, 'encodeOutput' => false, 'quiet' => true); $result = Minify::serve('Files', $options); file_put_contents(site::get_dir('user') . '/files/minified.js', $result['content']); Cache::set(self::$cache_name . '_js', 'true', Options::get('minification__expire')); } /* CSS */ if (!Cache::has(self::$cache_name . '_css') || !file_exists(site::get_dir('user') . '/files/minified.css')) { $css_stack = array(); foreach ($css as $file) { $css_stack[] = Site::get_path('base') . str_replace(Site::get_url('habari') . '/', '', $file); } $options = array('files' => $css_stack, 'encodeOutput' => false, 'quiet' => true); // handle request $result = Minify::serve('Files', $options); file_put_contents(site::get_dir('user') . '/files/minified.css', $result['content']); Cache::set(self::$cache_name . '_css', 'true', Options::get('minification__expire')); } } }
/** * 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(); } }
/** * out_path echos a URL path * @param string the URL path to display * @param bool whether or not to include a trailing slash. Default: No */ public static function out_path( $path, $trail = false ) { echo Site::get_path( $path, $trail ); }
/** * Initialise the file paths * */ protected function init_backend() { $this->_root_path = Options::get(self::PATH_OPTION); if (!$this->_root_path) { // default to this directory $this->_root_path = HABARI_PATH . '/' . Site::get_path('user', true) . '/plugins/multisearch/indexes/'; Options::set(self::PATH_OPTION, $this->_root_path); } if (Options::get(self::ENGINE_OPTION)) { $this->load_backend(Options::get(self::ENGINE_OPTION)); } }
/** * 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); }
/** * Returns an array of URLs correlating to each directory found in the * default Habari Silo path in the form: * * URL => "Habari Silo:/path/to/dir/" * * This is for use in a <select> form element. * * @access private * @return array */ private static function siloDirs() { // Get a list of all the directories available in the loaded Habari Silo $user_path = HABARI_PATH . '/' . Site::get_path('user') . '/files/'; // Default Habari silo path $user_url = Site::get_url('user') . '/files/'; // Default Habari Silo URL $dirs = array($user_url => 'Habari Silo:/ '); $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($user_path), RecursiveIteratorIterator::SELF_FIRST); foreach ($objects as $name => $object) { if ($object->isDir()) { if ($object->getFilename() != '.deriv') { // Exclude the .deriv dirs created by Habari Silo plugin $newname = str_replace($user_path, '', $name) . '/'; $newurl = str_replace($user_path, $user_url, $name) . '/'; $dirs[$newurl] = 'Habari Silo:/' . $newname; } } } return $dirs; }
/** * Parses the requested URL. Automatically * translates URLs coming in from mod_rewrite and parses * out any action and parameters in the slug. */ public static function parse_request() { /* Local scope variable caching */ $controller = Controller::instance(); /* Grab the base URL from the Site class */ $controller->base_url = Site::get_path('base', true); /* If we're installed in a directory subsite, add that to the base_url */ // $controller->base_url .= Site::$config_urldir; /* Start with the entire URL coming from web server... */ if (isset($_SERVER['REQUEST_URI'])) { $start_url = $_SERVER['REQUEST_URI']; } else { $start_url = $_SERVER['SCRIPT_NAME']; if (isset($_SERVER['PATH_INFO'])) { $start_url .= $_SERVER['PATH_INFO']; } // the query string is included in REQUEST_URI, we only need to append it if we're building the URI ourselves if (isset($_SERVER['QUERY_STRING']) && $_SERVER['QUERY_STRING'] != '') { $start_url .= '?' . $_SERVER['QUERY_STRING']; } } /* Strip out the base URL from the requested URL */ /* but only if the base URL isn't / */ if ('/' != $controller->base_url) { if (substr($controller->base_url, -1) == '/') { $controller->base_url = substr($controller->base_url, 0, -1); } $start_url = preg_replace('#^' . preg_quote($controller->base_url, '#') . '#i', '', $start_url); } // undo &s $start_url = str_replace('&', '&', $start_url); /* Trim off any leading or trailing slashes */ $start_url = trim($start_url, '/'); /* Allow plugins to rewrite the stub before it's passed through the rules */ $start_url = Plugins::filter('rewrite_request', $start_url); $controller->stub = $start_url; /* Grab the URL filtering rules from DB */ $matched_rule = URL::parse($controller->stub); if ($matched_rule === false) { $matched_rule = URL::set_404(); } /* OK, we have a matching rule. Set the action and create a handler */ $controller->action = $matched_rule->action; $handler = $matched_rule->handler; // @todo This is pretty kludgy. If there's no namespace in the handler class, add one. if (strpos($handler, '\\') === false) { $handler = '\\Habari\\' . $handler; } $controller->handler = new $handler(); /* Insert the regexed submatches as the named parameters */ $controller->handler->handler_vars['entire_match'] = $matched_rule->entire_match; // The entire matched string is returned at index 0 $controller->handler->handler_vars['matched_rule'] = $matched_rule; foreach ($matched_rule->named_arg_values as $named_arg_key => $named_arg_value) { $controller->handler->handler_vars[$named_arg_key] = $named_arg_value; } /* Also, we musn't forget to add the GET and POST vars into the action's settings array */ $handler_vars = new SuperGlobal($controller->handler->handler_vars); //$handler_vars = $handler_vars->merge( $_GET, $_POST ); $controller->handler->handler_vars = $handler_vars; return true; }
/** * 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 = '…' . 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' => 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(); } }
/** * Validate database credentials for SQLite * Try to connect and verify if database name exists */ public function ajax_check_sqlite_credentials() { $db_file = $_POST['file']; $xml = new \SimpleXMLElement('<response></response>'); // Missing anything? if (!isset($db_file)) { $xml->addChild('status', 0); $xml_error = $xml->addChild('error'); $xml_error->addChild('id', '#databasefile'); $xml_error->addChild('message', _t('The database file was left empty.')); } if (!isset($xml_error)) { if ($db_file == basename($db_file)) { // The filename was given without a path $db_file = Site::get_path('user', true) . $db_file; } if (!is_writable(dirname($db_file))) { $xml->addChild('status', 0); $xml_error = $xml->addChild('error'); $xml_error->addChild('id', '#databasefile'); $xml_error->addChild('message', _t('Cannot write to %s directory. SQLite requires that the directory that holds the DB file be writable by the web server.', array(dirname($db_file)))); } elseif (file_exists(Site::get_path('user', true) . $db_file) && !is_writable(Site::get_path('user', true) . $db_file)) { $xml->addChild('status', 0); $xml_error = $xml->addChild('error'); $xml_error->addChild('id', '#databasefile'); $xml_error->addChild('message', _t('Cannot write to %s. The SQLite data file is not writable by the web server.', array($db_file))); } else { // Can we connect to the DB? $pdo = 'sqlite:' . $db_file; $connect = DB::connect($pdo, null, null); // Disconnect, but no longer delete the file - it could already have contents! DB::disconnect(); switch ($connect) { case true: // We were able to connect to an existing database file. $xml->addChild('status', 1); break; default: // We can't create the database file, send an error message. $xml->addChild('status', 0); $xml_error = $xml->addChild('error'); // TODO: Add error codes handling for user-friendly messages $xml_error->addChild('id', '#databasefile'); $xml_error->addChild('message', $connect->getMessage()); } } } $xml = $xml->asXML(); ob_clean(); header("Content-type: application/xml"); header("Cache-Control: no-cache"); print $xml; }
/** * function action_user_logout * removes the persistent cookie when the user logs out * @param user User the user that is logging out **/ public function action_user_logout($user) { $cookiename = 'P_' . md5(Options::get('GUID') . '_Persistence'); if (!isset($_COOKIE[$cookiename])) { return; } $cookie = $_COOKIE[$cookiename]; $info = 'persistence_' . $cookie; // remove the info record for this cookie unset($user->info->{$info}); // commit the change $user->update(); // remove the cookie from the user's PC setcookie($cookiename, 'empty', time() - 3600, Site::get_path(' base', true)); }
/** * Parses the requested URL. Automatically * translates URLs coming in from mod_rewrite and parses * out any action and parameters in the slug. */ public static function parse_request() { /* Local scope variable caching */ $controller = Controller::instance(); /* Grab the base URL from the Site class */ $controller->base_url = Site::get_path('base', true); /* Start with the entire URL coming from web server... */ $start_url = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : $_SERVER['SCRIPT_NAME'] . (isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '') . (isset($_SERVER['QUERY_STRING']) && $_SERVER['QUERY_STRING'] != '' ? '?' . $_SERVER['QUERY_STRING'] : ''); /* Strip out the base URL from the requested URL */ /* but only if the base URL isn't / */ if ('/' != $controller->base_url) { $start_url = str_replace($controller->base_url, '', $start_url); } // undo &s $start_url = str_replace('&', '&', $start_url); /* Trim off any leading or trailing slashes */ $start_url = trim($start_url, '/'); /* Allow plugins to rewrite the stub before it's passed through the rules */ $start_url = Plugins::filter('rewrite_request', $start_url); $controller->stub = $start_url; /* Grab the URL filtering rules from DB */ $matched_rule = URL::parse($controller->stub); if ($matched_rule === FALSE) { $matched_rule = URL::set_404(); } /* OK, we have a matching rule. Set the action and create a handler */ $controller->action = $matched_rule->action; $controller->handler = new $matched_rule->handler(); /* Insert the regexed submatches as the named parameters */ $controller->handler->handler_vars['entire_match'] = $matched_rule->entire_match; // The entire matched string is returned at index 0 foreach ($matched_rule->named_arg_values as $named_arg_key => $named_arg_value) { $controller->handler->handler_vars[$named_arg_key] = $named_arg_value; } /* Also, we musn't forget to add the GET and POST vars into the action's settings array */ $handler_vars = new SuperGlobal($controller->handler->handler_vars); $handler_vars = $handler_vars->merge($_GET, $_POST); $controller->handler->handler_vars = $handler_vars; return true; }
/** * 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); }