public function filter_default_rewrite_rules($rules) { if ($this->current_load() > self::KILL_LOAD) { foreach ($rules as $key => $rule) { if (strpos($rule['build_str'], 'admin') !== false) { $rules[$key]['handler'] = 'UserThemeHandler'; $rules[$key]['action'] = 'display_throttle'; } } if (Options::get('throttle') == '') { EventLog::log(sprintf(_t('Kill - Load is %s'), $this->current_load())); Options::set('throttle', 'kill'); } } elseif ($this->current_load() > self::MAX_LOAD) { foreach ($rules as $key => $rule) { if ($rule['name'] == 'search') { unset($rules[$key]); } } $rules[] = array('name' => 'search', 'parse_regex' => '%^search(?:/(?P<criteria>[^/]+))?(?:/page/(?P<page>\\d+))?/?$%i', 'build_str' => 'search(/{$criteria})(/page/{$page})', 'handler' => 'UserThemeHandler', 'action' => 'display_throttle', 'priority' => 8, 'description' => 'Searches posts'); if (Options::get('throttle') == '') { EventLog::log(sprintf(_t('Restrict - Load is %s'), $this->current_load())); Options::set('throttle', 'restrict'); } } else { if (Options::get('throttle') != '') { EventLog::log(sprintf(_t('Normal - Load is %s'), $this->current_load())); Options::set('throttle', ''); } } return $rules; }
public function filter_optimize_database($result, $paramarray) { $space_saved = 0; $tables = 0; switch (DB::get_driver_name()) { case 'mysql': $q = 'SHOW TABLE STATUS WHERE data_free > 0'; $tables = DB::get_results($q); if (count($tables) > 0) { foreach ($tables as $table) { $q2 = 'OPTIMIZE TABLE ' . $table->Name; if (DB::query($q2)) { $space_saved += $table->Data_free; $tables++; } } EventLog::log('Database Tables Optimized. ' . Utils::human_size($space_saved) . ' reclaimed from ' . HabariLocale::_n('table', 'tables', $tables) . '.'); } $result = true; break; case 'sqlite': if (DB::exec('VACUUM')) { $result = true; EventLog::log('SQLite database VACUUM\'ed successfully.'); } else { $result = false; } break; default: $result = false; break; } return $result; }
/** * Constructor for RenderCache * * Sets up paths and gets the list of groups from file */ public static function __static() { //Define the cache path and url self::$cache_path = HABARI_PATH . '/' . self::$rel_cache_path; self::$cache_url = Site::get_url('habari') . '/' . self::$rel_cache_path; //If the cache directory doesn't exist, make it if (!is_dir(self::$cache_path)) { mkdir(self::$cache_path, 0755); } //Enable only if the cache directory now exists and is writable self::$enabled = is_dir(self::$cache_path) && is_writeable(self::$cache_path); //Give an error if the cache directory is not writable if (!self::$enabled) { Session::error(sprintf(_t("The cache directory '%s' is not writable - the cache is disabled. The user, or group, which your web server is running as, needs to have read, write, and execute permissions on this directory."), self::$cache_path), 'RenderCache'); EventLog::log(sprintf(_t("The cache directory '%s' is not writable - the cache is disabled."), self::$cache_path), 'notice', 'RenderCache', 'habari'); return; } //Get the list of group names $group_file = self::get_group_list_file(); if (file_exists($group_file)) { self::$group_list = unserialize(file_get_contents($group_file)); } else { self::$group_list = array(); } }
public function filter_linkit_fetch($success) { $stats = $this->api_getstats(); EventLog::log(_t('Running dashboard fetch for 123LinkIt', 'linkit'), 'info', null, null, $stats); Options::set('linkit__stats', $stats); return $success; }
public function filter_rssblocks_update($success, $force = false) { EventLog::log('Running rrsblocks update'); $blocks = DB::get_results('SELECT b.* FROM {blocks} b WHERE b.type = ?', array('rssblock'), 'Block'); Plugins::act('get_blocks', $blocks); $success = true; foreach ($blocks as $block) { $cachename = array('rssblock', md5($block->feed_url)); if ($force || Cache::expired($cachename)) { $r = new RemoteRequest($block->feed_url); $r->set_timeout(10); $r->execute(); $feed = $r->get_response_body(); try { if (is_string($feed)) { new SimpleXMLElement($feed); // This throws an exception if the feed isn't valid Cache::set($cachename, $feed, 3600, true); } } catch (Exception $e) { $success = false; } } } Session::notice('ran rssblocks update'); return $success; }
function action_admin_moderate_comments($action, $comments, $handler) { if ($action == 'approve' || $action == 'approved') { foreach ($comments as $c) { $this->update_post_modified($c->post_id); EventLog::log('bumped post ' . $c->post_id . ', by admin approval', 'info', 'default', 'bumping'); } } }
function action_comment_insert_before($comment) { // This plugin ignores non-comments and comments already marked as spam if ($comment->type == Comment::COMMENT && $comment->status != Comment::STATUS_SPAM) { $comment->status = Comment::STATUS_APPROVED; EventLog::log('Comment by ' . $comment->name . ' automatically approved.', 'info', 'autoapprove', 'autoapprove'); } return $comment; }
/** * Constructor for APCCache */ public function __construct() { $this->prefix = Options::get('private-GUID'); $this->enabled = extension_loaded('apc'); if (!$this->enabled) { Session::error(_t("The APC Cache PHP module is not loaded - the cache is disabled.", "apccache"), 'filecache'); EventLog::log(_t("The APC Cache PHP module is not loaded - the cache is disabled.", "apccache"), 'notice', 'cache', 'apccache'); } }
/** * Reject form submission (and repopulate the form) if the captcha fails. * ... * @return array Message to return upon failure **/ public function validate_captcha($unused, $control, $form) { $solvemedia_response = solvemedia_check_answer(Options::get('solvemedia__vkey'), $_SERVER["REMOTE_ADDR"], $_POST["adcopy_challenge"], $_POST["adcopy_response"], Options::get('solvemedia__hkey')); if ($solvemedia_response->is_valid) { EventLog::log(_t('Comment by %s approved by SolveMedia captcha.', array($comment->name), 'solvemedia'), 'info', 'comment', 'SolveMedia'); } else { return array(_t('Your CAPTCHA attempt did not succeed: %s', array($solvemedia_response->error), 'solvemedia')); } }
public function action_comment_insert_before($comment) { if ($comment->type == Comment::COMMENT && $comment->status != Comment::STATUS_SPAM) { if ($this->check_comment($comment) === false) { $comment->status = Comment::STATUS_SPAM; EventLog::log(sprintf(_t("Comment by %s automatically marked as spam", 'simpleblacklist'), $comment->name), 'info', 'Simple Blacklist', 'plugin'); } } return $comment; }
public function filter_activate_plugin($ok, $file) { // Don't bother loading if the gd library isn't active if (!function_exists('imagecreatefromjpeg')) { EventLog::log(_t("S3 Silo activation failed. PHP has not loaded the gd imaging library."), 'warning', 'plugin'); Session::error(_t("S3 Silo activation failed. PHP has not loaded the gd imaging library.")); $ok = false; } return $ok; }
function action_comment_insert_before($comment) { // This plugin ignores non-comments and comments already marked as spam if ($comment->type == Comment::COMMENT && $comment->status != Comment::STATUS_SPAM) { if (Comments::get(array('email' => $comment->email, 'name' => $comment->name, 'url' => $comment->url, 'status' => Comment::STATUS_APPROVED))->count >= Options::get('preapproved__approved_count')) { $comment->status = Comment::STATUS_APPROVED; EventLog::log('Comment by ' . $comment->name . ' automatically approved.', 'info', 'PreApproved', 'PreApproved'); } } return $comment; }
/** * Constructor for MemcacheCache * * Sets up paths etc. and reads cache index, if it exists. */ public function __construct() { $this->prefix = Options::get('GUID'); $this->enabled = extension_loaded('memcache'); if ($this->enabled) { $this->memcache = new Memcache(); $this->memcache->connect(Config::get('memcache_host', 'localhost'), Config::get('memcache_port', 11211)); $this->cache_index = $this->memcache->get('habari:cache:index'); } else { Session::error(_t("The Memcache PHP module is not loaded - the cache is disabled.", "memcache"), 'memcachecache'); EventLog::log(_t("The Memcache PHP module is not loaded - the cache is disabled.", "memcache"), 'notice', 'cache', 'memcachecache'); } }
public function action_init() { //$this->add_template('event.single', dirname(__FILE__) . '/event.single.php'); Post::add_new_type('imageset', false); Post::add_new_type('image', false); Post::add_new_type('gallery', false); CpgDb::registerTables(); //Utils::debug('tables registered!'); if (CpgDb::DB_VERSION > CpgOptions::getDbVersion()) { CpgDb::install(); EventLog::log('Updated CPG.'); CpgOptions::setDbVersion(CpgDb::DB_VERSION); } }
/** * Helper function which automatically assigns all handler_vars * into the theme and displays a theme template * * @param template_name Name of template to display ( note: not the filename ) */ protected function display($template_name) { /* * Assign internal variables into the theme ( and therefore into the theme's template * engine. See Theme::assign(). */ foreach ($this->handler_vars as $key => $value) { $this->theme->assign($key, $value); } try { $this->theme->display($template_name); } catch (Error $e) { EventLog::log($e->humane_error(), 'error', 'theme', 'habari', print_r($e, 1)); } }
public function filter_activate_plugin( $ok, $file ) { if ( Plugins::id_from_file($file) == Plugins::id_from_file(__FILE__) ) { if ( !$this->check_files() ) { EventLog::log( _t( "Habari Silo activation failed. The web server does not have permission to create the 'files' directory for the Habari Media Silo." ), 'warning', 'plugin' ); Session::error( _t( "Habari Silo activation failed. The web server does not have permission to create the 'files' directory for the Habari Media Silo." ) ); $ok = false; } // Don't bother loading if the gd library isn't active if ( !function_exists( 'imagecreatefromjpeg' ) ) { EventLog::log( _t( "Habari Silo activation failed. PHP has not loaded the gd imaging library." ), 'warning', 'plugin' ); Session::error( _t( "Habari Silo activation failed. PHP has not loaded the gd imaging library." ) ); $ok = false; } } return $ok; }
/** * function undelete_post * This function reverts a post's status from 'deleted' to whatever * it previously was. **/ private function undelete_post($post_id) { $post = Post::get(array('id' => $post_id, 'status' => Post::status('any'))); if ($post->status == Post::status('deleted')) { $post->status = $post->info->prior_status ? $post->info->prior_status : Post::status('draft'); unset($post->info->prior_status); $post->update(); EventLog::log(sprintf(_t('Post %1$s (%2$s) restored.'), $post->id, $post->slug), 'info', 'content', 'habari'); //scheduled post if ($post->status == Post::status('scheduled')) { Posts::update_scheduled_posts_cronjob(); } return true; } else { return false; } }
/** * Constructor for FileCache * * Sets up paths etc. and reads cache index, if it exists. */ public function __construct() { if (!defined('FILE_CACHE_LOCATION')) { define('FILE_CACHE_LOCATION', HABARI_PATH . '/user/cache/'); } $this->cache_location = FILE_CACHE_LOCATION; $this->index_file = $this->cache_location . md5('index' . Options::get('GUID')) . '.data'; $this->enabled = is_writeable($this->cache_location); if ($this->enabled) { if (file_exists($this->index_file)) { $this->cache_files = unserialize(file_get_contents($this->index_file)); } } else { Session::error(_t("The cache directory '%s' is not writable - the cache is disabled. The user, or group, which your web server is running as, needs to have read, write, and execute permissions on this directory.", array($this->cache_location)), 'filecache'); EventLog::log(_t("The cache directory '%s' is not writable - the cache is disabled.", array($this->cache_location)), 'notice', 'cache', 'habari'); } }
public function filter_user_authenticate($user, $username, $password) { $passwdfile = Options::get('passwdlogins__file'); if (!$passwdfile) { EventLog::log(_t('No passwd file configured!'), 'err', 'passwdlogins', 'passwdlogins'); return false; } if (!file_exists($passwdfile)) { EventLog::log(_t('Passwd file does not exist: %1$s', array($passwdfile)), 'err', 'passwdlogins', 'passwdlogins'); return false; } // go ahead and trim the user and password $username = trim($username); $password = trim($password); // blank usernames and passwords are not allowed if ($username == '' || $password == '') { return false; } $users = $this->parse_htpasswd($passwdfile); if (isset($users[$username])) { $crypt_pass = $users[$username]; if ($crypt_pass[0] == '{') { // figure out the algorithm used for this password $algo = MultiByte::strtolower(MultiByte::substr($crypt_pass, 1, MultiByte::strpos($crypt_pass, '}', 1) - 1)); $passok = false; switch ($algo) { case 'ssha': $hash = base64_decode(MultiByte::substr($crypt_pass, 6)); $passok = MultiByte::substr($hash, 0, 20) == pack("H*", sha1($password . MultiByte::substr($hash, 20))); break; case 'sha': $passok = '{SHA}' . base64_encode(pack("H*", sha1($password))) == $crypt_pass; break; } } else { // it's plain crypt $passok = crypt($password, MultiByte::substr($crypt_pass, 0, CRYPT_SALT_LENGTH)) == $crypt_pass; } if ($passok == true) { return $this->get_user($username); } } // returning $user would continue the login check through other plugins and core - we want to force passwd logins return false; }
/** * Executes all cron jobs in the DB if there are any to run. * * @param boolean $async If true, allows execution to continue by making an asynchronous request to a cron URL */ static function run_cron($async = false) { // check if it's time to run crons, and if crons are already running. $next_cron = HabariDateTime::date_create(Options::get('next_cron', 1)); $time = HabariDateTime::date_create(); if ($next_cron->int > $time->int || Options::get('cron_running') && Options::get('cron_running') > microtime(true)) { return; } // cron_running will timeout in 10 minutes // round cron_running to 4 decimals $run_time = microtime(true) + 600; $run_time = sprintf("%.4f", $run_time); Options::set('cron_running', $run_time); if ($async) { // Timeout is really low so that it doesn't wait for the request to finish $cronurl = URL::get('cron', array('time' => $run_time, 'asyncronous' => Utils::crypt(Options::get('GUID')))); $request = new RemoteRequest($cronurl, 'GET', 1); try { $request->execute(); } catch (RemoteRequest_Timeout $e) { // the request timed out - we knew that would happen } catch (Exception $e) { // some other error occurred. log it. EventLog::log($e->getMessage(), 'err', 'crontab', 'habari', $e); } } else { // @todo why do we usleep() and why don't we just call act_poll_cron()? usleep(5000); if (Options::get('cron_running') != $run_time) { return; } $time = HabariDateTime::date_create(); $crons = DB::get_results('SELECT * FROM {crontab} WHERE start_time <= ? AND next_run <= ? AND active != ?', array($time->sql, $time->sql, 0), 'CronJob'); if ($crons) { foreach ($crons as $cron) { $cron->execute(); } } EventLog::log(_t('CronTab run completed.'), 'debug', 'crontab', 'habari', $crons); // set the next run time to the lowest next_run OR a max of one day. $next_cron = DB::get_value('SELECT next_run FROM {crontab} ORDER BY next_run ASC LIMIT 1', array()); Options::set('next_cron', min(intval($next_cron), $time->modify('+1 day')->int)); Options::set('cron_running', false); } }
/** * Get log entries by multiple ids */ public function test_get_logs_by_ids() { $expected = array(); $expected[] = EventLog::log('Test get_logs_by_id entry #1', 'info', 'default', 'habari'); $expected[] = EventLog::log('Test get_logs_by_id entry #2', 'info', 'default', 'habari'); $ids = array(); foreach ($expected as $entry) { $ids[] = $entry->id; } $result = EventLog::get(array('id' => $ids)); $this->assert_true($result instanceof EventLog, 'Result should be of type EventLog'); // @todo This currently isn't true, because the options limit is respected. Should it be? //$this->assert_equal( count( $result ), count( $expected ), 'The number of posts we asked for should be returned' ); foreach ($result as $r) { $this->assert_true($r instanceof LogEntry, 'Items should be of type LogEntry'); $this->assert_true(in_array($r->id, $ids), 'id of returned LogEntry should be in the list of the ones we asked for'); } }
public function filter_send_mail($handled, $mail) { if (!$handled) { $headers = array('Accept: application/json', 'Content-Type: application/json', 'X-Postmark-Server-Token: ' . Options::get('postmark__apikey')); $data = array('To' => $mail['to'], 'subject' => $mail['subject'], 'TextBody' => $mail['message'], 'From' => $mail['headers']['From']); $rr = new RemoteRequest('http://api.postmarkapp.com/email', 'POST'); $rr->set_body(json_encode($data)); $rr->add_headers($headers); try { $rr->execute(); EventLog::log(_t('Send message to %s via Postmark', array($mail['to'])), 'info', 'default', null, array($data, $headers)); Session::notice(var_export($rr->get_response_headers(), 1)); } catch (Exception $e) { EventLog::log(_t('Failed to send message to %s via Postmark', array($mail['to'])), 'err', 'default', null, array($e->getMessage(), $data, $headers)); Session::error('There was a problem sending your message. Please contact the site administrators directly.'); } } return true; }
/** * Filters any messages sent through the Utils::mail() function, attempting to send them via SMTP instead. * * @param boolean Whether this message has already been handled by another plugin or not. * @param array The content of the message to send. * @return boolean Whether or not this plugin handled the message. **/ function filter_send_mail($handled, $mail) { require dirname(__FILE__) . '/mail.php'; // Start SMTP object $smtp = new Mail_SMTP(array('host' => (Options::get('mailsmtp__ssl') ? 'ssl://' : '') . Options::get('mailsmtp__hostname'), 'port' => (int) Options::get('mailsmtp__port'), 'auth' => (bool) Options::get('mailsmtp__auth'), 'username' => Options::get('mailsmtp__username'), 'password' => Options::get('mailsmtp__password'))); // Make header array $headers = array_merge($mail['headers'], array('To' => $mail['to'], 'Subject' => $mail['subject'], 'From' => Options::get('mailsmtp__from'))); // Send! $result = $smtp->send($mail['to'], $headers, $mail['message']); if ($result === true) { $handled = true; return true; } else { // log the reason why EventLog::log(_t('Unable to send SMTP message: %s', array($result->get()))); $handled = false; return false; } }
public function action_comment_insert_before(Comment $comment) { $api_key = Options::get('habariakismet__api_key'); $provider = Options::get('habariakismet__provider'); if ($api_key == null || $provider == null) { return; } $endpoint = $provider == 'Akismet' ? self::SERVER_AKISMET : self::SERVER_TYPEPAD; $a = new Akismet(Site::get_url('habari'), $api_key); $a->setAkismetServer($endpoint); $a->setCommentAuthor($comment->name); $a->setCommentAuthorEmail($comment->email); $a->setCommentAuthorURL($comment->url); $a->setCommentContent($comment->content); $a->setPermalink($comment->post->permalink); try { $comment->status = $a->isCommentSpam() ? 'spam' : 'ham'; return; } catch (Exception $e) { EventLog::log($e->getMessage(), 'notice', 'comment', 'HabariAkismet'); } }
/** * function delete * Deletes an existing tag and all relations to it (e.g. a post2tag relationship) */ public function delete() { $allow = true; $allow = Plugins::filter('tag_delete_allow', $allow, $this); if (!$allow) { return; } // invoke plugins Plugins::act('tag_delete_before', $this); // Delete all tag2post records associated with this tag $sql = "DELETE FROM {tag2post} WHERE tag_id = ?"; DB::query($sql, array($this->id)); // Delete the parent tags record $result = parent::deleteRecord(DB::table('tags'), array('id' => $this->id)); EventLog::log(sprintf(_t('Tag %1$s (%2$s) deleted.'), $this->id, $this->tag_text), 'info', 'content', 'habari'); Plugins::act('tag_delete_after', $this); return $result; }
/** * TODO: be more careful * INSERT INTO {tag2post} / SELECT $master_tag->ID,post_ID FROM {tag2post} WHERE tag_id = $tag->id" and then "DELETE FROM {tag2post} WHERE tag_id = $tag->id" * Renames tags. * If the master tag exists, the tags will be merged with it. * If not, it will be created first. * * @param Array tags The tag text, slugs or ids to be renamed * @param mixed master The Tag to which they should be renamed, or the slug, text or id of it **/ public static function rename($master, $tags) { if (!is_array($tags)) { $tags = array($tags); } $tag_names = array(); // get array of existing tags first to make sure we don't conflict with a new master tag foreach ($tags as $tag) { $posts = array(); $post_ids = array(); $tag = Tags::get_one($tag); // get all the post ID's tagged with this tag $posts = DB::get_results('SELECT post_id FROM {tag2post} WHERE tag_id = ?', array($tag->id)); if (count($posts) > 0) { // build a list of all the post_id's we need for the new tag foreach ($posts as $post) { $post_ids[] = $post->post_id; } $tag_names[] = $tag->tag; } Tags::delete($tag); } // get the master tag $master_tag = Tags::get_one($master); if (!isset($master_tag->slug)) { // it didn't exist, so we assume it's tag text and create it $master_tag = Tag::create(array('tag_slug' => Utils::slugify($master), 'tag_text' => $master)); $master_ids = array(); } else { // get the posts the tag is already on so we don't duplicate them $master_posts = DB::get_results('SELECT post_id FROM {tag2post} WHERE tag_id = ?', array($master_tag->id)); $master_ids = array(); foreach ($master_posts as $master_post) { $master_ids[] = $master_post->post_id; } } if (count($post_ids) > 0) { // only try and add the master tag to posts it's not already on $post_ids = array_diff($post_ids, $master_ids); // link the master tag to each distinct post we removed tags from foreach ($post_ids as $post_id) { DB::query('INSERT INTO {tag2post} ( tag_id, post_id ) VALUES ( ?, ? )', array($master_tag->id, $post_id)); } } EventLog::log(sprintf(_n('Tag %s has been renamed to %s.', 'Tags %s have been renamed to %s.', count($tags)), implode($tag_names, ', '), $master), 'info', 'tag', 'habari'); }
/** * function delete * Deletes all comments in this object */ public function delete() { $result = true; foreach ($this as $c) { $result &= $c->delete(); EventLog::log(sprintf(_t('Comment %1$s deleted from %2$s'), $c->id, $c->post->title), 'info', 'comment', 'habari'); } // Clear ourselves. $this->exchangeArray(array()); return $result; }
/** * Remove one or more user from this group * @param mixed $users A user ID or name, or an array of the same */ public function remove( $users ) { $this->load_member_cache(); $users = Utils::single_array( $users ); // Use ids internally for all users $users = array_map( array( 'User', 'get_id' ), $users ); // Remove users from group membership $this->member_ids = array_diff( $this->member_ids, $users ); $this->update(); EventLog::log( _t( 'User Group %1$s: Users were removed from the group.', array( $this->name ) ), 'notice', 'user', 'habari' ); }
/** * function publish * Updates an existing post to published status * @return boolean True on success, false if not */ public function publish() { if ( $this->status == Post::status( 'published' ) ) { return true; } $allow = true; $allow = Plugins::filter( 'post_publish_allow', $allow, $this ); if ( ! $allow ) { return; } Plugins::act( 'post_publish_before', $this ); if ( $this->status != Post::status( 'scheduled' ) ) { $this->pubdate = HabariDateTime::date_create(); } if ( $this->status == Post::status( 'scheduled' ) ) { $msg = sprintf( _t( 'Scheduled Post %1$s (%2$s) published at %3$s.' ), $this->id, $this->slug, $this->pubdate->format() ); } else { $msg = sprintf( _t( 'Post %1$s (%2$s) published.' ), $this->id, $this->slug ); } $this->status = Post::status( 'published' ); $result = $this->update( false ); EventLog::log( $msg, 'info', 'content', 'habari' ); // and call any final plugins Plugins::act( 'post_publish_after', $this ); return $result; }
public static function purge() { $result = DB::query('DELETE FROM {log}'); if ($result) { EventLog::log(_t('Logs purged.'), 'info'); } return $result; }