示例#1
0
 /**
  * Get an instance of the module manager.
  * 
  * @param array|null $default_active_modules
  * @return blcModuleManager
  */
 static function getInstance($default_active_modules = null)
 {
     static $instance = null;
     if (is_null($instance)) {
         $instance = new blcModuleManager();
         $instance->init($default_active_modules);
     }
     return $instance;
 }
 /**
  * Class "constructor". Can't use an actual constructor due to how PHP4 handles object references.
  * 
  * Specifically, this class is a singleton. The function needs to pass $this to several other 
  * functions (to set up hooks), which will store the reference for later use. However, it appears 
  * that in PHP4 the actual value of $this is thrown away right after the constructor finishes, and
  * `new` returns a *copy* of $this. The result is that getInstance() won't be returning a ref.
  * to the same object as is used for hook callbacks. And that's horrible.   
  * 
  * Sets up hooks that monitor added/modified/deleted posts and registers
  * virtual modules for all post types.
  *
  * @return void
  */
 function init()
 {
     $this->plugin_conf = blc_get_configuration();
     if (isset($this->plugin_conf->options['enabled_post_statuses'])) {
         $this->enabled_post_statuses = $this->plugin_conf->options['enabled_post_statuses'];
     }
     //Register a virtual container module for each enabled post type
     $module_manager = blcModuleManager::getInstance();
     $post_types = get_post_types(array(), 'objects');
     $exceptions = array('revision', 'nav_menu_item', 'attachment');
     foreach ($post_types as $data) {
         $post_type = $data->name;
         if (in_array($post_type, $exceptions)) {
             continue;
         }
         $module_manager->register_virtual_module($post_type, array('Name' => $data->labels->name, 'ModuleCategory' => 'container', 'ModuleContext' => 'all', 'ModuleClassName' => 'blcAnyPostContainerManager'));
     }
     //These hooks update the synch & instance records when posts are added, deleted or modified.
     add_action('delete_post', array(&$this, 'post_deleted'));
     add_action('save_post', array(&$this, 'post_saved'));
     //We also treat post trashing/untrashing as delete/save.
     add_action('trash_post', array(&$this, 'post_deleted'));
     add_action('untrash_post', array(&$this, 'post_saved'));
     //Highlight and nofollow broken links in posts & pages
     if ($this->plugin_conf->options['mark_broken_links'] || $this->plugin_conf->options['nofollow_broken_links']) {
         add_filter('the_content', array(&$this, 'hook_the_content'));
         if ($this->plugin_conf->options['mark_broken_links'] && !empty($this->plugin_conf->options['broken_link_css'])) {
             add_action('wp_head', array(&$this, 'hook_wp_head'));
         }
     }
 }
示例#3
0
 /**
  * A helper method for parsing a list of search criteria and generating the parts of the SQL query.
  *
  * @see blcLinkQuery::get_links() 
  *
  * @param array $params An array of search criteria.
  * @return array 'where_exprs' - an array of search expressions, 'join_instances' - whether joining the instance table is required. 
  */
 function compile_search_params($params)
 {
     global $wpdb;
     /** @var wpdb $wpdb */
     //Track whether we'll need to left-join the instance table to run the query.
     $join_instances = false;
     //Generate the individual clauses of the WHERE expression and store them in an array.
     $pieces = array();
     //Convert parser and container type lists to arrays of valid values
     $s_parser_type = array();
     if (!empty($params['s_parser_type'])) {
         $s_parser_type = $params['s_parser_type'];
         if (is_string($s_parser_type)) {
             $s_parser_type = preg_split('/[,\\s]+/', $s_parser_type);
         }
     }
     $s_container_type = array();
     if (!empty($params['s_container_type'])) {
         $s_container_type = $params['s_container_type'];
         if (is_string($s_container_type)) {
             $s_container_type = preg_split('/[,\\s]+/', $s_container_type);
         }
     }
     //Don't include links with instances that reference invalid (not currently loaded)
     //containers and parsers (unless specifically told to also include invalid links).
     if (empty($params['include_invalid'])) {
         $join_instances = true;
         $module_manager = blcModuleManager::getInstance();
         $loaded_containers = array_keys($module_manager->get_active_by_category('container'));
         $loaded_parsers = array_keys($module_manager->get_active_by_category('parser'));
         if (empty($s_parser_type)) {
             $s_parser_type = $loaded_parsers;
         } else {
             $s_parser_type = array_intersect($s_parser_type, $loaded_parsers);
         }
         if (empty($s_container_type)) {
             $s_container_type = $loaded_containers;
         } else {
             $s_container_type = array_intersect($s_container_type, $loaded_containers);
         }
     }
     //Parser type should match the parser_type column in the instance table.
     if (!empty($s_parser_type)) {
         $s_parser_type = array_map('trim', array_unique($s_parser_type));
         $s_parser_type = array_map('esc_sql', $s_parser_type);
         if (count($s_parser_type) == 1) {
             $pieces[] = sprintf("instances.parser_type = '%s'", reset($s_parser_type));
         } else {
             $pieces[] = "instances.parser_type IN ('" . implode("', '", $s_parser_type) . "')";
         }
         $join_instances = true;
     }
     //Container type should match the container_type column in the instance table.
     if (!empty($s_container_type)) {
         //Sanitize for use in SQL
         $s_container_type = array_map('trim', array_unique($s_container_type));
         $s_container_type = array_map('esc_sql', $s_container_type);
         if (count($s_container_type) == 1) {
             $pieces[] = sprintf("instances.container_type = '%s'", reset($s_container_type));
         } else {
             $pieces[] = "instances.container_type IN ('" . implode("', '", $s_container_type) . "')";
         }
         $join_instances = true;
     }
     //A part of the WHERE expression can be specified explicitly
     if (!empty($params['where_expr'])) {
         $pieces[] = $params['where_expr'];
         $join_instances = $join_instances || stripos($params['where_expr'], 'instances') !== false;
     }
     //List of allowed link ids (either an array or comma-separated)
     if (!empty($params['link_ids'])) {
         $link_ids = $params['link_ids'];
         if (is_string($link_ids)) {
             $link_ids = preg_split('/[,\\s]+/', $link_ids);
         }
         //Only accept non-zero integers
         $sanitized_link_ids = array();
         foreach ($link_ids as $id) {
             $id = intval($id);
             if ($id != 0) {
                 $sanitized_link_ids[] = $id;
             }
         }
         $pieces[] = 'links.link_id IN (' . implode(', ', $sanitized_link_ids) . ')';
     }
     //Anchor text - use LIKE search
     if (!empty($params['s_link_text'])) {
         $s_link_text = esc_sql($this->esc_like($params['s_link_text']));
         $s_link_text = str_replace('*', '%', $s_link_text);
         $pieces[] = '(instances.link_text LIKE "%' . $s_link_text . '%")';
         $join_instances = true;
     }
     //URL - try to match both the initial URL and the final URL.
     //There is limited wildcard support, e.g. "google.*/search" will match both
     //"google.com/search" and "google.lv/search"
     if (!empty($params['s_link_url'])) {
         $s_link_url = esc_sql($this->esc_like($params['s_link_url']));
         $s_link_url = str_replace('*', '%', $s_link_url);
         $pieces[] = '(links.url LIKE "%' . $s_link_url . '%") OR ' . '(links.final_url LIKE "%' . $s_link_url . '%")';
     }
     //Container ID should match... you guessed it - container_id
     if (!empty($params['s_container_id'])) {
         $s_container_id = intval($params['s_container_id']);
         if ($s_container_id != 0) {
             $pieces[] = "instances.container_id = {$s_container_id}";
             $join_instances = true;
         }
     }
     //Link type can match either the the parser_type or the container_type.
     if (!empty($params['s_link_type'])) {
         $s_link_type = esc_sql($params['s_link_type']);
         $pieces[] = "instances.parser_type = '{$s_link_type}' OR instances.container_type='{$s_link_type}'";
         $join_instances = true;
     }
     //HTTP code - the user can provide a list of HTTP response codes and code ranges.
     //Example : 201,400-410,500
     if (!empty($params['s_http_code'])) {
         //Strip spaces.
         $params['s_http_code'] = str_replace(' ', '', $params['s_http_code']);
         //Split by comma
         $codes = explode(',', $params['s_http_code']);
         $individual_codes = array();
         $ranges = array();
         //Try to parse each response code or range. Invalid ones are simply ignored.
         foreach ($codes as $code) {
             if (is_numeric($code)) {
                 //It's a single number
                 $individual_codes[] = abs(intval($code));
             } elseif (strpos($code, '-') !== false) {
                 //Try to parse it as a range
                 $range = explode('-', $code, 2);
                 if (count($range) == 2 && is_numeric($range[0]) && is_numeric($range[0])) {
                     //Make sure the smaller code comes first
                     $range = array(intval($range[0]), intval($range[1]));
                     $ranges[] = array(min($range), max($range));
                 }
             }
         }
         $piece = array();
         //All individual response codes get one "http_code IN (...)" clause
         if (!empty($individual_codes)) {
             $piece[] = '(links.http_code IN (' . implode(', ', $individual_codes) . '))';
         }
         //Ranges get a "http_code BETWEEN min AND max" clause each
         if (!empty($ranges)) {
             $range_strings = array();
             foreach ($ranges as $range) {
                 $range_strings[] = "(links.http_code BETWEEN {$range['0']} AND {$range['1']})";
             }
             $piece[] = '( ' . implode(' OR ', $range_strings) . ' )';
         }
         //Finally, generate a composite WHERE clause for both types of response code queries
         if (!empty($piece)) {
             $pieces[] = implode(' OR ', $piece);
         }
     }
     //Dismissed links are included by default, but can explicitly included
     //or filtered out by passing a special param.
     if (isset($params['s_include_dismissed'])) {
         $s_include_dismissed = !empty($params['s_include_dismissed']);
         $pieces['filter_dismissed'] = $s_include_dismissed ? '1' : '(dismissed = 0)';
     }
     //Optionally sorting is also possible
     $order_exprs = array();
     if (!empty($params['orderby'])) {
         $allowed_columns = array('url' => 'links.url', 'link_text' => 'instances.link_text');
         $column = $params['orderby'];
         $direction = !empty($params['order']) ? strtolower($params['order']) : 'asc';
         if (!in_array($direction, array('asc', 'desc'))) {
             $direction = 'asc';
         }
         if (array_key_exists($column, $allowed_columns)) {
             $order_exprs[] = $allowed_columns[$column] . ' ' . $direction;
         }
     }
     //Custom filters can optionally call one of the native filters
     //to narrow down the result set.
     if (!empty($params['s_filter']) && isset($this->native_filters[$params['s_filter']])) {
         $the_filter = $this->native_filters[$params['s_filter']];
         $extra_criteria = $this->compile_search_params($the_filter['params']);
         $pieces = array_merge($extra_criteria['where_exprs'], $pieces);
         $join_instances = $join_instances || $extra_criteria['join_instances'];
     }
     return array('where_exprs' => $pieces, 'join_instances' => $join_instances, 'order_exprs' => $order_exprs);
 }
 /**
  * Remove instances that reference invalid containers or containers/parsers that are not currently loaded
  *
  * @return bool
  */
 function blc_cleanup_instances()
 {
     global $wpdb;
     global $blclog;
     //Delete all instances that reference non-existent containers
     $q = "DELETE instances.*\n\t\t  FROM \n  \t\t\t{$wpdb->prefix}blc_instances AS instances LEFT JOIN {$wpdb->prefix}blc_synch AS synch\n  \t\t\tON instances.container_type = synch.container_type AND instances.container_id = synch.container_id\n\t\t  WHERE\n \t\t\tsynch.container_id IS NULL";
     $rez = $wpdb->query($q);
     $blclog->log(sprintf('... %d instances deleted', $wpdb->rows_affected));
     //Delete instances that reference containers and parsers that are no longer active
     $manager =& blcModuleManager::getInstance();
     $active_containers = $manager->get_escaped_ids('container');
     $active_parsers = $manager->get_escaped_ids('parser');
     $q = "DELETE instances.*\n\t      FROM {$wpdb->prefix}blc_instances AS instances\n\t      WHERE\n\t        instances.container_type NOT IN ({$active_containers}) OR\n\t        instances.parser_type NOT IN ({$active_parsers})";
     $rez2 = $wpdb->query($q);
     $blclog->log(sprintf('... %d more instances deleted', $wpdb->rows_affected));
     return $rez !== false && $rez2 !== false;
 }
示例#5
0
$blc_config_manager->options['installation_complete'] = false;
$blc_config_manager->options['installation_flag_cleared_on'] = date('c') . ' (' . microtime(true) . ')';
//Note the time of the first installation (not very accurate, but still useful)
if (empty($blc_config_manager->options['first_installation_timestamp'])) {
    $blc_config_manager->options['first_installation_timestamp'] = time();
}
$blc_config_manager->save_options();
$blclog->info('Installation/update begins.');
//Load the base classes and utilities
require_once BLC_DIRECTORY . '/includes/links.php';
require_once BLC_DIRECTORY . '/includes/link-query.php';
require_once BLC_DIRECTORY . '/includes/instances.php';
require_once BLC_DIRECTORY . '/includes/utility-class.php';
//Load the module subsystem
require_once BLC_DIRECTORY . '/includes/modules.php';
$moduleManager = blcModuleManager::getInstance();
//If upgrading, activate/deactivate custom field and comment containers based on old ver. settings
if (isset($blc_config_manager->options['check_comment_links'])) {
    if (!$blc_config_manager->options['check_comment_links']) {
        $moduleManager->deactivate('comment');
    }
    unset($blc_config_manager->options['check_comment_links']);
}
if (empty($blc_config_manager->options['custom_fields'])) {
    $moduleManager->deactivate('custom_field');
}
//Prepare the database.
$blclog->info('Upgrading the database...');
$upgrade_start = microtime(true);
require_once BLC_DIRECTORY . '/includes/admin/db-upgrade.php';
blcDatabaseUpgrader::upgrade_database();
示例#6
0
 /**
  * Retrieve links that need to be checked or re-checked.
  *
  * @param integer $max_results The maximum number of links to return. Defaults to 0 = no limit.
  * @param bool $count_only If true, only the number of found links will be returned, not the links themselves. 
  * @return int|blcLink[]
  */
 function get_links_to_check($max_results = 0, $count_only = false)
 {
     global $wpdb;
     /* @var wpdb $wpdb */
     $check_threshold = date('Y-m-d H:i:s', strtotime('-' . $this->conf->options['check_threshold'] . ' hours'));
     $recheck_threshold = date('Y-m-d H:i:s', time() - $this->conf->options['recheck_threshold']);
     //FB::log('Looking for links to check (threshold : '.$check_threshold.', recheck_threshold : '.$recheck_threshold.')...');
     //Select some links that haven't been checked for a long time or
     //that are broken and need to be re-checked again. Links that are
     //marked as "being checked" and have been that way for several minutes
     //can also be considered broken/buggy, so those will be selected
     //as well.
     //Only check links that have at least one valid instance (i.e. an instance exists and
     //it corresponds to one of the currently loaded container/parser types).
     $manager = blcModuleManager::getInstance();
     $loaded_containers = $manager->get_escaped_ids('container');
     $loaded_parsers = $manager->get_escaped_ids('parser');
     //Note : This is a slow query, but AFAIK there is no way to speed it up.
     //I could put an index on last_check_attempt, but that value is almost
     //certainly unique for each row so it wouldn't be much better than a full table scan.
     if ($count_only) {
         $q = "SELECT COUNT(links.link_id)\n";
     } else {
         $q = "SELECT links.*\n";
     }
     $q .= "FROM {$wpdb->prefix}blc_links AS links\r\n\t\t      WHERE \r\n\t\t      \t(\r\n\t\t\t\t  \t( last_check_attempt < %s ) \r\n\t\t\t\t\tOR \r\n\t\t\t \t  \t( \r\n\t\t\t\t\t\t(broken = 1 OR being_checked = 1) \r\n\t\t\t\t\t\tAND may_recheck = 1\r\n\t\t\t\t\t\tAND check_count < %d \r\n\t\t\t\t\t\tAND last_check_attempt < %s \r\n\t\t\t\t\t)\r\n\t\t\t\t)\r\n\t\t\t\tAND EXISTS (\r\n\t\t\t\t\tSELECT 1 FROM {$wpdb->prefix}blc_instances AS instances\r\n\t\t\t\t\tWHERE \r\n\t\t\t\t\t\tinstances.link_id = links.link_id\r\n\t\t\t\t\t\tAND ( instances.container_type IN ({$loaded_containers}) )\r\n\t\t\t\t\t\tAND ( instances.parser_type IN ({$loaded_parsers}) )\r\n\t\t\t\t)\r\n\t\t\t";
     if (!$count_only) {
         $q .= "\nORDER BY last_check_attempt ASC\n";
         if (!empty($max_results)) {
             $q .= "LIMIT " . intval($max_results);
         }
     }
     $link_q = $wpdb->prepare($q, $check_threshold, $this->conf->options['recheck_count'], $recheck_threshold);
     //FB::log($link_q, "Find links to check");
     //If we just need the number of links, retrieve it and return
     if ($count_only) {
         return $wpdb->get_var($link_q);
     }
     //Fetch the link data
     $link_data = $wpdb->get_results($link_q, ARRAY_A);
     if (empty($link_data)) {
         return array();
     }
     //Instantiate blcLink objects for all fetched links
     $links = array();
     foreach ($link_data as $data) {
         $links[] = new blcLink($data);
     }
     return $links;
 }
示例#7
0
 /**
  * Get all parsers that support either the specified format or the container type.
  * If a parser supports both, it will still be included only once.
  *
  * @param string $format
  * @param string $container_type
  * @return array of blcParser
  */
 static function get_parsers($format, $container_type)
 {
     $found = array();
     //Retrieve a list of active parsers
     $manager = blcModuleManager::getInstance();
     $active_parsers = $manager->get_modules_by_category('parser');
     //Try each one
     foreach ($active_parsers as $module_id => $module_data) {
         $parser = $manager->get_module($module_id);
         //Will autoload if necessary
         if (!$parser) {
             continue;
         }
         if (in_array($format, $parser->supported_formats) || in_array($container_type, $parser->supported_containers)) {
             array_push($found, $parser);
         }
     }
     return $found;
 }
 /**
  * Remove synch. records that reference container types not currently loaded
  * 
  * @return bool
  */
 static function cleanup_containers()
 {
     global $wpdb;
     /* @var wpdb $wpdb */
     global $blclog;
     $module_manager = blcModuleManager::getInstance();
     $start = microtime(true);
     $active_containers = $module_manager->get_escaped_ids('container');
     $q = "DELETE synch.*\r\n\t\t      FROM {$wpdb->prefix}blc_synch AS synch\r\n\t\t      WHERE\r\n\t      \t    synch.container_type NOT IN ({$active_containers})";
     $rez = $wpdb->query($q);
     $elapsed = microtime(true) - $start;
     $blclog->log(sprintf('... %d synch records deleted in %.3f seconds', $wpdb->rows_affected, $elapsed));
     return $rez !== false;
 }
 /**
  * Remove synch. records that reference container types not currently loaded
  * 
  * @return bool
  */
 function cleanup_containers()
 {
     global $wpdb;
     global $blclog;
     $module_manager =& blcModuleManager::getInstance();
     $active_containers = $module_manager->get_escaped_ids('container');
     $q = "DELETE synch.*\n\t\t      FROM {$wpdb->prefix}blc_synch AS synch\n\t\t      WHERE\n\t      \t    synch.container_type NOT IN ({$active_containers})";
     $rez = $wpdb->query($q);
     $blclog->log(sprintf('... %d synch records deleted', $wpdb->rows_affected));
     return $rez !== false;
 }
示例#10
0
 /**
  * Get a checker object that can check the specified URL. 
  *
  * @param string $url
  * @return blcChecker|null
  */
 static function get_checker_for($url)
 {
     $parsed = @parse_url($url);
     $manager = blcModuleManager::getInstance();
     $active_checkers = $manager->get_active_by_category('checker');
     foreach ($active_checkers as $module_id => $module_data) {
         //Try the URL pattern in the header first. If it doesn't match,
         //we can avoid loading the module altogether.
         if (!empty($module_data['ModuleCheckerUrlPattern'])) {
             if (!preg_match($module_data['ModuleCheckerUrlPattern'], $url)) {
                 continue;
             }
         }
         $checker = $manager->get_module($module_id);
         if (!$checker) {
             continue;
         }
         //The can_check() method can perform more sophisticated filtering,
         //or just return true if the checker thinks matching the URL regex
         //is sufficient.
         if ($checker->can_check($url, $parsed)) {
             return $checker;
         }
     }
     $checker = null;
     return $checker;
 }
示例#11
0
<?php

/**
 * Load all files pertaining to BLC's module subsystem  
 */
require 'module-manager.php';
require 'module-base.php';
require 'containers.php';
require 'checkers.php';
require 'parsers.php';
$blc_module_manager = blcModuleManager::getInstance(array('http', 'link', 'image', 'metadata', 'url_field', 'comment', 'custom_field', 'post', 'page', 'youtube-checker', 'youtube-iframe', 'dummy'));
require 'any-post.php';
//Let other plugins register virtual modules.
do_action('blc_register_modules', $blc_module_manager);
<?php

/**
 * Load all files pertaining to BLC's module subsystem  
 */
require 'module-manager.php';
require 'module-base.php';
require 'containers.php';
require 'checkers.php';
require 'parsers.php';
$blc_module_manager =& blcModuleManager::getInstance(array('http', 'link', 'image', 'metadata', 'url_field', 'blogroll', 'comment', 'custom_field', 'post', 'page', 'dummy'));
require 'any-post.php';